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.getpathlib.Path.write_textをモックし、 assert_called_once_with(引数)で、 それぞれの関数が適切な引数で呼び出されたことを確認しています。

リファレンス