urllib.requestモジュールを使って、指定したURLをオープンし、その内容をファイルと同様な手法で取り出す方法の基本を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
前回は、shelveモジュールを使用して辞書のような使い勝手でオブジェクトを外部ファイルに保存する方法を見た。今回は、ファイルと同様な手法でネットワークからファイルを取得する方法について見てみよう。
PythonにはURLを扱うためのモジュールとして、urllibモジュールが標準で付属している。実際には、これは幾つかのモジュールをまとめたパッケージである。本稿ではそのうちのurllib.requestモジュールを紹介する。
urllib.requestモジュールを使って、特定のURLをオープンするにはurllib.request.urlopen関数を使用する。その基本構文を以下に示す。
urlopen(url)
urlをオープンする。
パラメーター | 説明 |
---|---|
url | オープンしたいURL |
urllib.request.urlopen関数のパラメーター(一部) |
urllib.request.urlopen関数はより多くのパラメーターを持つが、これらについてはPythonのドキュメントを参照されたい。
この関数を使用して、指定したURLをオープンすると、http.clientモジュールで定義されているHTTPResponseクラスのオブジェクトが返送される。このクラスには、readメソッド、readlineメソッド、readlinesメソッドなど、取得したHTTPレスポンスから、そのボディー(内容)を読み出すためのメソッドがある。これらを使うことで、取得したレスポンスページの内容を、ファイルを操作するのと同様な手法で読み込めるようになっている。
この他にも取得したリソースの実際のURLを返送するgeturlメソッド、ページに関する情報を取得するinfoメソッド、urllib.request.urlopen関数によるURLのオープンが成功したかを示すHTTPステータスコードを取得するgetcodeメソッドもある。
以下に簡単な例を示す。
import urllib
response = urllib.request.urlopen('https://www.example.com/')
print('url:', response.geturl())
print('code:', response.getcode())
print('Content-Type:', response.info()['Content-Type'])
content = response.read()
print(content)
response.close()
ここではhttps://www.example.comをオープンして、上で述べた3つのメソッドを使い、実際のURL、HTTPレスポンスコード、infoメソッドで得た情報のうちContent-Typeヘッダの内容を表示している。その後、readメソッドを使ってWebページの内容を読み込んで、それを画面に出力している。ここではreadメソッドを使っているが、readlineメソッドで1行ずつ内容を読み出すことも可能だ。
実行結果を以下に示す。
実行結果を見ると分かるように、取得したページ内容はバイト列(bytesオブジェクト)になっている。よって、実際にこれを利用するにはdecodeメソッドで文字列にデコードする必要がある。
html = content.decode()
print(html)
このコードを実行すると、次のように文字列としてWebページのソースが表示される。
このときに注意したいのは、decodeメソッドではエンコーディング方式をデフォルトで'utf-8'としている点だ。例えば、@ITのWebページはシフトJISをそのエンコーディングに使用している。そのため、urllib.request.urlopen関数でそのページの内容を取得しても、デコード時にエンコーディングに'shift_jis'などを指定しないと、適切な結果が得られない。
response = urllib.request.urlopen('https://www.atmarkit.co.jp/ait/subtop/di')
content = response.read()
response.close()
html = content.decode() # UTF-8でデコード
そのため、上のコードを実行すると、次のような結果になる。
このように、UnicodeDecodeError例外が発生する。これを修正するには、次のようにdecodeメソッドにエンコーディングを指定する。
html = content.decode('shift_jis')
print(html)
実行結果を以下に示す。
このとき、エンコーディングを調べるには、上述のinfoメソッドやこの例ならresponse.headersとして取り出せるhttp.client.HTTPMessageオブジェクトに対して、get_content_charsetメソッドを呼び出すとよい(ただし、常にエンコーディングを取得できるとは限らない)。
以下に例を示す(実行結果は省略する)。
response = urllib.request.urlopen('https://www.google.co.jp')
print(response.info().get_content_charset())
なお、上のコードではurllibモジュールのインポートに次の行を実行している。
import urllib
これにより「urllib.request.urlopen(……)」や「urllib.parse.urlencode(……)」のように、urllibモジュールに含まれているサブモジュールの関数やクラスにアクセスできるようになるが、記述が煩わしいと感じる方もいるかもしれない。以下のように、必要なものだけをインポートしても構わない。
from urllib import request, parse
from urllib.request import urlopen
from urllib.parse import urlencode
1行目のようなインポートをすれば、その後は「request.urlopen(……)」のようにurllib.requestモジュールで定義されている関数やクラスにアクセスできるようになる。2行目と3行目のように使用することが分かっている関数だけをインポートしてもよい。以下では、「import urllib」でこのモジュールをインポートしたものとして話を進める。
Copyright© Digital Advantage Corp. All Rights Reserved.