web-dev-qa-db-fra.com

Pourquoi requests.get () ne retourne-t-il pas? Quel est le délai d'attente par défaut utilisé par requests.get ()?

Dans mon script, requests.get ne revient jamais:

import requests

print ("requesting..")

# This call never returns!
r = requests.get(
    "http://www.justdial.com",
    proxies = {'http': '222.255.169.74:8080'},
)

print(r.ok)

Quelle pourrait être la raison possible? Un remède? Quel est le délai d'attente par défaut utilisé par get?

75
Nawaz

Quel est le délai d'attente par défaut qui est utilisé?

Le délai d'attente par défaut est None, ce qui signifie qu'il attendra jusqu'à la fermeture de la connexion.

Que se passe-t-il lorsque vous passez une valeur de délai d'attente?

r = requests.get(
    'http://www.justdial.com',
    proxies={'http': '222.255.169.74:8080'},
    timeout=5
)
109
ron rothman

De demande de la documentation :

Vous pouvez indiquer aux demandes de ne plus attendre les réponses après un nombre de secondes donné avec le paramètre timeout:

>>> requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(Host='github.com', port=80): Request timed out. (timeout=0.001)

Remarque:

le délai d'attente n'est pas une limite de temps pour le téléchargement complet de la réponse; une exception est plutôt générée si le serveur n'a pas émis de réponse pendant le délai d'attente de secondes (plus précisément, si aucun octet n'a été reçu sur le socket sous-jacent pendant le délai d'attente de secondes).

Il m'est souvent arrivé que requests.get () mette beaucoup de temps à retourner, même si le timeout dure 1 seconde. Il y a plusieurs façons de surmonter ce problème:

1. Utilisez la classe interne TimeoutSauce

De: https://github.com/kennethreitz/requests/issues/1928#issuecomment-35811896

import requests from requests.adapters import TimeoutSauce

class MyTimeout(TimeoutSauce):
    def __init__(self, *args, **kwargs):
        if kwargs['connect'] is None:
            kwargs['connect'] = 5
        if kwargs['read'] is None:
            kwargs['read'] = 5
        super(MyTimeout, self).__init__(*args, **kwargs)

requests.adapters.TimeoutSauce = MyTimeout

Ce code doit nous amener à définir le délai de lecture comme étant égal au délai de connexion, qui correspond à la valeur de délai que vous transmettez à votre appel Session.get (). (Notez que je n'ai pas encore testé ce code, il peut donc nécessiter un débogage rapide, je l'ai simplement écrit directement dans la fenêtre de GitHub.)

2. Utilisez une fourchette de demandes provenant de kevinburke: https://github.com/kevinburke/requests/tree/connect-timeout

À partir de sa documentation: https://github.com/kevinburke/requests/blob/connect-timeout/docs/user/advanced.rst

Si vous spécifiez une seule valeur pour le délai d'attente, procédez comme suit:

r = requests.get('https://github.com', timeout=5)

La valeur de délai d'attente sera appliquée à la fois aux délais de connexion et de lecture. Spécifiez un tuple si vous souhaitez définir les valeurs séparément:

r = requests.get('https://github.com', timeout=(3.05, 27))

REMARQUE: la modification a depuis été fusionnée avec le projet Requests principal .

3. Utiliser evenlet ou signal comme déjà mentionné dans la même question: délai d'attente pour python requests.get réponse entière

31
Hieu

A examiné toutes les réponses et est parvenu à la conclusion que le problème existait toujours. Sur certains sites, les demandes peuvent être suspendues indéfiniment et l'utilisation du multitraitement semble excessive. Voici mon approche (Python 3.5+):

import asyncio

import aiohttp


async def get_http(url):
    async with aiohttp.ClientSession(conn_timeout=1, read_timeout=3) as client:
        try:
            async with client.get(url) as response:
                content = await response.text()
                return content, response.status
        except Exception:
            pass


loop = asyncio.get_event_loop()
task = loop.create_task(get_http('http://example.com'))
loop.run_until_complete(task)
result = task.result()
if result is not None:
    content, status = task.result()
    if status == 200:
        print(content)
2
Alex Polekha

Je voulais un délai d'attente par défaut facilement ajouté à un tas de code (en supposant que le délai d'attente résout votre problème)

C’est la solution que j’ai choisie à partir d’un ticket soumis au référentiel des demandes.

crédit: https://github.com/kennethreitz/requests/issues/2011#issuecomment-477784399

La solution est les deux dernières lignes ici, mais je montre plus de code pour un meilleur contexte. J'aime utiliser une session pour réessayer le comportement.

import requests
import functools
from requests.adapters import HTTPAdapter,Retry


def requests_retry_session(
        retries=10,
        backoff_factor=2,
        status_forcelist=(500, 502, 503, 504),
        session=None,
        ) -> requests.Session:
    session = session or requests.Session()
    retry = Retry(
            total=retries,
            read=retries,
            connect=retries,
            backoff_factor=backoff_factor,
            status_forcelist=status_forcelist,
            )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    # set default timeout
    for method in ('get', 'options', 'head', 'post', 'put', 'patch', 'delete'):
        setattr(session, method, functools.partial(getattr(session, method), timeout=30))
    return session

alors vous pouvez faire quelque chose comme ceci:

requests_session = requests_retry_session()
r = requests_session.get(url=url,...
0
Tim Richardson