web-dev-qa-db-ja.com

Python requestsモジュール

いくつかのAPIテストを実行し、入力されたURLを指定する関数を作成しようとすると、json応答が返されますが、HTTPエラーが応答の場合、エラーメッセージが返されます。

以前はurllib2を使用していましたが、代わりにリクエストを使用しようとしています。ただし、エラーに関係なく、exceptブロックは実行されないようです。

testURL = 'http://httpbin.org/status/404'


def return_json(URL):
    try:
        response = requests.get(URL)
        json_obj = response.json()
        return json_obj
    except requests.exceptions.HTTPError as e:
        return "Error: " + str(e)

上記を実行した結果...

<Response [404]>
15
mroriel

応答で200以外のステータスコードの例外を発生させる場合は、response.raise_for_status()を使用します。コードは次のようになります。

testURL = 'http://httpbin.org/status/404'


def return_json(URL):
    response = requests.get(testURL)

    try:
        response.raise_for_status()
    except requests.exceptions.HTTPError as e:
        # Whoops it wasn't a 200
        return "Error: " + str(e)

    # Must have been a 200 status code
    json_obj = response.json()
    return json_obj

これは他のソリューションよりも明らかにシンプルであり、ステータスコードを手動で確認する必要がないことがわかります。 HTTPErrorをキャッチすることもできます。これはraise_for_statusが発生します。 RequestsExceptionをキャッチするのはよくありません。それはConnectionErrorsやTimeoutErrorsなどのようなものをキャッチします。これらのどれも、あなたがキャッチしようとしているものと同じことを意味しません。

:これは受け入れられた回答ですが、 Ian's answer で説明されているように、response.raise_for_status()を使用する必要があります以下(彼はrequestsモジュールのメンテナーの一人)。


これをどのように処理するかは、HTTPエラーとみなされるものによって異なります。ステータスコードはありますが、_200_以外のすべてが必ずしも何らかのエラーがあることを意味するわけではありません。

お気づきのように、リクエストライブラリはHTTP応答の別の側面を考慮し、例外を発生させません。たとえば、HTTPステータス_302_はFoundを意味しますが、応答には応答本文が含まれず、代わりにLocationヘッダーが含まれているため、リソースにアクセスする必要があります実際に欲しかった。

したがって、 _response.status_code_ を調べて、実際のプロトコルエラーをキャッチしながら、その処理を行います_try..except_付き。これらをキャッチするときは、実際に_requests.exceptions.RequestException_をキャッチする必要があります。これは、これが他のすべての例外の ベースクラスrequestsモジュールが発生するためです。

したがって、次の3つのケースすべてを示す例があります。

  • 成功した_200 OK_応答
  • 要求と応答は成功しましたが、_200_以外のステータス
  • プロトコルエラー(無効なスキーマ)
_import requests

test_urls = ['http://httpbin.org/user-agent',
             'http://httpbin.org/status/404',
             'http://httpbin.org/status/500',
             'httpx://invalid/url']


def return_json(url):
    try:
        response = requests.get(url)

        # Consider any status other than 2xx an error
        if not response.status_code // 100 == 2:
            return "Error: Unexpected response {}".format(response)

        json_obj = response.json()
        return json_obj
    except requests.exceptions.RequestException as e:
        # A serious problem happened, like an SSLError or InvalidURL
        return "Error: {}".format(e)


for url in test_urls:
    print "Fetching URL '{}'".format(url)
    print return_json(url)
    print
_

出力:

_Fetching URL 'http://httpbin.org/user-agent'
{u'user-agent': u'python-requests/2.1.0 CPython/2.7.1 Darwin/11.4.2'}

Fetching URL 'http://httpbin.org/status/404'
Error: Unexpected response <Response [404]>

Fetching URL 'http://httpbin.org/status/500'
Error: Unexpected response <Response [500]>

Fetching URL 'httpx://invalid/url'
Error: No connection adapters were found for 'httpx://invalid/url'
_

また、成功した応答を取得した場合はresponse.json()によって例外が発生する可能性がありますが、それは単にJSONではないため、同様に説明することもできます。


:_if not response.status_code // 100 == 2_ビットは次のように機能します:_//_演算子はいわゆる floor divisionを実行します ので、次の整数に切り捨てます(これは、Python 2.xの_/_のデフォルトの動作ですが、Python 3.x、これは_/_を浮動小数点除算に変更したため、_status // 100 == 2_はすべての_2xx_コードに当てはまります。

11
Lukas Graf

response.status_code値を確認できます。 200でない場合は、エラー状態であると見なし、独自の例外をスローできます。

1
austin