¿Forma correcta de probar / excepto usar el módulo de solicitudes Python?

Respuestas:

796

Eche un vistazo a los documentos de excepción de Solicitudes . En breve:

En el caso de un problema de red (por ejemplo, falla de DNS, conexión rechazada, etc.), las solicitudes generarán una ConnectionErrorexcepción.

En el caso de la rara respuesta HTTP no válida, las solicitudes generarán una HTTPErrorexcepción.

Si se agota el tiempo de espera de una solicitud, se Timeoutgenera una excepción.

Si una solicitud excede el número configurado de redireccionamientos máximos, se genera una TooManyRedirectsexcepción.

Todas las excepciones de las que Solicitudes plantea explícitamente heredan requests.exceptions.RequestException.

Para responder a su pregunta, lo que muestre no cubrirá todas sus bases. Solo detectará los errores relacionados con la conexión, no los que caducan.

Qué hacer cuando detecta la excepción depende realmente del diseño de su script / programa. ¿Es aceptable salir? ¿Puedes seguir y volver a intentarlo? Si el error es catastrófico y no puede continuar, entonces sí, puede abortar su programa levantando SystemExit (una buena manera de imprimir un error y llamar sys.exit).

Puede capturar la excepción de clase base, que manejará todos los casos:

try:
    r = requests.get(url, params={'s': thing})
except requests.exceptions.RequestException as e:  # This is the correct syntax
    raise SystemExit(e)

O puede atraparlos por separado y hacer cosas diferentes.

try:
    r = requests.get(url, params={'s': thing})
except requests.exceptions.Timeout:
    # Maybe set up for a retry, or continue in a retry loop
except requests.exceptions.TooManyRedirects:
    # Tell the user their URL was bad and try a different one
except requests.exceptions.RequestException as e:
    # catastrophic error. bail.
    raise SystemExit(e)

Como Christian señaló:

Si desea que los errores http (p. Ej. 401 no autorizados) generen excepciones, puede llamar Response.raise_for_status. Eso generará un HTTPError, si la respuesta fue un error http.

Un ejemplo:

try:
    r = requests.get('http://www.google.com/nothere')
    r.raise_for_status()
except requests.exceptions.HTTPError as err:
    raise SystemExit(err)

Imprimirá:

404 Client Error: Not Found for url: http://www.google.com/nothere
Jonathon Reinhart
fuente
11
Muy buena respuesta para tratar los detalles de la biblioteca de solicitudes, y también para la captura de excepciones en general.
Brian Peterson
10
Tenga en cuenta que debido a un error en la biblioteca subyacente urllib3, también necesitará detectar socket.timeoutexcepciones si está usando un tiempo de espera: github.com/kennethreitz/requests/issues/1236
jb.
15
Futuros lectores de comentarios: esto se solucionó en las Solicitudes 2.9 (que agrupa urllib3 1.13)
RazerM
14
Si desea que los errores http (p. Ej., 401 no autorizados) generen excepciones, puede llamar a Response.raise_for_status . Eso generará un HTTPError, si la respuesta fue un error http.
Christian Long
55
La lista de excepciones en el sitio web de Solicitud no está completa. Puedes leer la lista completa aquí .
Epoc
88

Una sugerencia adicional para ser explícito. Parece mejor pasar de lo específico a lo general hacia abajo en la pila de errores para obtener el error deseado, para que los específicos no se enmascaren por el error general.

url='http://www.google.com/blahblah'

try:
    r = requests.get(url,timeout=3)
    r.raise_for_status()
except requests.exceptions.HTTPError as errh:
    print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
    print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
    print ("Timeout Error:",errt)
except requests.exceptions.RequestException as err:
    print ("OOps: Something Else",err)

Http Error: 404 Client Error: Not Found for url: http://www.google.com/blahblah

vs

url='http://www.google.com/blahblah'

try:
    r = requests.get(url,timeout=3)
    r.raise_for_status()
except requests.exceptions.RequestException as err:
    print ("OOps: Something Else",err)
except requests.exceptions.HTTPError as errh:
    print ("Http Error:",errh)
except requests.exceptions.ConnectionError as errc:
    print ("Error Connecting:",errc)
except requests.exceptions.Timeout as errt:
    print ("Timeout Error:",errt)     

OOps: Something Else 404 Client Error: Not Found for url: http://www.google.com/blahblah
jouell
fuente
¿Es esta sintaxis válida para la publicación también?
ScipioAfricanus
@ScipioAfricanus sí.
andrea
10

El objeto de excepción también contiene la respuesta original e.response, que podría ser útil si necesita ver el cuerpo del error en respuesta del servidor. Por ejemplo:

try:
    r = requests.post('somerestapi.com/post-here', data={'birthday': '9/9/3999'})
    r.raise_for_status()
except requests.exceptions.HTTPError as e:
    print (e.response.text)
tsh
fuente