Prawidłowy sposób wypróbowania / oprócz używania modułu żądań Python?

Odpowiedzi:

794

Zajrzyj do dokumentacji wyjątków Zgłoszenia . W skrócie:

W przypadku problemu z siecią (np. Awaria DNS, odmowa połączenia itp.) Żądania zgłoszą ConnectionErrorwyjątek.

W przypadku rzadkiej niepoprawnej odpowiedzi HTTP Żądania zgłoszą HTTPErrorwyjątek.

Jeśli upłynie limit czasu żądania, Timeoutzgłaszany jest wyjątek.

Jeśli żądanie przekroczy skonfigurowaną liczbę maksymalnych przekierowań, TooManyRedirectszgłaszany jest wyjątek.

Wszystkie wyjątki, które żądania jawnie wywołują, dziedziczą requests.exceptions.RequestException.

Aby odpowiedzieć na twoje pytanie, to, co pokażesz, nie obejmie wszystkich twoich baz. Złapiesz tylko błędy związane z połączeniem, a nie te, które przekroczą limit czasu.

Co zrobić, gdy złapiesz wyjątek, tak naprawdę zależy od projektu twojego skryptu / programu. Czy można wyjść? Czy możesz kontynuować i spróbować ponownie? Jeśli błąd jest katastrofalny i nie można go kontynuować, to tak, możesz przerwać program, podnosząc SystemExit (dobry sposób na wydrukowanie błędu i wywołanie sys.exit).

Możesz złapać wyjątek klasy podstawowej, który będzie obsługiwał wszystkie przypadki:

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

Lub możesz złapać je osobno i robić różne rzeczy.

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)

Jak zauważył Christian :

Jeśli chcesz, aby błędy http (np. 401 nieautoryzowane) zgłaszały wyjątki, możesz zadzwonić Response.raise_for_status. To podniesie HTTPError, jeśli odpowiedź była błędem http.

Przykład:

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

Wydrukuje:

404 Client Error: Not Found for url: http://www.google.com/nothere
Jonathon Reinhart
źródło
11
Bardzo dobra odpowiedź do radzenia sobie ze specyfiką biblioteki żądań, a także do ogólnego wychwytywania wyjątków.
Brian Peterson
10
Zauważ, że z powodu błędu w podkładającej bibliotece urllib3 musisz także wychwycić socket.timeoutwyjątki, jeśli używasz limitu czasu: github.com/kennethreitz/requests/issues/1236
jb.
15
Przyszłe czytniki komentarzy: zostało to naprawione w Requests 2.9 (który zawiera pakiet urllib3 1.13)
RazerM
14
Jeśli chcesz, aby błędy http (np. 401 nieautoryzowane) zgłaszały wyjątki, możesz wywołać Response.raise_for_status . To spowoduje podniesienie błędu HTTP, jeśli odpowiedzią był błąd http.
Christian Długi
5
Lista wyjątków w witrynie Request nie jest kompletna. Możesz przeczytać pełną listę tutaj .
Epoc
87

Jedna dodatkowa sugestia, która ma być jednoznaczna. Wydaje się, że najlepiej jest przechodzić od konkretnego do ogólnego w dół stosu błędów, aby uzyskać pożądany błąd do złapania, więc te konkretne nie są maskowane przez ogólny.

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
źródło
czy to też jest poprawna składnia postu?
ScipioAfricanus
@ScipioAfricanus tak.
andrea
10

Obiekt wyjątku zawiera również oryginalną odpowiedź e.response, która może być przydatna, jeśli trzeba zobaczyć treść błędu w odpowiedzi z serwera. Na przykład:

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
źródło