如何避免HTTP错误429(Too Many Requests)python

时间:2014-04-01 12:35:42

标签: python http mechanize http-status-code-429

我正在尝试使用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 个答案:

答案 0 :(得分:114)

接收状态429 不是错误,另一个服务器“善意地”要求您停止发送垃圾邮件请求。显然,您的请求率太高,服务器也不愿意接受。

你不应该试图“躲避”这个,甚至试图通过欺骗你的IP来绕过服务器安全设置,你应该通过不发送太多请求来尊重服务器的答案。

如果一切设置正确,您还会收到“Retry-after”标题以及429响应。此标头指定在进行另一次呼叫之前应等待的秒数。处理这个“问题”的正确方法是读取这个标题并让你的过程睡了好几秒钟。

您可以在此处找到有关状态429的更多信息:http://tools.ietf.org/html/rfc6585#page-3

答案 1 :(得分:21)

编写这段代码解决了我的问题:

requests.get(link, headers = {'User-agent': 'your bot 0.1'})

答案 2 :(得分:13)

正如MRA所说,你不应该试图躲避429 Too Many Requests,而是相应地处理它。根据您的使用情况,您有多种选择:

1)睡眠过程。服务器通常在响应中包含Retry-after标头,其中包含您在重试之前应等待的秒数。请记住,睡眠过程可能会导致问题,例如:在任务队列中,您应该在以后重新尝试任务以释放工作人员以进行其他操作。

2) Exponential backoff 。如果服务器没有告诉您等待多长时间,则可以使用之间增加的暂停来重试您的请求。流行的任务队列Celery具有此功能built right-in

3) Token bucket 。如果您事先知道在给定时间内能够进行多少次请求,则此技术非常有用。每次访问API时,首先从存储桶中获取令牌。铲斗以恒定速率重新填充。如果存储桶为空,您知道在再次访问API之前必须等待。令牌桶通常在另一端(API)实现,但您也可以将它们用作代理,以避免获得429 Too Many Requests。 Celery的rate_limit功能使用令牌桶算法。

以下是使用指数退避和速率限制/令牌桶的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()

答案 3 :(得分:7)

另一种解决方法是使用某种公共VPN或Tor网络来欺骗您的IP。这将假设IP级别的服务器上的速率限制。

有一篇简短的博客文章,展示了使用tor和urllib2的方法:

http://blog.flip-edesign.com/?p=119

答案 4 :(得分:4)

if response.status_code == 429:
  time.sleep(int(response.headers["Retry-After"]))

答案 5 :(得分:2)

在抓取网站时,我发现了一个很好的 IP阻止方法。它可让您通过从Google App Engine运行Scraper来无限期运行它,并在获得429时自动重新部署它。

签出this article

答案 6 :(得分:0)

在许多情况下,即使服务器要求您不继续从网站上抓取数据也是不道德的。但是,如果不是这样,则可以利用公共代理服务器列表来抓取具有许多不同IP地址的网站。