236 votes

Demandes asynchrones avec Python requests

J'ai essayé l'échantillon fourni dans la documentation de l'application bibliothèque des demandes pour python.

Avec async.map(rs) J'obtiens les codes de réponse, mais je veux obtenir le contenu de chaque page demandée. Ceci, par exemple, ne fonctionne pas :

out = async.map(rs)
print out[0].content

0 votes

Peut-être que les réponses que vous obtenez ont un corps vide ?

0 votes

Ça marche pour moi. Veuillez poster l'erreur complète que vous obtenez.

0 votes

Il n'y a pas d'erreur. il s'exécute simplement pour toujours par les urls de test fournies.

194voto

Jeff Points 959

Nota

La réponse ci-dessous est no applicable aux demandes v0.13.0+. La fonctionnalité asynchrone a été déplacée vers grequests après que cette question ait été écrite. Cependant, vous pourriez simplement remplacer requests con grequests ci-dessous et cela devrait fonctionner.

J'ai laissé cette réponse telle quelle pour refléter la question originale qui concernait l'utilisation des requêtes < v0.13.0.


Pour effectuer plusieurs tâches avec async.map de manière asynchrone vous devez le faire :

  1. Définissez une fonction pour ce que vous voulez faire avec chaque objet (votre tâche).
  2. Ajoutez cette fonction comme un crochet d'événement dans votre requête
  3. Appelez async.map sur une liste de toutes les demandes / actions

Exemple :

from requests import async
# If using requests > v0.13.0, use
# from grequests import async

urls = [
    'http://python-requests.org',
    'http://httpbin.org',
    'http://python-guide.org',
    'http://kennethreitz.com'
]

# A simple task to do to each response object
def do_something(response):
    print response.url

# A list to hold our things to do via async
async_list = []

for u in urls:
    # The "hooks = {..." part is where you define what you want to do
    # 
    # Note the lack of parentheses following do_something, this is
    # because the response will be used as the first argument automatically
    action_item = async.get(u, hooks = {'response' : do_something})

    # Add the task to our list of things to do via async
    async_list.append(action_item)

# Do our list of things to do via async
async.map(async_list)

2 votes

Bonne idée d'avoir laissé votre commentaire : en raison de problèmes de compatibilité entre les dernières versions de requests et grequests (absence de l'option max_retries dans requests 1.1.0), j'ai dû rétrograder requests pour récupérer l'asynchrone et j'ai constaté que la fonctionnalité asynchrone a été déplacée avec les versions 0.13+ ( pypi.python.org/pypi/requests )

0 votes

Merci de l'avoir souligné ! Je vais modifier ma réponse pour refléter cette information.

1 votes

Question bête : Quelle est l'augmentation de la vitesse d'utilisation des grequests par rapport aux simples requêtes ? Quelles sont les limites concernant les requêtes ? Par exemple, est-ce que mettre 3500 requêtes dans async.map est acceptable ?

110voto

outforawhile Points 308

async est maintenant un module indépendant : grequests .

Voir ici : https://github.com/kennethreitz/grequests

Et là : Méthode idéale pour envoyer plusieurs requêtes HTTP via Python ?

installation :

$ pip install grequests

l'usage :

construire une pile :

import grequests

urls = [
    'http://www.heroku.com',
    'http://tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://kennethreitz.com'
]

rs = (grequests.get(u) for u in urls)

envoyer la pile

grequests.map(rs)

Le résultat ressemble à

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]

Les grequests ne semblent pas fixer de limite pour les demandes simultanées, c'est-à-dire lorsque plusieurs demandes sont envoyées au même serveur.

11 votes

En ce qui concerne la limitation des requêtes simultanées, vous pouvez spécifier une taille de pool lors de l'exécution de map()/imap(). Par exemple, grequests.map(rs, size=20) pour avoir 20 saisies simultanées.

3 votes

Pour l'instant, il n'est pas compatible avec python3 (gevent ne parvient pas à construire la version 2.6 sur py3.4).

1 votes

Je ne comprends pas bien la partie async. Si je laisse results = grequests.map(rs) le code après cette ligne est en bloc, je peux voir l'effet asynchrone ?

37voto

Dreampuf Points 179

Peut-être demandes-futures est un autre choix.

from requests_futures.sessions import FuturesSession

session = FuturesSession()
# first request is started in background
future_one = session.get('http://httpbin.org/get')
# second requests is started immediately
future_two = session.get('http://httpbin.org/get?foo=bar')
# wait for the first request to complete, if it hasn't already
response_one = future_one.result()
print('response one status: {0}'.format(response_one.status_code))
print(response_one.content)
# wait for the second request to complete, if it hasn't already
response_two = future_two.result()
print('response two status: {0}'.format(response_two.status_code))
print(response_two.content)

Il est également recommandé dans le document de bureau . Si vous ne voulez pas participer à un événement, c'est un bon événement.

1 votes

Une des solutions les plus simples. Le nombre de requêtes simultanées peut être augmenté en définissant le paramètre max_workers.

1 votes

Il serait intéressant de voir un exemple de ce système à l'échelle, afin de ne pas utiliser un nom de variable par élément à parcourir en boucle.

0 votes

Avoir un thread par requête est un gaspillage de ressources ! il n'est pas possible de faire par exemple 500 requêtes simultanément, cela tuerait votre cpu. cela ne devrait jamais être considéré comme une bonne solution.

7voto

Monkey Boson Points 469

Je sais que ce sujet est clos depuis un moment, mais j'ai pensé qu'il pourrait être utile de promouvoir une autre solution asynchrone construite sur la bibliothèque requests.

list_of_requests = ['http://moop.com', 'http://doop.com', ...]

from simple_requests import Requests
for response in Requests().swarm(list_of_requests):
    print response.content

Les documents sont ici : http://pythonhosted.org/simple-requests/

0 votes

@YSY N'hésitez pas à poster un problème : github.com/ctheiss/simple-requests/issues J'utilise littéralement cette bibliothèque des milliers de fois par jour.

0 votes

Boston, comment gérez-vous les erreurs 404/500 ? qu'en est-il des urls https ? j'apprécierais un snipping qui prend en charge des milliers d'urls. pouvez-vous coller un exemple ? merci.

0 votes

@YSY Par défaut, les erreurs 404/500 soulèvent une exception. Ce comportement peut être modifié (voir pythonhosted.org/simple-requests/ ). Les urls HTTPS sont délicates en raison de la dépendance à l'égard de gevent, qui a actuellement un bogue en suspens à ce sujet ( github.com/gevent/gevent/issues/477 ). Il y a un shim dans le ticket que vous pouvez exécuter, mais il affichera toujours des avertissements pour les serveurs SNI (mais il sera travail). Pour ce qui est du snipping, j'ai bien peur que tous mes usages soient dans mon entreprise et fermés. Mais je vous assure que nous exécutons des milliers de requêtes sur des dizaines de travaux.

2voto

David Watson Points 850

Depuis quelque temps, j'utilise des requêtes python pour les appels asynchrones contre l'API gist de github.

Pour un exemple, voir le code ici :

https://github.com/davidthewatson/flasgist/blob/master/views.py#L60-72

Ce style de python n'est peut-être pas l'exemple le plus clair, mais je peux vous assurer que le code fonctionne. L

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X