Попробуйте/за исключением использования модуля запросов Python

выполнение некоторого тестирования 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]>

3 ответов


если вы хотите, чтобы ответ вызвал исключение для кода состояния не-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 - это плохая идея. Это будет ловить такие вещи, как ConnectionErrorили TimeoutErrors, etc. Ни одно из них не означает то же самое, что ты пытаешься поймать.


Примечание: даже если это принятый ответ, вы должны скорее пойти с response.raise_for_status() как описано в Иэн ниже (он один из операторов requests модуль).


как вы справляетесь с этим, зависит от того, что вы считаете ошибкой HTTP. Есть коды состояния, но не все, кроме 200 обязательно означает, что есть ошибка какая-то.

как вы заметили, библиотека запросов рассматривает их как еще один аспект HTTP-ответа и не вызывает исключения. Состояния HTTP 302, например,Found, но ответ не содержит ответа, но Location заголовок вместо этого вам нужно будет следовать, чтобы добраться до ресурса, который вы действительно хотели.

так что вы хотите посмотреть на response.status_code, и сделайте свою обработку этого, поймав фактический ошибки протокола С try..except. Когда вы ловите тех, кого вы должны на самом деле поймать requests.exceptions.RequestException, потому что это базовый класс для всех исключений the requests модуль поднимает.

Итак, вот пример, который демонстрирует все три случая:

  • продвижение 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 бит работает следующим образом: The // оператор делает так называемый этаж отдел, так что округление до следующего целого числа (это поведение по умолчанию для / в Python 2.x, но не Python 3.x, который изменился / для деления с плавающей запятой). Так что status // 100 == 2 держит верно для всех 2xx кодексы.


Вы можете проверить response.status_code значение. Если это не 200, тогда вы можете считать это условием ошибки и создать собственное исключение.