J'utilise la bibliothèque de demandes pour obtenir un grand nombre de pages Web quelque part. Il est le code pertinent:
response = requests.Session()
retries = Retry(total=5, backoff_factor=.1)
response.mount('http://', HTTPAdapter(max_retries=retries))
response = response.get(url)
Après un certain temps, il se bloque/se fige (jamais sur la même page Web) lors de l'obtention de la page. Voici le traceback lorsque je l'interromps:
File "/Users/Student/Hockey/Scrape/html_pbp.py", line 21, in get_pbp
response = r.read().decode('utf-8')
File "/anaconda/lib/python3.6/http/client.py", line 456, in read
return self._readall_chunked()
File "/anaconda/lib/python3.6/http/client.py", line 566, in _readall_chunked
value.append(self._safe_read(chunk_left))
File "/anaconda/lib/python3.6/http/client.py", line 612, in _safe_read
chunk = self.fp.read(min(amt, MAXAMOUNT))
File "/anaconda/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
KeyboardInterrupt
Quelqu'un sait-il ce qui pourrait en être la cause? Ou (plus important encore), quelqu'un connaît-il un moyen de l'arrêter si cela prend plus d'un certain temps pour que je puisse réessayer?
Il semble que la définition d'un (lecture) délai d'attente pourrait vous aider.
Quelque chose dans le sens de:
response = response.get(url, timeout=5)
(Cela définira le délai de connexion et de lecture sur 5 secondes.)
Dans requests
, malheureusement, ni connect ni read timeouts sont définis par défaut, même si les docs say il est bon de le régler:
La plupart des demandes adressées à des serveurs externes doivent avoir un délai d'attente attaché , au cas où le serveur ne répondrait pas en temps opportun. Par défaut, les demandes ne dépassent pas le délai sauf si une valeur de délai d'attente est définie explicitement. Sans délai, votre code peut se bloquer pendant quelques minutes ou plus.
Juste pour être complet, le délai de connexion est le nombre de secondes que requests
attendra que votre client établisse une connexion avec une machine distante, et le délai de lecture est le nombre de secondes pendant lesquelles le client attendra entre les octets envoyés par le serveur.
Corriger la fonction "envoyer" documentée corrigera cela pour toutes les requêtes - même dans de nombreuses bibliothèques et sdk dépendants. Lorsque vous corrigez des bibliothèques, assurez-vous de corriger les fonctions prises en charge/documentées, sinon vous risquez de perdre silencieusement l'effet de votre correctif.
import requests
old_send = requests.Session.send
def new_send(*args, **kwargs):
if kwargs.get("timeout", None) is None:
kwargs["timeout"] = DEFAULT_TIMEOUT
return old_send(*args, **kwargs)
requests.Session.send = new_send
Pour définir le délai d'expiration globalement au lieu de le spécifier dans chaque demande:
from requests.adapters import TimeoutSauce
REQUESTS_TIMEOUT_SECONDS = float(os.getenv("REQUESTS_TIMEOUT_SECONDS", 5))
class CustomTimeout(TimeoutSauce):
def __init__(self, *args, **kwargs):
if kwargs["connect"] is None:
kwargs["connect"] = REQUESTS_TIMEOUT_SECONDS
if kwargs["read"] is None:
kwargs["read"] = REQUESTS_TIMEOUT_SECONDS
super().__init__(*args, **kwargs)
# Set it globally, instead of specifying ``timeout=..`` kwarg on each call.
requests.adapters.TimeoutSauce = CustomTimeout
sess = requests.Session()
sess.get(...)
sess.post(...)