web-dev-qa-db-fra.com

Essayez / sauf lorsque vous utilisez Python module de requêtes

Faire des tests d'API et essayer de créer une fonction qui, étant donné une URL entrée, retournera la réponse json, mais si une erreur HTTP est la réponse, un message d'erreur sera retourné.

J'utilisais urllib2 auparavant, mais j'essaie maintenant d'utiliser les requêtes à la place. Cependant, il semble que mon bloc except ne soit jamais exécuté, quelle que soit l'erreur.

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)

Le résultat que j'obtiens en exécutant ce qui précède ...

<Response [404]>
21
mroriel

Si vous souhaitez que la réponse lève une exception pour un code d'état autre que 200, utilisez response.raise_for_status(). Votre code ressemblerait alors à:

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

Vous pouvez dire que c'est clairement plus simple que les autres solutions ici et ne vous oblige pas à vérifier le code d'état manuellement. Vous attraperiez aussi juste un HTTPError puisque c'est ce que raise_for_status augmentera. Attraper RequestsException est une mauvaise idée. Cela va attraper des choses comme ConnectionErrors ou TimeoutErrors, etc. Aucune de ces choses ne signifie la même chose que ce que vous essayez d'attraper.

35

Note : Vous devriez plutôt aller avec response.raise_for_status() comme décrit dans réponse d'Ian ci-dessus ( il est l'un des mainteneurs du module requests).


La façon dont vous gérez tout cela dépend de ce que vous considérez comme une erreur HTTP. Il y a des codes d'état, mais tout autre que 200 Signifie nécessairement qu'il y a une erreur quelconque.

Comme vous l'avez remarqué, la bibliothèque de requêtes ne prend en compte que ces aspects de la réponse HTTP et ne déclenche pas d'exception. L'état HTTP 302 Signifie par exemple Found, mais la réponse ne contient pas de corps de réponse mais un en-tête Location à la place que vous devez suivre pour accéder à la ressource vous vouliez vraiment.

Donc, vous voudrez regarder response.status_code , et faire votre traitement de cela, tout en détectant les erreurs de protocole réelles avec un try..except. Lorsque vous attrapez ceux-ci, vous devez réellement attraper requests.exceptions.RequestException, Car il s'agit de la classe de base pour toutes les autres exceptions que le module requests déclenche.

Voici donc un exemple qui illustre les trois cas:

  • Réponse réussie 200 OK
  • Demande et réponse réussies, mais état autre que 200
  • Erreur de protocole (schéma non valide)
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

Production:

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'

Il peut également y avoir une exception déclenchée par response.json() si vous obtenez une réponse réussie, mais ce n'est tout simplement pas JSON - vous voudrez peut-être également en tenir compte.


Remarque : Le bit if not response.status_code // 100 == 2 Fonctionne comme ceci: L'opérateur // Fait ce qu'on appelle division au sol , donc il arrondit à l'entier suivant (c'est le comportement par défaut pour le / dans Python 2.x, mais pas Python 3.x, qui a changé / Pour faire une division en virgule flottante). Donc status // 100 == 2 Est vrai pour tous les codes 2xx.

12
Lukas Graf

Vous pouvez vérifier le response.status_code valeur. Si ce n'est pas 200, vous pouvez alors considérer qu'il s'agit d'une condition d'erreur et lever votre propre exception.

1
austin