Question En utilisant des requêtes Grequests pour faire en sorte que plusieurs milliers de requêtes soient envoyées à sourceforge, obtenez "Max retries dépassé avec url"


Je suis très nouveau à tout cela; Je dois obtenir des données sur plusieurs milliers de projets sourceforge pour un article que j'écris. Les données sont toutes disponibles gratuitement au format json à l'adresse http://sourceforge.net/api/project/name/[project name] / 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 peux obtenir les données pour quelque 200 projets que j'aime, c'est-à-dire rs = (grequests.get(u) for u in ulist[0:199]) fonctionne, mais dès que je repasse par-dessus, toutes les tentatives sont rencontrées

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 d'autres requêtes jusqu'à ce que je quitte Python, mais dès que je redémarre python, je peux faire 200 autres requêtes.

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


22
2018-02-24 02:55


origine


Réponses:


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

Dans mon cas, le serveur de destination ne limitait pas le débit, mais quelque chose de beaucoup plus simple: je ne fermais pas explicitement les réponses, ils gardaient donc le socket ouvert et le processus python manquait de descripteurs de fichiers.

Ma solution (je ne sais pas avec certitude lequel a résolu le problème - théoriquement l'un ou l'autre devrait) était de:

  • Ensemble stream=False dans grequests.get:

    rs = (grequests.get(u, stream=False) for u in urls)
    
  • Appelez explicitement response.close() après avoir lu response.content:

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

Remarque: simplement détruire le response objet (attribution None à elle, appelant gc.collect()) ne suffisait pas - cela ne fermait pas les gestionnaires de fichiers.


23
2018-04-03 13:39



Celui-ci peut être facilement modifié pour utiliser le nombre de connexions souhaité.

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
2017-12-21 20:05