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

Aou*_*000 75 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
Run Code Online (Sandbox Code Playgroud)

我用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")
Run Code Online (Sandbox Code Playgroud)

MRA*_*MRA 131

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

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

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

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

  • 好吧,没有人说所有的Web服务器都配置正确.此外,由于大多数速率限制器都通过IP识别访问者,因此在动态共享IP的情况下可能会出现问题.如果您仍然保持接收状态429,但您确信自己没有发送太多请求,则可以考虑联系该网站的管理员. (17认同)
  • 感谢您提到“重试后”标题。我希望有一个代码示例来查看如何获取该值(我使用 urllib,以进行 OP 机械化,在任何一种情况下,我都不认为标头包含在引发的异常中) (2认同)

tad*_*123 25

编写这段代码修复了我的问题:

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

  • 此答案被低估了,但如果用户代理因其他人的滥用而被禁止,则某些网站会自动返回错误代码429.即使您只发送了一些请求,如果收到错误代码429,请尝试将用户代理设置为其他内容. (16认同)
  • 还想补充一点,除非发送用户代理,否则有些网站会明确拒绝请求,并且您可能会得到无数其他响应:503/403 /一些通用索引页面. (5认同)
  • 您可以添加一些解释吗? (4认同)
  • 可以确认这一点。只是尝试将 python 与 reddit 连接起来,而没有设置用户代理,我总是收到错误代码 429。 (2认同)

psa*_*iko 17

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

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

2)指数退避.如果服务器没有告诉您等待多长时间,则可以使用之间增加的暂停来重试您的请求.流行的任务队列Celery 内置了这个功能.

3)令牌桶.如果您事先知道在给定时间内能够进行多少次请求,则此技术非常有用.每次访问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()
Run Code Online (Sandbox Code Playgroud)


小智 11

if response.status_code == 429:
  time.sleep(int(response.headers["Retry-After"]))
Run Code Online (Sandbox Code Playgroud)

  • 这可能是一个简单的示例,但它指出了如何处理速率限制的一般形式 - 检查 429 状态,使用标头中的信息进行响应。这对我很有用。 (4认同)
  • 简单实现的方法。“重试时间”可以是时间戳而不是秒数。请参阅 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After (3认同)

Gau*_*wal 8

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

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

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

  • 这就是为什么我总是要求我的API用户注册一个密钥来发出请求.这样我可以通过密钥而不是IP来限制请求.注册另一个密钥是获得更高限制的唯一方法. (5认同)

Jua*_*gle 7

我发现了一个很好的解决方法来在抓取站点时阻止 IP。它允许您通过从 Google App Engine 运行 Scraper 并在收到 429 时自动重新部署它来无限期地运行 Scraper。

看看这篇文章

  • 哈哈哇...用Google来抓取Google。然后在 Google 阻止时更改您的 Google IP。 (2认同)