Nombre maximal de tentatives dépassé avec l'URL dans les demandes

153

J'essaie d'obtenir le contenu de l' App Store> Entreprise :

import requests
from lxml import html

page = requests.get("https://itunes.apple.com/in/genre/ios-business/id6000?mt=8")
tree = html.fromstring(page.text)

flist = []
plist = []
for i in range(0, 100):
    app = tree.xpath("//div[@class='column first']/ul/li/a/@href")
    ap = app[0]
    page1 = requests.get(ap)

Quand j'essaye rangeavec (0,2)ça marche, mais quand je mets le rangedans, 100ça montre cette erreur:

Traceback (most recent call last):
  File "/home/preetham/Desktop/eg.py", line 17, in <module>
    page1 = requests.get(ap)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 383, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 486, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 378, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='itunes.apple.com', port=443): Max retries exceeded with url: /in/app/adobe-reader/id469337564?mt=8 (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)
user3446000
la source
1
Ne devriez-vous pas utiliser la ivariable quelque part dans le for?
Laurent S.
vous êtes comme demander la même application 100 fois. à quoi ça sert?
njzk2
J'utilise i dans le reste du code. Je n'ai pas posté l'intégralité du code
user3446000
Je ne demande pas 100 fois la même application. Je demande 100 applications différentes dans la même catégorie.
user3446000
3
Il semble que votre résolveur DNS ne puisse pas résoudre itunes.apple.com. Pouvez-vous exécuter dig itunes.apple.comsur votre ligne de commande et publier les résultats ici?
Thomas Orozco

Réponses:

141

Ce qui s'est passé ici, c'est que le serveur iTunes refuse votre connexion (vous envoyez trop de demandes à partir de la même adresse IP dans un court laps de temps)

Nombre maximal de tentatives dépassé avec l'URL: / in / app / adobe-reader / id469337564? Mt = 8

La trace d'erreur est trompeuse, cela devrait être quelque chose comme "Aucune connexion n'a pu être établie car la machine cible l'a activement refusée" .

Il y a un problème à propos de python.requests lib sur Github, vérifiez-le ici

Pour surmonter ce problème (pas tellement un problème car il s'agit d'une trace de débogage trompeuse), vous devez intercepter les exceptions liées à la connexion comme ceci:

try:
    page1 = requests.get(ap)
except requests.exceptions.ConnectionError:
    r.status_code = "Connection refused"

Une autre façon de surmonter ce problème est que si vous utilisez suffisamment de temps pour envoyer des requêtes au serveur, cela peut être réalisé par une sleep(timeinsec)fonction en python (n'oubliez pas d'importer sleep)

from time import sleep

Dans l'ensemble, les requêtes sont géniales python lib, espérons que cela résout votre problème.

Djra
la source
2
La boucle de sommeil a résolu mon problème - un peu un hack, mais en effectuant une boucle plusieurs fois tout en gérant la réponse d'erreur, j'ai pu trouver une solution par force brute.
elPastor
14
Cette réponse est en fait fausse. Il s'agit d'un problème de recherche de résolveur, comme indiqué par la (Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)pièce. "gai" signifie getaddrinfo, et l'erreur associée probable est: EAI_NONAME Le nœud ou le service n'est pas connu; ou le nœud et le service sont NULL; ou AI_NUMERICSERV a été spécifié dans hints.ai_flags et le service n'était pas une chaîne de numéro de port numérique. Cela ressemblait probablement au sommeil corrigé, mais vous venez probablement de dormir à travers un problème de résolution DNS transitoire.
lingfish
4
Cette réponse ne semble pas logique car dans «r» est l'objet qui provient de requests.get () donc à l'exception, cela conduit simplement à une autre erreur.
mikkokotila
Cette réponse n'a pas de sens. L'erreur d'OP ne dit pas «Connexion refusée», mais «Nom ou service inconnu». Cette réponse semble supposer que toutes les ConnectionError sont dues à "Connection refusée".
erjiang
1
Pour moi, cela doit être tout à fait exact, une limite de débit placée par le serveur. Je peux faire 80 appels et ce message apparaîtra pour moi. Ensuite, après un court laps de temps, le serveur est disponible pour 80 autres appels et le cycle se répète. c'est trop régulier pour être autre chose.
demongolem le
123

Utilisez simplement les requests'fonctionnalités:

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry


session = requests.Session()
retry = Retry(connect=3, backoff_factor=0.5)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)

session.get(url)

Ce sera GETl'URL et réessayer 3 fois en cas de requests.exceptions.ConnectionError.backoff_factoraidera à appliquer des délais entre les tentatives pour éviter d'échouer à nouveau en cas de quota de demandes périodiques.

Jetez un œil à requests.packages.urllib3.util.retry.Retry, il a de nombreuses options pour simplifier les tentatives.

zoulou
la source
Pour une raison quelconque, cela ne fonctionne pas sous Windows 10. J'ai démarré le shell avec python manage.py shellet j'utilise session.get('http://localhost:8000/api/'). De l'aide? @Zulu
MwamiTovi
j'ai réglé mon problème. J'avais oublié de démarrer le dev-serveret de le faire fonctionner en premier.
MwamiTovi
Pourquoi ce n'est toujours pas la meilleure réponse?
Pavel Druzhinin
J'ai essayé cela mais je n'ai pas réessayé pendant que j'obtenais des requêtes.exceptions.ConnectionError La lecture a expiré. mais j'ai défini un délai pour la demande d'obtention.
Zagfai
34

