urllib.request.urlopen()
| 対応: | Python 3.0(2008) |
|---|
『urllib』はPythonの標準ライブラリに含まれるHTTPクライアントで、外部ライブラリなしでWebページの取得やAPIの呼び出しができます。『urllib.request.urlopen()』でURLにアクセスし、『urllib.parse.urlencode()』でクエリ文字列を生成します。実務ではrequestsライブラリの方が扱いやすいですが、環境によっては標準ライブラリのみで実装する必要がある場面もあります。
構文
from urllib import request, parse
# GETリクエスト
with request.urlopen(url) as res:
data = res.read()
# POSTリクエスト
data = parse.urlencode({'key': 'value'}).encode()
with request.urlopen(url, data=data) as res:
result = res.read()
# URLエンコード
encoded = parse.urlencode({'q': '検索ワード'})
quoted = parse.quote('日本語テキスト')
関数・クラス一覧
| 関数・クラス | 概要 |
|---|---|
| request.urlopen(url) | URLにGETリクエストを送り、レスポンスオブジェクトを返す。 |
| request.urlopen(url, data) | dataを指定するとPOSTリクエストになる。 |
| request.Request(url, headers) | ヘッダーなどを指定したリクエストオブジェクトを生成する。 |
| res.read() | レスポンスボディをバイト列で読み込む。 |
| res.status | HTTPステータスコードを返す(Python 3.9+)。 |
| res.getheader(name) | 指定したレスポンスヘッダーの値を返す。 |
| parse.urlencode(dict) | 辞書をクエリ文字列(key=value&key2=value2)に変換する。 |
| parse.quote(string) | 文字列をURLエンコードする(スペースは%20になる)。 |
| parse.quote_plus(string) | 文字列をURLエンコードする(スペースは+になる)。 |
| parse.unquote(string) | URLエンコードされた文字列をデコードする。 |
| parse.urlparse(url) | URLをスキーム・ホスト・パスなどの要素に分解する。 |
サンプルコード
urllib_get.py
from urllib import request, parse
import json
url = 'https://jsonplaceholder.typicode.com/todos/1'
try:
with request.urlopen(url, timeout=10) as res:
data = res.read()
status = res.status
ctype = res.getheader('Content-Type')
print(status)
print(ctype)
result = json.loads(data.decode('utf-8'))
print(result)
except Exception as e:
print(e)
params = {'q': 'Python', 'page': 1, 'limit': 10}
query = parse.urlencode(params)
url = 'https://wp-p.info/sandbox/api.php?' + query
print(url)
実行すると次のように出力されます。
python3 urllib_get.py
200
application/json; charset=utf-8
{'userId': 1, 'id': 1, 'title': 'delectus aut autem', 'completed': False}
https://wp-p.info/sandbox/api.php?q=Python&page=1&limit=10
urllib_post.py
from urllib import request, parse
import json
req = request.Request(
'https://wp-p.info/sandbox/api.php',
headers={
'User-Agent': 'MyApp/1.0',
'Accept': 'application/json',
}
)
with request.urlopen(req, timeout=10) as res:
body = res.read()
print(res.status)
print(body.decode('utf-8'))
post_data = parse.urlencode({'name': '綾波レイ', 'org': 'NERV'}).encode('utf-8')
req = request.Request(
'https://httpbin.org/post',
data=post_data,
headers={'Content-Type': 'application/x-www-form-urlencoded'},
)
with request.urlopen(req, timeout=10) as res:
result = json.loads(res.read().decode('utf-8'))
print(result['form'])
実行すると次のように出力されます。
python3 urllib_post.py
200
{"status": "ok"}
{'name': '綾波レイ', 'org': 'NERV'}
urllib_parse.py
from urllib import parse
text = '日本語 テキスト'
encoded = parse.quote(text)
print(encoded)
decoded = parse.unquote(encoded)
print(decoded)
parsed = parse.urlparse('https://example.com:8080/path?key=val#section')
print(parsed.scheme)
print(parsed.netloc)
print(parsed.path)
print(parsed.query)
print(parsed.fragment)
実行すると次のように出力されます。
python3 urllib_parse.py %E6%97%A5%E6%9C%AC%E8%AA%9E%20%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88 日本語 テキスト https example.com:8080 /path key=val section
よくあるミス
よくあるミス1: res.read()を呼ばずに内容を取得しようとする
『urlopen()』が返すのはレスポンスオブジェクトであり、内容そのものではありません。『res.read()』を呼ばないとバイト列を取得できません。
mistake_read_ng.py
from urllib import request
url = 'https://jsonplaceholder.typicode.com/todos/1'
with request.urlopen(url, timeout=10) as res:
print(res)
実行すると次のように出力されます。
python3 mistake_read_ng.py <http.client.HTTPResponse object at 0x...>
レスポンスボディを取得するには『res.read()』を呼び出します。文字列として使う場合はさらにdecode()でデコードします。
mistake_read_ok.py
from urllib import request
url = 'https://jsonplaceholder.typicode.com/todos/1'
with request.urlopen(url, timeout=10) as res:
body = res.read().decode('utf-8')
print(body)
実行すると次のように出力されます。
python3 mistake_read_ok.py
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
よくあるミス2: urlencode忘れで日本語パラメータが文字化けする
クエリ文字列に日本語や特殊文字をそのまま埋め込むと、サーバー側で正しく解釈されないことがあります。『parse.urlencode()』でエンコードしてからURLを構築します。
mistake_encode_ng.py
from urllib import request keyword = 'Pythonチュートリアル' url = 'https://example.com/search?q=' + keyword print(url)
実行すると次のように出力されます。
python3 mistake_encode_ng.py https://example.com/search?q=Pythonチュートリアル
『parse.urlencode()』でパラメータをエンコードすることで、日本語を含むURLを安全に構築できます。
mistake_encode_ok.py
from urllib import parse
keyword = 'Pythonチュートリアル'
params = {'q': keyword}
query = parse.urlencode(params)
url = 'https://example.com/search?' + query
print(url)
実行すると次のように出力されます。
python3 mistake_encode_ok.py https://example.com/search?q=Python%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB
概要
『urllib.request.urlopen()』はHTTPSをサポートしており、SSL証明書の検証もデフォルトで行います。タイムアウトはtimeoutパラメータで秒単位で指定でき、指定するとタイムアウト時のハングを防げます。
レスポンスボディはバイト列で返されるため、文字列として使うには適切なエンコーディング(通常はUTF-8)でデコードします。Content-Typeヘッダーからエンコーディングを取得することもできます。
実務でHTTPリクエストを多用する場合はrequestsライブラリを使う方法もあります。セッション管理・認証・リトライなどが簡単に実装でき、コードも簡潔になります。外部ライブラリを使える環境では『pip install requests』で導入できます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。