PythonモジュールRequestsのHTTPステータスコードについて

はじめに

オペレーションチームの高橋です。

LambdaでURL監視をする際に使用したPython(Requests)について調べたことをご紹介したいと思います。

RequestsでHTTPステータスコードを取得する

成功の場合

>>> import requests
>>> r = requests.get('http://httpbin.org/get')
>>> r.status_code
200

簡易的にTrue,False判定する場合

>>> r.status_code
200
>>> r.status_code == requests.codes.ok
True
>>> r = requests.get('http://httpbin.org/status/404')
>>> r.status_code
404
>>> r.status_code == requests.codes.ok
False

4XX、5XX系のレスポンスの場合、例外を発生させることも可能

>>> r.raise_for_status()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/username/.pyenv/versions/3.6.1/lib/python3.6/site-packages/requests/models.py", line 935, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: NOT FOUND for url: http://httpbin.org/status/404

リダイレクトの場合

リダイレクトが発生するURLを取得した際に悩みました。
リダイレクト301のステータスコードを期待していましたが200が戻ってきました。

>>> r = requests.get('http://httpbin.org/status/301')
>>> r.status_code
200

curlで確認しても301でしたがrequestsで200が戻ってきます。

$ curl -I http://httpbin.org/status/301
HTTP/1.1 301 MOVED PERMANENTLY
Connection: keep-alive
Server: meinheld/0.6.1
Date: Fri, 04 Aug 2017 19:28:40 GMT
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
Location: /redirect/1
X-Processed-Time: 0.000458955764771
Access-Control-Allow-Origin: *
Content-Length: 0
Via: 1.1 vegur

ドキュメントを見ると以下記載がありました。

By default Requests will perform location redirection for all verbs except HEAD.

デフォルトではRequestsはリダイレクトに対応させているようです。
なのでcurlでいうと、-Lオプションをつけた挙動と同じですね。

$ curl -IL http://httpbin.org/status/301
HTTP/1.1 301 MOVED PERMANENTLY
Connection: keep-alive
Server: meinheld/0.6.1
Date: Fri, 04 Aug 2017 19:28:47 GMT
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
Location: /redirect/1
X-Processed-Time: 0.000839948654175
Access-Control-Allow-Origin: *
Content-Length: 0
Via: 1.1 vegur

HTTP/1.1 302 FOUND
Connection: keep-alive
Server: meinheld/0.6.1
Date: Fri, 04 Aug 2017 19:28:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 215
Location: /get
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.00106191635132
Via: 1.1 vegur

HTTP/1.1 200 OK
Connection: keep-alive
Server: meinheld/0.6.1
Date: Fri, 04 Aug 2017 19:28:47 GMT
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.000760793685913
Content-Length: 214
Via: 1.1 vegur

Requestsでリダイレクトを確認するには Response.history を使います。

>>> r = requests.get('http://httpbin.org/status/301')
>>> r.history
[<Response [301]>, <Response [302]>]

結果が古い順にリストで確認できます。

>>> r.history
[<Response [301]>, <Response [302]>]
>>> r.history[0]
<Response [301]>
>>> r.history[1]
<Response [302]>
>>> r.history[0].status_code
301
>>> r.history[1].status_code
302

リダイレクトさせずステータスだけ見たい場合は allow_redirects パラメータを使用します。

>>> r = requests.get('http://httpbin.org/status/301' ,allow_redirects=False)
>>> r.status_code
301
>>> r.history
[]

Response.status_code で301が確認できます。
またリダイレクトはされなので、 r.history の結果は空です。

まとめ

今回はリダイレクトするURLを取得する際に悩んだのでステータスコードについて記載しました。
詳しくはドキュメント(以下参考URL) を見ていただきたいのですが
本ブログも参考になれば幸いです。

ではまた。

参考URL

Requests | Quickstart