Fais juste ça,

Collez le code suivant à la place de page = requests.get(url):

import time

page = ''
while page == '':
    try:
        page = requests.get(url)
        break
    except:
        print("Connection refused by the server..")
        print("Let me sleep for 5 seconds")
        print("ZZzzzz...")
        time.sleep(5)
        print("Was a nice sleep, now let me continue...")
        continue

Vous êtes les bienvenus :)

jatin
la source
3
n'oubliez pas de faire import time
Yuan Tao
3
requestsa son propre code pour gérer son erreur et réessayer
Zulu
5
Il ne sort jamais de la boucle. @jatin
alper
11
De plus, ce n'est pas une bonne idée d'attraper n'importe quel type d'exception (avec except: ...) requestset sleep()en réponse. Au lieu de cela, ils devraient attraper requests.exceptions.ConnectionErroret sleep()seulement si cette exception se produit. (Ou mieux encore, utilisez simplement la Retry()classe intégrée fournie avec requests, comme suggéré par @Zulu).
J.Taylor
16

J'ai eu un problème similaire mais le code suivant a fonctionné pour moi.

url = <some REST url>    
page = requests.get(url, verify=False)

"verify = False" désactive la vérification SSL. Try and catch peut être ajouté comme d'habitude.

Raj Stha
la source
5

Il est toujours bon d'implémenter la gestion des exceptions. Cela aide non seulement à éviter la sortie inattendue du script, mais peut également aider à consigner les erreurs et les notifications d'informations. Lorsque j'utilise des requêtes Python, je préfère attraper des exceptions comme celle-ci:

    try:
        res = requests.get(adress,timeout=30)
    except requests.ConnectionError as e:
        print("OOPS!! Connection Error. Make sure you are connected to Internet. Technical Details given below.\n")
        print(str(e))            
        renewIPadress()
        continue
    except requests.Timeout as e:
        print("OOPS!! Timeout Error")
        print(str(e))
        renewIPadress()
        continue
    except requests.RequestException as e:
        print("OOPS!! General Error")
        print(str(e))
        renewIPadress()
        continue
    except KeyboardInterrupt:
        print("Someone closed the program")

Ici, renewIPadress () est une fonction définie par l'utilisateur qui peut changer l'adresse IP si elle est bloquée. Vous pouvez vous passer de cette fonction.

Tanmoy Datta
la source
votre solution est sympa mais comment changer ip-adrressen python, savez-vous quelque chose à ce sujet, alors faites le moi savoir
Haritsinh Gohil
1
J'avais utilisé un service VPN IPVanish et Hide My Ass. Ils sont configurés en utilisant open-vpn et open-vpn ont une ligne de commande shell renouvelant l'adresse IP. Vous pouvez appeler la commande shell ou bash depuis python. De cette façon, vous pouvez l'implémenter.
Tanmoy Datta
5

La spécification du proxy dans un environnement d'entreprise l'a résolu pour moi.

page = requests.get("http://www.google.com:80", proxies={"http": "http://111.233.225.166:1234"})

L'erreur complète est:

request.exceptions.ConnectionError: HTTPSConnectionPool (host = 'www.google.com', port = 80): Nombre maximal de tentatives dépassé avec url: / (Caused by NewConnectionError (': Échec de l'établissement d'une nouvelle connexion: [WinError 10060] Une connexion la tentative a échoué car la partie connectée n'a pas répondu correctement après un certain temps ou la connexion établie a échoué car l'hôte connecté n'a pas répondu '))

Jeremy Thompson
la source
2

Je n'ai pas pu le faire fonctionner sur Windows même après avoir installé pyopenssl et essayé diverses versions de python (alors que cela fonctionnait bien sur mac), alors je suis passé à urllib et cela fonctionne sur python 3.6 (à partir de python .org) et 3.7 (anaconda )

import urllib 
from urllib.request import urlopen
html = urlopen("http://pythonscraping.com/pages/page1.html")
contents = html.read()
print(contents)
Alex
la source
Je suis assez ennuyé que les choses ne fonctionnent que si elles sont exécutées avec l'invite Anaconda.
BingLi224
1

Lorsque j'écrivais un script de test de navigateur au sélénium, j'ai rencontré cette erreur lors d'un appel driver.quit()avant l'utilisation d'un appel API JS.N'oubliez pas que quitter Webdriver est la dernière chose à faire!

Saleh
la source
1

Ajout de ma propre expérience pour ceux qui vivent cela dans le futur. Mon erreur spécifique était

Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'

Il s'avère que c'était en fait parce que j'avais atteint le nombre maximum de fichiers ouverts sur mon système. Cela n'avait rien à voir avec des connexions échouées, ou même une erreur DNS comme indiqué.

Oded
la source
0

Ajout de ma propre expérience:

r = requests.get(download_url)

lorsque j'ai essayé de télécharger un fichier spécifié dans l'url.

L'erreur était

HTTPSConnectionPool(host, port=443): Max retries exceeded with url (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))

Je l'ai corrigé en ajoutant verify = Falsela fonction comme suit:

r = requests.get(download_url + filename)
open(filename, 'wb').write(r.content)
Suraj Subramanian
la source
0

Vérifiez votre connexion réseau. J'avais ceci et la VM n'avait pas une connexion réseau appropriée.

Timothy C. Quinn
la source
-1

Ajoutez des en-têtes pour cette demande.

headers={
'Referer': 'https://itunes.apple.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
}

requests.get(ap, headers=headers)
Michael Yang
la source