请求中的URL超过了最大重试次数

304

我正在尝试获取App Store > Business的内容:

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)

当我尝试使用(0,2)range时,它可以正常工作,但是当我把range放入100中时,就会显示以下错误:

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)

4
你在 for 循环中不应该使用 i 变量吗? - Laurent S.
2
你就像请求同一个应用程序100次一样,这是为什么? - njzk2
我在代码的其余部分中使用i。我没有发布整个代码。 - user3446000
4
看起来你的 DNS 解析器无法解析 itunes.apple.com。你可以在命令行中运行 dig itunes.apple.com 并将结果发布在此处吗? - Thomas Orozco
1
我曾经遇到过这个错误,我通过将9150端口更改为9050来解决它。 - JinSnow
显示剩余6条评论
20个回答

288

只需使用requests功能:

import requests
from requests.adapters import HTTPAdapter
from 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)

这将GET该URL并在出现requests.exceptions.ConnectionError时重试3次。 backoff_factor会帮助在尝试之间应用延迟,以避免在定期请求配额的情况下再次失败。

看看urllib3.util.retry.Retry,它有许多选项可以简化重试。


3
不知何故,在Windows 10上无法正常运行。 使用 python manage.py shell 启动shell,并使用 session.get('http://localhost:8000/api/') 。有人能提供帮助吗? @Zulu - MwamiTovi
2
问题解决了。我忘记先启动并保持 dev-server 运行了。 - MwamiTovi
我尝试过这个,但是当我遇到requests.exceptions.ConnectionError读取超时时,它不会重试。但是我已经为get请求设置了超时时间。 - Zagfai
1
这个程序已经尝试运行了超过5分钟。它是否会超时并报告失败?或者max_retries=retry的代码意味着永不停止尝试? - Nick
1
@Nick 根据文档规定,有一个参数 total 用于指定尝试的次数。 - Zulu
使用requests模块中的Retry,请查看以下答案: https://dev59.com/oGUp5IYBdhLWcg3wNVhb#35504626 - Akshay Chandran

212

这里发生的情况是iTunes服务器拒绝了您的连接(您在短时间内从同一IP地址发送了太多请求)。

URL /in/app/adobe-reader/id469337564?mt=8 的最大重试次数已超过。

错误跟踪是具有误导性的,应该是类似于"无法建立连接,因为目标机器主动拒绝了它"的信息。

在 Github 上关于 python.requests 库存在问题,可以在此处查看。

为了解决这个问题(不是真正的问题,而是误导性的调试跟踪),您应该像这样捕获与连接相关的异常:

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

另一种克服这个问题的方法是在向服务器发送请求之间使用足够的时间间隔,可以通过 Python 中的 sleep(timeinsec) 函数实现(不要忘记导入 sleep)

from time import sleep

总的来说,requests 是一个很棒的 Python 库,希望这可以解决你的问题。


3
“睡眠循环”解决了我的问题——这有点取巧,但是通过在处理错误响应时循环几次,我能够用强制方式找到一个解决方案。 - elPastor
34
这个答案实际上是错误的。这是一个解析器查找问题,正如(Caused by <class 'socket.gaierror'>: [Errno -2] Name or service not known)部分所示。"gai"代表getaddrinfo,可能相关的错误是:EAI_NONAME 节点或服务未知;或者节点和服务均为空;或在hints.ai_flags中指定了AI_NUMERICSERV,而service不是数字端口号字符串。你可能认为睡眠解决了问题,但实际上可能只是因为DNS解析器问题是短暂的,你刚好睡过去了。 - lingfish
5
这个回答似乎不合理,因为'r'是来自requests.get()的对象,所以除非进行修改,否则这只会导致另一个错误。 - mikkokotila
1
这个答案没有意义。OP的错误信息并不是“连接被拒绝”,而是“名称或服务未知”。这个答案似乎假设所有的ConnectionError都是由于“连接被拒绝”引起的。 - erjiang
1
对我来说,这必须是完全正确的,由服务器设置的速率限制。我可以进行80次调用,然后这条消息就会出现在我的面前。然后经过短暂的时间,服务器又可以进行另外80次调用,循环重复。这太规律了,不可能是其他什么原因。 - demongolem

