如何避免HTTP错误429(请求过多)python
我正在尝试用Python登录一个网站,并从几个网页上收集信息,但我遇到了以下错误:
Traceback (most recent call last): File "extract_test.py", line 43, in <module> response=br.open(v) File "/usr/local/lib/python2.7/dist-packages/mechanize/_mechanize.py", line 203, in open return self._mech_open(url, data, timeout=timeout) File "/usr/local/lib/python2.7/dist-packages/mechanize/_mechanize.py", line 255, in _mech_open raise response mechanize._response.httperror_seek_wrapper: HTTP Error 429: Unknown Response Code
我用了time.sleep()
这个方法,虽然能解决问题,但感觉这样做不太聪明,也不太可靠,有没有其他方法可以避免这个错误呢?
这是我的代码:
import mechanize
import cookielib
import re
first=("example.com/page1")
second=("example.com/page2")
third=("example.com/page3")
fourth=("example.com/page4")
## I have seven URL's I want to open
urls_list=[first,second,third,fourth]
br = mechanize.Browser()
# Cookie Jar
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)
# Browser options
br.set_handle_equiv(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)
# Log in credentials
br.open("example.com")
br.select_form(nr=0)
br["username"] = "username"
br["password"] = "password"
br.submit()
for url in urls_list:
br.open(url)
print re.findall("Some String")
7 个回答
另一种解决方法是通过使用公共VPN或Tor网络来伪装你的IP地址。这是因为服务器可能会根据IP地址来限制访问频率。
这里有一篇简短的博客文章,展示了如何将Tor与urllib2一起使用:
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,但其实很多时候,解决这些问题的方法是相似的。我们可以通过查看别人遇到的类似问题和解决方案,来找到自己的答案。
比如,有人可能在使用某个编程语言时,发现代码运行不正常。他们会把这个问题发到一个叫StackOverflow的网站上,寻求帮助。在那里,其他程序员会分享他们的经验,告诉你可能是什么原因导致了这个问题,以及如何解决它。
总之,遇到问题时,不要害怕寻求帮助,很多人都经历过类似的情况,分享他们的解决方案可以帮助你更快地找到答案。
if response.status_code == 429:
time.sleep(int(response.headers["Retry-After"]))
正如MRA所说,你不应该试图绕过一个 429 请求过多
的错误,而是应该正确处理它。根据你的使用场景,你有几种选择:
1) 让你的程序“睡一觉”。服务器通常会在响应中包含一个 Retry-after
的头信息,告诉你需要等待多少秒再重试。要注意,让程序“睡觉”可能会引发一些问题,比如在任务队列中,你应该在稍后重试任务,以便让工作者可以处理其他事情。
2) 指数退避。如果服务器没有告诉你需要等待多久,你可以在重试请求时逐渐增加等待的时间。流行的任务队列Celery就有这个功能 内置。
3) 令牌桶。如果你提前知道在特定时间内可以发送多少请求,这个方法就很有用。每次你访问API时,首先从桶里取一个令牌。这个桶会以固定的速度被重新填满。如果桶空了,你就知道需要等一等才能再次访问API。令牌桶通常是在API那一端实现的,但你也可以用它们作为代理,避免出现 429 请求过多
的错误。Celery的 速率限制功能使用了令牌桶算法。
下面是一个使用指数退避和速率限制/令牌桶的Python/Celery应用示例:
class TooManyRequests(Exception):
"""Too many requests"""
@task(
rate_limit='10/s',
autoretry_for=(ConnectTimeout, TooManyRequests,),
retry_backoff=True)
def api(*args, **kwargs):
r = requests.get('placeholder-external-api')
if r.status_code == 429:
raise TooManyRequests()
写下这段代码后,我的问题就解决了:
requests.get(link, headers = {'User-agent': 'your bot 0.1'})
之所以有效,是因为有些网站在没有提供用户代理的情况下,会返回“请求过多”(429)的错误。例如,Reddit的API只有在提供用户代理时才能正常工作。
收到状态码429并不是一个错误,这其实是另一个服务器在“好心”地告诉你,请停止发送过多请求。显然,你的请求频率太高了,服务器不愿意接受这么多请求。
你不应该试图“躲避”这个问题,或者通过伪装你的IP地址来绕过服务器的安全设置。你应该尊重服务器的回应,别发送太多请求。
如果一切设置得当,你还会收到一个“Retry-after”的头信息,和429的响应一起发来的。这个头信息会告诉你在再次发送请求之前需要等待多少秒。处理这个“问题”的正确方法是查看这个头信息,然后让你的程序暂停那么多秒。
你可以在这里找到关于状态码429的更多信息:https://www.rfc-editor.org/rfc/rfc6585#page-3