En utilisant grequests pour faire plusieurs milliers de requêtes get à sourceforge, get " Max retries exceeded with url"

je suis très nouveau à tout cela; j'ai besoin d'obtenir des données sur plusieurs milliers de projets sourceforge pour un papier que j'écris. Les données sont toutes librement disponibles en format json à l'url http://sourceforge.net/api/project/name/[nom du projet]/json. J'ai une liste de plusieurs milliers de ces URL et j'utilise le code suivant.

import grequests
rs = (grequests.get(u) for u in ulist)
answers = grequests.map(rs)

en utilisant ce code, je suis capable d'obtenir les données pour quelque 200 projets que j'aime, i.e. rs = (grequests.get(u) for u in ulist[0:199]) fonctionne, mais dès que je vais sur ce que, tous les tentatives sont accueillies avec

ConnectionError: HTTPConnectionPool(host='sourceforge.net', port=80): Max retries exceeded with url: /api/project/name/p2p-fs/json (Caused by <class 'socket.gaierror'>: [Errno 8] nodename nor servname provided, or not known)
<Greenlet at 0x109b790f0: <bound method AsyncRequest.send of <grequests.AsyncRequest object at 0x10999ef50>>(stream=False)> failed with ConnectionError

je suis alors incapable de faire plus de requêtes jusqu'à ce que je quitte python, mais dès que je redémarre python je peux faire encore 200 requêtes.

j'ai essayé d'utiliser grequests.map(rs,size=200) mais cela semble ne rien faire.

22
demandé sur crf 2014-02-24 06:55:33

2 réponses

donc, je réponds ici, peut-être que cela aidera les autres.

dans mon cas, ce n'était pas une limitation de vitesse par le serveur de destination, mais quelque chose de beaucoup plus simple: je n'ai pas explicitement fermé les réponses, donc ils ont gardé la socket ouverte, et le processus python a été à court de poignées de fichiers.

ma solution (je ne sais pas avec certitude qui a réglé le problème - en théorie l'un ou l'autre devrait) était de:

  • Set stream=False dans grequests.get:

    rs = (grequests.get(u, stream=False) for u in urls)
    
  • Appel explicitement response.close() après avoir lu réponse.contenu:

    responses = grequests.map(rs)
    for response in responses:
          make_use_of(response.content)
          response.close()
    

Remarque: simplement détruire l' response objet (assigning None pour cela, appel de gc.collect()) n'était pas suffisant - cela n'a pas fermé les gestionnaires de fichiers.

23
répondu Virgil 2015-08-09 08:14:28

celui-ci peut être facilement modifié pour utiliser n'importe quel nombre de connexions que vous voulez.

MAX_CONNECTIONS = 100 #Number of connections you want to limit it to
# urlsList: Your list of URLs. 

results = []
for x in range(1,pages+1, MAX_CONNECTIONS):
    rs = (grequests.get(u, stream=False) for u in urlsList[x:x+MAX_CONNECTIONS])
    time.sleep(0.2) #You can change this to whatever you see works better. 
    results.extend(grequests.map(rs)) #The key here is to extend, not append, not insert. 
    print("Waiting") #Optional, so you see something is done. 
1
répondu MaikelDotUk 2016-12-21 20:35:24