Python Requests モジュール

HTTP リクエストを扱うことは、どのプログラミング言語でも簡単なことではありません。Pythonの場合、HTTP関連の操作を処理するために、 urlliburllib2 という2つのビルトインモジュールが用意されています。この2つのモジュールはそれぞれ異なる機能を備えており、多くの場合、一緒に使用する必要があります。urllibを使用する主な欠点は、混乱しやすいこと (urlliburllib2` の両方で使用できるメソッドが少ない)、ドキュメントが明確でないこと、簡単な HTTP リクエストを行うだけでも多くのコードを書かなければならないことである。

これらのことを簡単にするために、Requests として知られる使いやすいサードパーティライブラリが用意されており、ほとんどの開発者は urllib/urllib2 の代わりにこれを使用することを好みます。これは Apache2 でライセンスされた HTTP ライブラリで、 urllib3 と httplib によって提供されています。

Requests モジュールのインストール

このパッケージのインストールは、他の多くの Python パッケージと同様に、非常に簡単です。Github から Requests のソースコードをダウンロードしてインストールするか、pip を使ってインストールします。

$ pip install requests


インストール手順の詳細については、公式ドキュメントを参照してください。

インストールを確認するために、以下のようにインポートしてみてください。

import requests


インポートエラーが出なければ、成功です。

GETリクエストの作成

GET は最もよく使われる HTTP メソッドです。GET リクエストを使って、任意の相手からデータを取得することができます。まず、簡単な例から説明します。例えば、ホームページの内容を取得し、その結果をHTMLデータとして出力したいとします。Requestsモジュールを使うと、以下のようなことができます。

import requests


r = requests.get('https://api.github.com/events')
print(r.content)


これは、エンコードされた形でレスポンスを出力します。もし、HTMLページの実際のテキスト結果を見たい場合は、このオブジェクトの .text プロパティを読み取ることができます。同様に、status_code プロパティは、URL の現在のステータスコードを表示します。

import requests


r = requests.get('https://api.github.com/events')
print(r.text)
print(r.status_code)


requestsは生のコンテンツをデコードして、その結果を表示します。もし、requestsが使用しているencodingの種類を確認したい場合は、.encoding` を呼び出してこの値を表示することができる。エンコーディングのタイプも、その値を変更することで変更することができる。さて、簡単ではありませんか?

レスポンスの読み方

HTTPリクエストのレスポンスには、さまざまな情報を保持する多くのヘッダが含まれます。

httpbin は、さまざまな HTTP 操作をテストするために人気のあるウェブサイトです。この記事では、httpbin/get を使って GET リクエストに対するレスポンスを解析してみます。まず最初に、レスポンスヘッダとそれがどのように見えるかを調べる必要があります。最近のウェブブラウザであれば、どのブラウザでも見つけることができますが、この例ではGoogleのChromeブラウザを使用することにします。

  • Chromeで、URL http://httpbin.org/get を開き、ページ上の任意の場所を右クリックして、「Inspect」オプションを選択します。
  • ブラウザ内に新しいウィンドウが表示されます。ページを更新し、「ネットワーク」タブをクリックします。
  • この「ネットワーク」タブには、ブラウザによって行われたすべての異なるタイプのネットワーク要求が表示されます。名前」欄の「get」リクエストをクリックし、右側の「ヘッダー」タブを選択します。

レスポンス・ヘッダ “の内容は、私たちの必須要素です。リソースとリクエストに関する様々な情報を保持するキー・バリュー・ペアが表示されています。これらの値を requests ライブラリを使ってパースしてみましょう。

import requests


r = requests.get('http://httpbin.org/get')
print(r.headers['Access-Control-Allow-Credentials'])
print(r.headers['Access-Control-Allow-Origin'])
print(r.headers['CONNECTION'])
print(r.headers['content-length'])
print(r.headers['Content-Type'])
print(r.headers['Date'])
print(r.headers['server'])
print(r.headers['via'])


ヘッダ情報は r.headers を用いて取得し、特定のキーを用いて各ヘッダ値にアクセスすることができる。なお、キーは大文字と小文字を区別しない。

同様に、レスポンスの値にもアクセスしてみよう。上記のヘッダーは、レスポンスがJSON形式であることを示しています。(Content-type: application/json). Requestsライブラリには1つのビルトインJSONパーサーが付属しており、requests.get(‘url’).json()` を使ってJSONオブジェクトとしてパースすることが可能です。そうすると、以下のようにレスポンス結果の各キーに対する値を簡単にパースすることができます。

import requests


r = requests.get('http://httpbin.org/get')


response = r.json()
print(r.json())
print(response['args'])
print(response['headers'])
print(response['headers']['Accept'])
print(response['headers']['Accept-Encoding'])
print(response['headers']['Connection'])
print(response['headers']['Host'])
print(response['headers']['User-Agent'])
print(response['origin'])
print(response['url'])


上記のコードでは、以下のような出力が得られます。

{'headers': {'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}, 'url': 'http://httpbin.org/get', 'args': {}, 'origin': '103.9.74.222'}
{}
{'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}
*/*
gzip, deflate
close
httpbin.org
python-requests/2.9.1
103.9.74.222
http://httpbin.org/get

3行目、つまり r.json() は、レスポンスのJSON値を出力しています。変数 response に JSON 値を格納し、各キーに対応する値を出力しています。前の例とは異なり、キー-値の大文字と小文字は区別されることに注意してください。

JSON やテキストコンテンツと同様に、 .content プロパティを使用して、テキスト以外のリクエストに対するレスポンスの内容をバイト単位で読み取ることができます。これは、 gzipdeflate でエンコードされたファイルを自動的にデコードする。

GETでパラメータを渡す

場合によっては、GETリクエストでクエリ文字列の形をしたパラメータを渡す必要があります。これを行うには、以下のように params パラメータでこれらの値を渡す必要があります。

import requests


payload = {'user_name': 'admin', 'password': 'password'}
r = requests.get('http://httpbin.org/get', params=payload)


print(r.url)
print(r.text)


ここでは、パラメータの値を payload 変数に代入し、params を介して GET リクエストに代入しています。上記のコードは以下のような出力を返します。

http://httpbin.org/get?password=password&user_name=admin
{"args":{"password":"password","user_name":"admin"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"origin":"103.9.74.222","url":"http://httpbin.org/get?password=password&user_name=admin"}


ご覧のとおり、Reqeustsライブラリはパラメータの辞書を自動的にクエリ文字列に変換し、それをURLに添付します。

上の出力でわかるように、ペイロードはURLで見えるので、GETリクエストで渡すデータの種類には注意する必要があることに注意してください。

POSTリクエストの作成

HTTP POST リクエストは GET リクエストとは逆に、データをサーバーに送信するためのものであり、データを取得するためのものではありません。しかし、POST リクエストも GET リクエストと同様に、レスポンスの中でデータを受け取ることができます。

get()メソッドを使う代わりに、post()メソッドを使う必要があります。引数を渡すには、data` パラメータの中で渡すことができます。

import requests


payload = {'user_name': 'admin', 'password': 'password'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.url)
print(r.text)


出力します。

出力: “`
http://httpbin.org/post
{“args”:{},”data”:””,”files”:{},”form”:{“password”:”password”,”user_name”:”admin”},”headers”:{“Accept”:”/“,”Accept-Encoding”:”gzip, deflate”,”Connection”:”close”,”Content-Length”:”33″,”Content-Type”:”application/x-www-form-urlencoded”,”Host”:”httpbin.org”,”User-Agent”:”python-requests/2.9.1″},”json”:null,”origin”:”103.9.74.222″,”url”:”http://httpbin.org/post”}


データはデフォルトで "form-encoded" になります。複数の値が同じキーを持つ場合はタプル、辞書の代わりに文字列、あるいはマルチパートのエンコードされたファイルなど、より複雑なヘッダーリクエストを渡すことも可能である。



### POSTでファイルを送信する

時には、一つまたは複数のファイルを同時にサーバに送信する必要があります。例えば、ユーザーがフォームを送信する際に、そのフォームにユーザープロファイル画像やユーザー履歴書などのファイルをアップロードするための異なるフォームフィールドが含まれている場合などです。リクエストは1つのリクエストで複数のファイルを扱うことができます。これは、以下のようにファイルをタプルのリストに入れることで実現できます。

import requests

url = ‘http://httpbin.org/post’
file_list = [
(‘image’, (‘image1.jpg’, open(‘image1.jpg’, ‘rb’), ‘image/png’)),
(‘image’, (‘image2.jpg’, open(‘image2.jpg’, ‘rb’), ‘image/png’))
]

r = requests.post(url, files=file_list)
print(r.text)


ファイルの情報を含むタプルは `(field_name, file_info)` という形式である。



### その他のHTTPリクエストタイプ

GETやPOSTと同様に、以下のように `requests` ライブラリを使用して、PUT、DELETE、HEAD、OPTIONSなどの他のHTTPリクエストを実行することができます。

import requests

requests.put(‘url’, data={‘key’: ‘value’})
requests.delete(‘url’)
requests.head(‘url’)
requests.options(‘url’)




### リダイレクトの処理

HTTPにおけるリダイレクトとは、ネットワークのリクエストを別のURLに転送することを意味します。例えば、「http://www.github.com」にリクエストした場合、301リダイレクトを使って「https://github.com」にリダイレクトされます。

import requests

r = requests.post(“http://www.github.com”)
print(r.url)
print(r.history)
print(r.status_code)


出力する。

https://github.com/
[, ]
200


このように、リダイレクト処理は `requests` によって自動的に処理されるので、自分で処理する必要はない。history` プロパティには、リダイレクトを完了させるために作成されたすべてのレスポンスオブジェクトのリストが格納されています。この例では、レスポンスコード 301 で 2 つの `Response` オブジェクトが作成されています。HTTP 301 と 302 レスポンスは、それぞれ恒久的なリダイレクトと一時的なリダイレクトに使用されます。

Requests ライブラリにリダイレクトを自動的に追従させたくない場合は、リクエストと一緒に `allow_redirects=False` パラメータを渡して、リダイレクトを無効にすることができる。



### タイムアウトの処理

もうひとつの重要な設定は、タイムアウト (リクエストを返すのに時間がかかりすぎること) をどのように処理するかをライブラリに伝えることです。timeout` パラメータを使用すると、ネットワークリクエストの待ち時間を短縮するように `requests` を設定できる。デフォルトでは、 `requests` はタイムアウトしない。つまり、このプロパティを設定しないと、プログラムが無限にハングアップしてしまう可能性があります。

import requests

requests.get(‘http://www.google.com’, timeout=1)


ここでは、サーバーが1秒以内に応答しない場合に例外を発生させるようにしています(実際のアプリケーションではまだ積極的な設定です)。より頻繁に失敗するようにするには(例として)、タイムアウトの上限を0.001のようなずっと小さな値に設定する必要があります。

タイムアウトは、タプルを使ってリクエストの "connect" と "read" の両方の操作に対して設定することができ、両方の値を別々に指定することができます。

import requests

requests.get(‘http://www.google.com’, timeout=(5, 14))


ここでは、「connect」タイムアウトを5秒、「read」タイムアウトを14秒としています。これにより、リソースに接続できない場合はより迅速にリクエストを失敗させ、接続できた場合はデータをダウンロードするための時間をより多く与えることができます。



### クッキーとカスタムヘッダー

以前、 `headers` プロパティを使用してヘッダにアクセスする方法について説明しました。同様に、`cookies` プロパティを使用してレスポンスからクッキーにアクセスすることができます。

例えば、以下の例では `cookie_name` という名前のクッキーにアクセスする方法を示しています。

import requests

r = requests.get(‘http://www.examplesite.com’)
r.cookies[‘cookie_name’]


また、GETリクエストの `cookies` パラメータに辞書を指定することで、カスタムクッキーをサーバに送信することもできます。

import requests

custom_cookie = {‘cookie_name’: ‘cookie_value’}
r = requests.get(‘http://www.examplesite.com/cookies’, cookies=custom_cookie)


クッキーは、Cookie Jar オブジェクトで渡すこともできます。これによって、異なるパスのクッキーを提供することができます。

import requests

jar = requests.cookies.RequestsCookieJar()
jar.set(‘cookie_one’, ‘one’, domain=’httpbin.org’, path=’/cookies’)
jar.set(‘cookie_two’, ‘two’, domain=’httpbin.org’, path=’/other’)

r = requests.get(‘https://httpbin.org/cookies’, cookies=jar)
print(r.text)


出力します。

{“cookies”:{“cookie_one”:”one”}}


同様に、`headers`パラメータを使ってリクエストヘッダに辞書を代入することで、カスタムヘッダを作成することができます。

import requests

custom_header = {‘user-agent’: ‘customUserAgent’}

r = requests.get(‘https://samplesite.org’, headers=custom_header)




### セッションオブジェクト

セッションオブジェクトは主に、クッキーのような特定のパラメータを異なる HTTP リクエスト間で持続させるために使用されます。セッションオブジェクトは、複数のネットワークリクエストとレスポンスを処理するために単一のTCP接続を使用することができ、これはパフォーマンス向上の結果になります。

import requests

first_session = requests.Session()
second_session = requests.Session()

first_session.get(‘http://httpbin.org/cookies/set/cookieone/111’)
r = first_session.get(‘http://httpbin.org/cookies’)
print(r.text)

second_session.get(‘http://httpbin.org/cookies/set/cookietwo/222’)
r = second_session.get(‘http://httpbin.org/cookies’)
print(r.text)

r = first_session.get(‘http://httpbin.org/anything’)
print(r.text)


出力。

出力:```
{"cookies":{"cookieone":"111"}}


{"cookies":{"cookietwo":"222"}}


{"args":{},"data":"","files":{},"form":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Cookie":"cookieone=111","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"json":null,"method":"GET","origin":"103.9.74.222","url":"http://httpbin.org/anything"}


httpbinのパス /cookies/set/{name}/{value} は namevalue を持つクッキーを設定します。ここでは、first_sessionsecond_sessionの両方のオブジェクトに対して、異なるクッキーの値を設定しています。特定のセッションに対する将来のすべてのネットワークリクエストで、同じクッキーが返されることがわかるでしょう。

同様に、セッションオブジェクトを使用して、すべてのリクエストに対して特定のパラメータを持続させることができます。

import requests


first_session = requests.Session()


first_session.cookies.update({'default_cookie': 'default'})


r = first_session.get('http://httpbin.org/cookies', cookies={'first-cookie': '111'})
print(r.text)


r = first_session.get('http://httpbin.org/cookies')
print(r.text)


出力します。

{"cookies":{"default_cookie":"default","first-cookie":"111"}}


{"cookies":{"default_cookie":"default"}}


見ての通り、default_cookieはセッションの各リクエストで送信されます。もし、 cookie オブジェクトに追加のパラメーターを追加すると、 default_cookie に追加されます。"first-cookie": "111"はデフォルトのクッキーに追加される "default_cookie": "default"となります。

プロキシの使用

引数 proxies は、リクエストで使用するプロキシサーバーを設定するために使用します。

http = "http://10.10.1.10:1080"
https = "https://10.10.1.11:3128"
ftp = "ftp://10.10.1.10:8080"


proxy_dict = {
  "http": http,
  "https": https,
  "ftp": ftp
}


r = requests.get('http://sampleurl.com', proxies=proxy_dict)


requestsライブラリは SOCKS プロキシもサポートしている。これはオプションの機能であり、使用する前にrequests[socks]` 依存関係をインストールする必要がある。以前と同様に、pip を使用してインストールすることができます。

$ pip install requests[socks]


インストールが完了したら、以下のように使用することができます。

proxies = {
  'http': 'socks5:user:pass@host:port'
  'https': 'socks5:user:pass@host:port'
}


SSL対応

リクエストに verify=true を渡すことで、Requests ライブラリを使用してウェブサイトの HTTPS 証明書を確認することもできます。

import requests


r = requests.get('https://www.github.com', verify=True)


これは、サイトのSSLに何らかの問題がある場合にエラーを投げます。ベリファイを行わない場合は、Trueの代わりに False を渡せばよい。このパラメータはデフォルトで True に設定されている。

ファイルのダウンロード

requestsを使用してファイルをダウンロードする場合、コンテンスをストリーミングしてダウンロードするか、直接全体をダウンロードするかのどちらかを選択することができる。両方の動作を指定するには、stream` フラグを使用する。

おそらく想像がつくと思うが、 streamTrue ならば、 requests はコンテンツをストリーミングする。streamFalse` の場合は、すべてのコンテンツをメモリにダウンロードしてから、それを返します。

ストリーミングコンテンツの場合、 iter_content メソッドを使用してチャンクごとにコンテンツをイテレートするか、 iter_line を使用してラインごとにイテレートすることができる。どちらにしても、ファイルを部分的にダウンロードすることになります。

例えば

import requests


r = requests.get('https://cdn.pixabay.com/photo/2018/07/05/02/50/sun-hat-3517443_1280.jpg', stream=True)
downloaded_file = open("sun-hat.jpg", "wb")
for chunk in r.iter_content(chunk_size=256):
    if chunk:
        downloaded_file.write(chunk)


上記のコードはPixabayサーバーから画像をダウンロードし、ローカルファイル sun-hat.jpg に保存します。

また、リクエストに raw プロパティと stream=True を指定することで、生データを読み込むこともできます。

import requests


r = requests.get("http://exampleurl.com", stream=True)
r.raw


コンテンツのダウンロードやストリーミングを行うには、 iter_content() が適しています。

エラーと例外

ネットワークに問題が発生した場合、requestsは様々な種類の例外やエラーを投げる。すべての例外は requests.exceptions.RequestException クラスから継承されています。

以下は、よく遭遇するエラーの簡単な説明です。

  • DNSの失敗、接続拒否、その他接続に関する問題が発生した場合、 ConnectionError 例外がスローされます。
  • Timeout は、リクエストがタイムアウトした場合に発生します。
  • TooManyRedirects は、リクエストがあらかじめ定義されたリダイレクトの最大数を超えた場合に送出されます。
  • HTTPError は、無効な HTTP レスポンスに対して発生する例外です。

より詳細な例外のリストと説明については、ドキュメントを参照してください。

結論

このチュートリアルでは、 requests ライブラリの多くの機能と、その様々な使用方法について説明しました。requests` ライブラリは REST API を操作するために使用できるだけでなく、Web サイトからデータをスクレイピングしたり、Web からファイルをダウンロードするためにも同様に使用することができます。

上記の例を修正して試してみて、 requests について何か質問があれば下のコメント欄に記入してほしい。

</response

タイトルとURLをコピーしました