HTTPしたい(requests
)
1import requests
2
3try:
4 r = requests.get("https://httpbin.org/get", timeout=10)
5 r.raise_for_status()
6 print(f"{r.status_code}: {r.reason}")
7except Exceptions as e:
8 print(f"error: {e}")
requests
でウェブページのリソースを取得できます。
「HTTP for Humans」を謳っていて、直感的なHTTP操作ができます。
.raise_for_status
で、レスポンスのステータスコードが400番台、500番台のときに例外を発生させることができます。
ヒント
https://httpbin.orgは、 HTTP通信のリクエストとリスポンスの動作テストができる無料のサービスです。 基本的にはエコーサーバーとなっていて、 自分が送ったリクエストの内容を JSON形式のレスポンスとして受け取ることができます。 APIの開発や、クライアントツールの挙動をデバッグするのに便利です。
リクエストしたい(get
)
1r = requests.get("https://httpbin.org/get")
2r = requests.head("https://httpbin.org/get")
3r = requests.options("https://httpbin.org/get")
4r = requests.post("https://httpbin.org/post", data={"key": "value"})
5r = requests.put("https://httpbin.org/put", data={"key": "value"})
6r = requests.delete("https://httpbin.org/delete")
7
8# リクエストしたURLを確認
9r.url
HTTPのリクエストメソッドに対応したメソッドで、リクエストできます。
url
プロパティでリクエストしたURLを確認できます。
レスポンスしたい(text
)
1r = requests.get("https://httpbin.org/get")
2
3r.text # str
4r.content # bytes
5r.json() # 辞書型
6r.headers # 辞書(みたいな)型
7r.cookies # 辞書(みたいな)型
HTMLのソースなどの文字データの場合、text
メソッドで確認できます。
画像をリクエストした場合は、content
メソッドでバイナリ形式のデータを確認できます。
REST APIのようにJSON形式のレスポンスはjson()
メソッドで確認できます。
レスポンスを保存したい
1r = requests.get("https://example.com")
2p = Path("output.html")
3p.write_text(r.text, encoding="utf-8")
テキスト形式のレスポンスは、通常のファイル出力を使って保存できます。 保存時のエンコーディングは必要に応じて指定してください。
注釈
HTML形式のレスポンスを取得した場合、charset
の値からエンコーディングを自動で判別するみたいです。
自動判別できなかった場合は、デフォルトのISO-8859-1
(Latin-1)になってしまいます。
日本語を含んだレスポンスの場合は、文字化けするため、エンコーディングは指定しておく方がよいでしょう。
タイムアウトしたい(timeout
)
1# requests.get("URL", timeout=秒数)
2r = requests.get("URL", timeout=10)
timeout
オプションで、リクエスト時のタイムアウト秒(=待機時間)を設定できます。
デフォルトでは値が設定されていないため、必ず設定したほうがよいと思います。
設定した待機時間を過ぎてもサーバーからの応答がない場合はTimeoutError
になります。
クエリしたい(params
)
1params = {
2 "key1": "value1",
3 "key2": "value2",
4 }
5r = requests.get("URL", params=params)
6
7# クエリ付きのURLを確認
8r.url
9# URL?key1=value1&key2=value2
params
オプションで、リクエスト時にクエリを追加できます。
クエリは辞書型で用意します。
ヘッダーしたい(headers
)
1headers = {"user-agent": "my-app/0.0.1"}
2r = requests.get("URL", headers=headers)
headers
オプションで、リクエストにヘッダーを追加できます。
ユーザーエージェントなどを設定できます。
1# 自作ツールの場合
2headers = {"User-Agent": "ツール名/バージョン (ホームページ)"}
ユーザーエージェント情報は、だれからのアクセスかを示す情報です。 自作ツールの場合、上記のような形式が一般的な形式のようです。
レスポンスのステータスを確認したい
1r = requests.get("https://httpbin.org/status/200")
2r.ok # True
3r.status_code # 200
4r.reason # 'OK'
ok
プロパティで接続に成功したかどうかを確認できます。
レスポンスが成功(200(もしくは200番台?))の場合True
になるので、
if
文で判定するときに便利です。
1if r.ok:
2 # SUCCESS時
3 # 取得した内容をファイルに保存する
4 p = Path("response.txt")
5 with p.open("w, encoding="utf-8") as f:
6 f.write(r.text)
7else:
8 msg = f"URL might be invalid or inaccessible. Status:{r.status_code} - {r.reason}"
9 logger.warning(msg)
status_code
でレスポンスのステータスコード、
reason
で値の説明を確認できます。
接続に失敗したときの処理の表示に使えます。
raise_for_status
でも同様の処理ができます(たぶん)。
例外処理したい(RequestException
)
1URL = "https://httpbin.org/status/404"
2
3try:
4 response = requests.get(URL)
5except requests.exceptions.RequestException as e:
6 msg = f"Failed to connect URL: {URL}"
7 logger.error(msg)
requests.exceptions.RequestException
は、
requestsモジュールの例外クラスの親分です。
ユーザーエージェント情報
1headers = {"User-Agent": "Mozilla/5.0 (OS情報) レンダリングエンジン ブラウザー名/バージョン Safari互換性/バージョン"}
上記のサンプルは、ユーザーエージェント情報のテンプレートです。 記述されている項目は以下の整理しました。
Mozilla/5.0
:
Netscape Navigatorとの互換性を示すための値。現在は、そのような効能はなく、慣例的にMozilla/5.0
と書かれているそうです。
- OS情報:
括弧内にOS名とバージョン情報を記述します。
WindowsPCの場合は(Windows NT 10.0; Win64; x64)
、
macOSの場合は(Macintosh; Intel Mac OS X 13_0)
のようになります。
- レンダリングエンジン / Gecko互換性:
ブラウザで使用しているレンダリングエンジンの情報を記述します。
FirefoxではGecko/バージョン
、
ChromeやSafariではAppleWebkit/バージョン (KHTML, like Gecko)
となります。
- ブラウザー情報:
ブラウザー名とバージョン情報を記述します。
Firefoxの場合はFirefox/バージョン
、
Safariの場合はVersion/16.0
、
ChromeやChromeベースの場合はChrome/バージョン
、
Edgeの場合はEdg/バージョン
と書くようです。
- Safari互換性:
WebKitベースのブラウザーのSafari互換性の情報を記述します。
具体例
以下に、UA情報のサンプルを整理しました。 ただし、UA情報を偽装することは行儀がよくない作法だそうです。 なかには利用規約で禁止されてることもあるようです。
Google Chrome (v115.0) / WindowsPC
1headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"}
Mozilla Firefox (v102.0) / WindowsPC
1headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0"}
Safari (v16.0) / macOS13
1headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Safari/605.1.15"}
MS Edge (v114.0) / WindowsPC
1headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.79"}
モックしたい(@patch(requests.get)
)
1from unittest.mock import patch
2
3@patch("pathlib.Path.write_text")
4@patch("requests.get")
5def test_requests(mock_get, mock_write):
6 # テスト用の文字列
7 text_data = "モックしたテキストデータ"
8
9 # response.ok の返り値をモック
10 # response.text の返り値をモック
11 mock_get.return_value.ok = True
12 mock_get.return_value.text = text_data
13
14
15 関数(引数)
16 # 内部で requests.get している関数
17 # response = requests.get(url="URL", timeout=30)
18 # p = Path("ファイル名")
19 # p.write_text(response.text)
20
21 # request.get の呼び出しを確認
22 mock_get.assert_called_once_with(url="URL", timeout=30)
23 # Path.write_text の呼び出しを確認
24 mock_write.assert_called_once_with(text_data)
requests.get
でGETリクエストして取得したレスポンス(=テキストデータ)を
Path.write_text
でファイルに保存する関数のユニットテストのサンプルです。
関数のロジックを確認するためのユニットテストの場合、 実際にGETリクエストを発生させたり、 ファイルを作成したりする必要はありません。
requests.get
とpathlib.Path.write_text
をモックし、
assert_called_once_with(引数)
で、
それぞれの関数が適切な引数で呼び出されたことを確認しています。