Maneira correta de tentar / exceto usando o módulo de solicitações Python?

Respostas:

795

Dê uma olhada nos documentos de exceção Solicitações . Em resumo:

No caso de um problema de rede (por exemplo, falha no DNS, conexão recusada, etc.), os pedidos criarão uma ConnectionErrorexceção.

No caso de uma resposta HTTP inválida rara, os Pedidos gerarão uma HTTPErrorexceção.

Se um pedido atingir o tempo limite, uma Timeoutexceção será gerada.

Se uma solicitação exceder o número configurado de redirecionamentos máximos, uma TooManyRedirectsexceção será gerada.

Todas as exceções das quais solicitações explicitamente geram herança requests.exceptions.RequestException.

Para responder sua pergunta, o que você mostrar não cobrirá todas as suas bases. Você detectará apenas erros relacionados à conexão, não aqueles que atingem o tempo limite.

O que fazer quando você capturar a exceção depende realmente do design do seu script / programa. É aceitável sair? Você pode continuar e tentar novamente? Se o erro for catastrófico e você não puder continuar, sim, você pode abortar seu programa aumentando SystemExit (uma boa maneira de imprimir um erro e chamar sys.exit).

Você pode capturar a exceção de classe base, que tratará de todos os casos:

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

Ou você pode pegá-los separadamente e fazer coisas 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 cristão apontou:

Se você deseja que erros de http (por exemplo, 401 Não Autorizado) gerem exceções, você pode ligar Response.raise_for_status. Isso criará umHTTPError , se a resposta for um erro http.

Um exemplo:

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

Irá imprimir:

404 Client Error: Not Found for url: http://www.google.com/nothere
Jonathon Reinhart
fonte
11
Resposta muito boa para lidar com os detalhes da biblioteca de solicitações e também para capturar exceções em geral.
Brian Peterson
10
Observe que, devido a um erro na biblioteca subjacente urllib3, você também precisará capturar socket.timeoutexceções se estiver usando um tempo limite: github.com/kennethreitz/requests/issues/1236
jb.
15
Futuros comentário leitores: este foi fixado em Solicitações 2.9 (que agrupa urllib3 1,13)
RazerM
14
Se você deseja que erros http (por exemplo, 401 Não Autorizado) gerem exceções, ligue para Response.raise_for_status . Isso gerará um HTTPError, se a resposta for um erro http.
Christian Long
5
A lista de exceções no site de solicitação não está completa. Você pode ler a lista completa aqui .
Epoc 31/01
87

Uma sugestão adicional a ser explícita. Parece melhor ir de específico para geral na pilha de erros para obter o erro desejado, para que os específicos não sejam mascarados pelo geral.

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
fonte
esta sintaxe também é válida para postagem?
ScipioAfricanus
@ScipioAfricanus yes.
andrea
10

O objeto de exceção também contém resposta original e.response, que pode ser útil se for necessário ver o corpo do erro em resposta do servidor. Por exemplo:

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
fonte