如何避免HTTP错误429(太多请求)python

如何避免HTTP错误429(太多请求)python,python,http,mechanize,http-status-code-429,Python,Http,Mechanize,Http Status Code 429,我试图使用Python登录到一个网站,并从多个网页收集信息,但出现以下错误: 另一个解决方法是使用某种公共VPN或Tor网络欺骗您的IP。这将假定服务器上的速率限制为IP级别 有一篇简短的博客文章演示了如何将tor与urllib2一起使用: 收到状态429不是错误,而是另一台服务器“善意地”要求您停止发送垃圾邮件请求。显然,您的请求率太高,服务器不愿意接受 你不应该试图“回避”这一点,甚至试图通过欺骗你的IP来规避服务器安全设置,你应该尊重服务器的回答,不要发送太多请求 如果一切设置正确,您还将

我试图使用Python登录到一个网站,并从多个网页收集信息,但出现以下错误:


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

有一篇简短的博客文章演示了如何将tor与urllib2一起使用:

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

你不应该试图“回避”这一点,甚至试图通过欺骗你的IP来规避服务器安全设置,你应该尊重服务器的回答,不要发送太多请求

如果一切设置正确,您还将收到一个“Retry after”(重试后)标题以及429响应。此标题指定在进行另一次呼叫之前应等待的秒数。处理此“问题”的正确方法是读取此标题并使进程休眠数秒


您可以在此处找到有关状态429的更多信息:

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

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

正如MRA所说,您不应该试图回避过多的
429请求,而应该相应地处理它。根据您的用例,您有几个选项:

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

2) 。如果服务器没有告诉您等待多长时间,您可以在其间增加暂停次数来重试请求。流行的任务队列芹菜具有此功能

3) 。如果您事先知道在给定时间内可以发出多少请求,那么此技术非常有用。每次访问API时,首先从bucket中获取一个令牌。铲斗以恒定速率重新加注。如果bucket是空的,您知道在再次访问API之前必须等待。令牌桶通常在另一端(API)实现,但您也可以将其用作代理,以避免收到过多的请求。芹菜的功能使用令牌桶算法

下面是一个使用指数退避和速率限制/令牌桶的Python/Cellery应用程序示例:

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

我发现了一个不错的解决方法,可以在抓取站点时阻止IP。它可以让你无限期地运行刮板,通过谷歌应用程序引擎运行刮板,当你得到429时自动重新部署刮板


检查一下

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

没有办法,这是服务器端的强制措施,用于跟踪您发出的请求/时间单位。如果你超过这个单位,你将被暂时阻止。有些服务器在标头中发送此信息,但这种情况很少。检查从服务器收到的标题,使用可用信息。。如果没有,请检查您可以以多快的速度敲打而不被抓到,并使用
睡眠
。好吧,从来没有人说过所有web服务器都配置正确。此外,由于大多数速率限制器都是通过IP识别访问者,因此在动态共享IP的情况下,这可能会导致问题。如果您继续接收状态429,尽管您确信您没有发送太多的请求,您可能会考虑与站点管理员联系。谢谢您提到“重试后”标题。我希望通过一个代码示例来了解如何获取该值(我使用urllib来操作机械化,在这两种情况下,我都不认为引发的异常中包含头)@MacFreek我没有准备任何特定的Python代码示例,但是我假设一些关于如何检索响应头的例子可以从这个问题的答案中得到:谢谢@MRA。我发现标题也可以在异常中使用:在捕捉到
HTTPError作为my_exception
后,它可以在
my_exception.headers
中使用,至少对于urllib2是这样。这个答案被否决了,但如果用户代理因他人滥用而被禁止,一些网站会自动返回错误代码429。如果即使您只发送了几个请求,但仍收到错误代码429,请尝试将用户代理设置为其他内容。还想补充一点,除非发送了用户代理,否则某些站点显然会拒绝请求,并且您可能会收到无数其他响应:503/403/某些通用索引页。您可以确认这一点。只是尝试将python与reddit进行接口,而没有设置用户代理,我总是得到错误代码429。您可以添加一些解释吗?您在哪里“编写这段代码”?这个解决方案需要更多的细节。这就是为什么我总是要求API的用户注册密钥以发出请求。这样我就可以通过密钥而不是IP来限制请求。注册另一个密钥将是获得更高限制的唯一途径。哈哈哇。。。用谷歌刮谷歌。然后在谷歌阻止的时候改变你的谷歌IP。这是一个简单的实现方式。“重试后”可以是时间戳,而不是秒数。看见
requests.get(link, headers = {'User-agent': 'your bot 0.1'})
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()
if response.status_code == 429:
  time.sleep(int(response.headers["Retry-After"]))