Как избежать ошибки HTTP 429 (Too Many Requests) 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")
4 ответа
Получение статуса 429 - это не ошибка, это другой сервер, который "любезно" просит вас прекратить рассылку спама. Очевидно, что ваш уровень запросов был слишком высок, и сервер не желает принимать это.
Вы не должны пытаться "уклониться" от этого или даже пытаться обойти настройки безопасности сервера, пытаясь подделать ваш IP, вы должны просто уважать ответ сервера, не посылая слишком много запросов.
Если все настроено правильно, вы также получите заголовок "Retry-after" вместе с ответом 429. Этот заголовок указывает количество секунд, которое вы должны подождать, прежде чем сделать еще один вызов. Правильный способ справиться с этой "проблемой" - прочитать этот заголовок и приостановить процесс на столько секунд.
Вы можете найти больше информации о статусе 429 здесь: http://tools.ietf.org/html/rfc6585
Написание этого фрагмента кода решило мою проблему:
requests.get(link, headers = {'User-agent': 'your bot 0.1'})
Как сказал MRA, вы не должны пытаться увернуться от 429 Too Many Requests
но вместо этого обращаться с этим соответственно. У вас есть несколько вариантов в зависимости от вашего варианта использования:
1) Спи свой процесс. Сервер обычно включает в себя Retry-after
заголовок в ответе с количеством секунд, которые вы должны подождать, прежде чем повторить попытку. Имейте в виду, что спящий процесс может вызвать проблемы, например, в очереди задач, где вы должны вместо этого повторить задачу позднее, чтобы освободить работника для других целей.
2) Экспоненциальный откат. Если сервер не сообщает вам, как долго ждать, вы можете повторить запрос, увеличивая паузы между ними. Популярная очередь задач Celery имеет встроенную функцию.
3) Ведро с жетонами. Этот метод полезен, если вы заранее знаете, сколько запросов вы можете сделать за данный период времени. Каждый раз, когда вы получаете доступ к API, вы сначала получаете токен из корзины. Ведро наполняется с постоянной скоростью. Если корзина пуста, вы знаете, что вам придется подождать, прежде чем снова использовать API. Корзины токенов обычно реализуются на другом конце (API), но вы также можете использовать их в качестве прокси, чтобы избежать получения 429 Too Many Requests
, Функция rate_limit в 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()
if response.status_code == 429:
time.sleep(int(response.headers["Retry-After"]))
Другим обходным решением может быть подмена вашего IP-адреса с помощью какой-либо сети Public VPN или сети Tor. Это будет предполагать ограничение скорости на сервере на уровне IP.
Есть краткое сообщение в блоге, демонстрирующее способ использования tor вместе с urllib2:
Я нашел хороший способ обхода блокировки IP-адресов при парсинге сайтов. Он позволяет вам запускать Scraper на неопределенный срок, запустив его из Google App Engine и автоматически повторно развернув, когда вы получите 429.
Прочтите эту статью
Во многих случаях продолжать собирать данные с веб-сайта, даже когда сервер просит вас не делать этого, неэтично. Однако в тех случаях, когда это не так, вы можете использовать список общедоступных прокси, чтобы очистить веб-сайт с множеством разных IP-адресов.