Cómo evitar el error HTTP 429 (demasiadas solicitudes) python

Estoy tratando de usar Python para iniciar sesión en un sitio web y recostackr información de varias páginas web y aparece el siguiente error:

Traceback (most recent call last): File "extract_test.py", line 43, in  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() y funciona, pero parece poco inteligente y poco confiable, ¿hay alguna otra forma de evitar este error?

Aquí está mi código:

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

Recibir un estado 429 no es un error , es el otro servidor “amablemente” pidiéndole que detenga las solicitudes de spam. Obviamente, su tasa de solicitudes ha sido demasiado alta y el servidor no está dispuesto a aceptar esto.

No debe intentar “esquivar” esto, o incluso tratar de eludir la configuración de seguridad del servidor intentando falsificar su IP, simplemente debe respetar la respuesta del servidor al no enviar demasiadas solicitudes.

Si todo está configurado correctamente, también habrá recibido un encabezado “Reintentar después de” junto con la respuesta 429. Este encabezado especifica la cantidad de segundos que debe esperar antes de hacer otra llamada. La forma correcta de lidiar con este “problema” es leer este encabezado y suspender el proceso durante tantos segundos.

Puede encontrar más información sobre el estado 429 aquí: http://tools.ietf.org/html/rfc6585#page-3

Escribir este fragmento de código solucionó mi problema:

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

Como dijo MRA, no debes tratar de esquivar un 429 Too Many Requests sino manejarlo en consecuencia. Tienes varias opciones dependiendo de tu caso de uso:

1) Duerme tu proceso . El servidor generalmente incluye un encabezado Retry-after de la respuesta con la cantidad de segundos que se espera que espere antes de volver a intentarlo. Tenga en cuenta que suspender un proceso puede causar problemas, por ejemplo, en una cola de tareas, donde debería volver a intentar la tarea más adelante para liberar al trabajador de otras cosas.

2) retroceso exponencial . Si el servidor no le dice cuánto tiempo debe esperar, puede reintentar su solicitud utilizando pausas cada vez mayores. La popular cola de tareas Celery tiene esta característica incorporada .

3) Cubo de fichas . Esta técnica es útil si sabe de antemano cuántas solicitudes puede realizar en un momento determinado. Cada vez que accede a la API, primero obtiene un token del depósito. El cubo se rellena a una velocidad constante. Si el depósito está vacío, sabrá que tendrá que esperar antes de volver a golpear la API. Los cubos de fichas generalmente se implementan en el otro extremo (la API), pero también puede usarlos como un proxy para evitar obtener un 429 Too Many Requests . La característica rate_limit de Celery utiliza un algoritmo de cubo de token.

Este es un ejemplo de una aplicación de Python / Celery que utiliza un retroceso exponencial y un grupo de fichas / limitadores de velocidad:

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

Otra solución sería falsificar su IP utilizando algún tipo de red pública VPN o Tor. Esto supondría la limitación de velocidad en el servidor a nivel de IP.

Hay una breve publicación en el blog que demuestra una forma de usar tor junto con urllib2:

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