49

请按照以下方式操作,

将以下代码粘贴到 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

不用谢 :)


4
记得执行import time - Yuan Tao
9
requests有自己的代码来处理其错误和重试。 - Zulu
11
它永远不会从循环中退出。@jatin - alper
17
不建议使用 except: ... 来捕获 requestssleep() 的任何异常。应该只捕获 requests.exceptions.ConnectionError 异常和仅在发生该异常时才捕获 sleep()。或者更好的是,可以像 @Zulu 建议的那样,直接使用内置的 Retry() 类来处理。 - J. Taylor
时间,导入时间,重新获取请求 - Ashik
continueи·іиү‡дёЂдёҒеңҒзҺҮ。如жһњж‚Ёжѓій‡ҚиҮ•иҮ·ж±‚пәЊиү™е№¶дёҚзђ†жѓігЂ‚ - Domenico Spidy Tamburro

48

我遇到了类似的问题,但以下代码对我有效。

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

"verify=False"可以禁用SSL验证。可以像往常一样添加try和catch。


3
这可能是一个不错的解决方案,但前提是你信任目标网址 url - serfer2
我的救星 :) !!!! - Préliator

42

4
帮助我发现SSL是我的问题。 - Milad Yarmohammadi
同样在这里 =) 谢谢! - Rodrigo E. Principe

12

在企业环境中指定代理解决了我的问题。

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

完整错误信息为:

requests.exceptions.ConnectionError: HTTPSConnectionPool(host='www.google.com', port=80):尝试连接URL时最大重试次数已超过(由于NewConnectionError引起:':无法建立新连接:[WinError 10060]因为连接方在一段时间后没有正确响应,或者已建立的连接失败,因为连接的主机没有响应')


你好 - 我在哪里可以找到我的代理?抱歉,我对这个代理的东西还很陌生。谢谢。 - Zack
1
@Zach 如果你在公司网络中,IT支持人员将会知道。或者你可以自己查找:https://superuser.com/a/346376 - Jeremy Thompson

8

使用异常处理总是一个好习惯。它不仅有助于避免脚本意外退出,还可以帮助记录错误和信息通知。在使用Python requests时,我喜欢这样捕获异常:

    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")

这里的renewIPadress()是一个用户自定义的函数,如果IP地址被阻止,它可以更改IP地址。您可以不使用此函数。


你的解决方案很好,但是如何在Python中更改“ip-address”,你知道这方面的内容吗?如果知道,请告诉我。 - Haritsinh Gohil
1
我曾使用过一些VPN服务,如IPVanish和Hide My Ass。它们是使用open-vpn配置的,而open-vpn有一个shell命令行来更新IP地址。你可以从Python中调用shell或bash命令。通过这种方式,你可以实现它。 - Tanmoy Datta

4
为了方便后来遇到此问题的读者,我想分享一下我的经验。我的具体错误是:
Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'

事实证明,这实际上是因为我在系统上达到了最大打开文件数。这与连接失败或甚至DNS错误无关。


1
你能详细说明一下吗?你所说的“打开文件”是什么意思? - akkhil
打开文件指的是打开文件句柄。如何修复它取决于操作系统,因此只需搜索“增加最大打开文件数”和您的系统所运行的操作系统即可。 - Oded
当我尝试使用requests.post将数百个同时同步作业提交到AWS Lambda函数时,我遇到了这个问题。对于Linux和Max,我发现这个页面在提高文件的操作系统限制方面非常有用:https://wilsonmar.github.io/maximum-limits/ - Iron Pillow

2
当我编写Selenium浏览器测试脚本时,在调用JS API之前调用driver.quit()时遇到了这个错误。请记住,退出WebDriver是最后要做的事情!

1
只需 import time 并添加 :
time.sleep(6)

在for循环中的某个位置,为了避免在短时间内向服务器发送过多请求。 数字6表示:6秒钟。 从1开始测试数字,直到达到能够帮助避免问题的最小秒数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接