web-dev-qa-db-fra.com

Python Demande de suspension / gel

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?

11
Hobbit36

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.

13
randomir

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
0
Erik Aronesty

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(...)
0
Danila Vershinin