Как избежать ошибки HTTP 429 (слишком много запросов) python


94

Я пытаюсь использовать 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")

6
Обойти это невозможно, это принудительное применение на стороне сервера, отслеживающее, сколько запросов / единиц времени вы делаете. Если вы превысите эту единицу, вы будете временно заблокированы. Некоторые серверы отправляют эту информацию в заголовке, но такие случаи редки. Проверьте заголовки, полученные от сервера, используйте имеющуюся информацию. Если нет, проверьте, насколько быстро вы можете забивать, не попадаясь, и используйте файл sleep.
— Torxed 01

Ответы:


158

Получение статуса 429 не является ошибкой , это другой сервер «любезно» просит вас прекратить рассылать спам-запросы. Очевидно, ваша скорость запросов была слишком высокой, и сервер не желает принимать это.

Вы не должны пытаться «уклоняться» от этого или даже пытаться обойти настройки безопасности сервера, пытаясь подделать ваш IP-адрес, вы должны просто уважать ответ сервера, не посылая слишком много запросов.

Если все настроено правильно, вы также получите заголовок «Retry-after» вместе с ответом 429. Этот заголовок определяет количество секунд, которое вы должны подождать, прежде чем сделать следующий звонок. Правильный способ справиться с этой «проблемой» - прочитать этот заголовок и приостановить ваш процесс на столько секунд.

Дополнительную информацию о статусе 429 можно найти здесь: http://tools.ietf.org/html/rfc6585#page-3.


23
Ну, никто никогда не говорил, что все веб-серверы настроены правильно. Кроме того, поскольку большинство ограничителей скорости идентифицируют посетителей по IP-адресу, это может привести к проблемам в сценарии, когда IP-адреса используются динамически. Если вы продолжаете получать статус 429, хотя уверены, что не отправили слишком много запросов, вы можете подумать о том, чтобы связаться с администратором сайта.
— MRA

2
Благодарим за упоминание заголовка «Повторить попытку». Мне бы хотелось увидеть пример кода, чтобы увидеть, как получить это значение (я использовал urllib для механизации OP, в любом случае я не думаю, что заголовки включены в поднятое исключение)
— MacFreek

@MacFreek У меня нет готовых конкретных примеров кода Python, но я предполагаю, что некоторые примеры того, как получать заголовки ответов в целом, можно взять из ответов на этот вопрос: stackoverflow.com/q/843392
— MRA

Спасибо @MRA. Я обнаружил, что заголовки также доступны в исключении: после перехвата HTTPError as my_exceptionони доступны my_exception.headers, по крайней мере, для urllib2.
— MacFreek

38

Написание этого фрагмента кода устранило мою проблему:

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


26
Этот ответ отвергнут, но некоторые сайты автоматически возвращают код ошибки 429, если пользовательский агент заблокирован из-за злоупотреблений со стороны других людей. Если вы получаете код ошибки 429, даже если вы отправили всего несколько запросов, попробуйте настроить пользовательский агент на что-то другое.
— Ferry Boender 01

7
Также хотелось бы добавить, что некоторые сайты просто отклоняют запросы, если не отправлен пользовательский агент, и вы можете получить множество других ответов: 503/403 / некоторая общая индексная страница.
— user3791372

1
Могу подтвердить это. Просто пытаясь связать python с Reddit и без настройки пользовательского агента, я всегда получал код ошибки 429.
— Karrq

1
не могли бы вы добавить некоторые пояснения?
— Tokci

Где вы «пишете этот кусок кода»? Это решение требует более подробной информации.
— Джо Маклин,

29

Как сказал MRA, вы не должны пытаться увернуться от A, 429 Too Many Requestsа вместо этого обращайтесь с ним соответствующим образом. У вас есть несколько вариантов в зависимости от вашего варианта использования:

1) Спите свой процесс . Сервер обычно включает Retry-afterзаголовок в ответ с количеством секунд, которое вы должны ждать перед повторной попыткой. Имейте в виду, что спящий процесс может вызвать проблемы, например, в очереди задач, где вы должны вместо этого повторить задачу позже, чтобы освободить воркера для других дел.

2) Экспоненциальная отсрочка . Если сервер не сообщает вам, сколько ждать, вы можете повторить запрос, увеличивая паузы между ними. Популярная очередь задач Celery имеет эту встроенную функцию .

3) Жетонное ведро . Этот метод полезен, если вы заранее знаете, сколько запросов вы можете сделать за определенное время. Каждый раз, когда вы обращаетесь к API, вы сначала извлекаете токен из корзины. Ведро наполняется с постоянной скоростью. Если корзина пуста, вы знаете, что вам придется подождать, прежде чем снова обращаться к API. Блоки токенов обычно реализуются на другом конце (API), но вы также можете использовать их в качестве прокси, чтобы никогда не получить файл 429 Too Many Requests. Функция 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()

9

Другой обходной путь - подделка вашего IP-адреса с помощью какой-либо общедоступной VPN или сети Tor. Это предполагает ограничение скорости на сервере на уровне IP.

В блоге есть краткое сообщение, демонстрирующее способ использования tor вместе с urllib2:

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


8
Вот почему я всегда требую, чтобы пользователи моего API регистрировались для получения ключа для выполнения запросов. Таким образом я могу ограничивать запросы по ключу, а не по IP. Регистрация для другого ключа - единственный способ получить более высокий лимит.
— Mnebuerquo


1

Я нашел хороший способ обхода блокировки IP-адресов при парсинге сайтов. Он позволяет вам запускать Scraper на неопределенный срок, запустив его из Google App Engine и автоматически повторно развернув, когда вы получите 429.

Прочтите эту статью


Ха-ха ... используя Google для очистки Google. А затем изменить свой IP-адрес Google, когда Google его заблокирует.
— sam1370
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.