Estoy tratando de usar Python para iniciar sesión en un sitio web y recopilar información de varias páginas web y obtengo el siguiente error:
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
Lo usé time.sleep()
y funciona, pero parece poco inteligente y poco confiable, ¿hay alguna otra forma de esquivar 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")
python
http
mechanize
http-status-code-429
Aous1000
fuente
fuente
sleep
.Respuestas:
Recibir un estado 429 no es un error , es el otro servidor "amablemente" pidiéndole que deje de enviar solicitudes de spam. Obviamente, su tasa de solicitudes ha sido demasiado alta y el servidor no está dispuesto a aceptar esto.
No debe tratar de "esquivar" esto, o incluso tratar de eludir la configuración de seguridad del servidor tratando de 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" junto con la respuesta 429. Este encabezado especifica la cantidad de segundos que debe esperar antes de realizar 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
fuente
HTTPError as my_exception
, está disponiblemy_exception.headers
, al menos para urllib2.Escribir este código solucionó mi problema:
requests.get(link, headers = {'User-agent': 'your bot 0.1'})
fuente
Como dijo MRA, no debe intentar esquivar un,
429 Too Many Requests
sino manejarlo en consecuencia. Tiene varias opciones según su caso de uso:1) Duerme tu proceso . El servidor generalmente incluye un
Retry-after
encabezado en la respuesta con la cantidad de segundos que se supone que debe esperar antes de volver a intentarlo. Tenga en cuenta que dormir un proceso puede causar problemas, por ejemplo, en una cola de tareas, donde debería volver a intentar la tarea en un momento posterior para liberar al trabajador para otras cosas.2) Retroceso exponencial . Si el servidor no le dice cuánto tiempo debe esperar, puede volver a intentar su solicitud utilizando pausas cada vez mayores en el medio. La popular cola de tareas Apio tiene esta función incorporada .
3) Cubo de fichas . Esta técnica es útil si sabe de antemano cuántas solicitudes puede realizar en un tiempo determinado. Cada vez que accede a la API, primero obtiene un token del depósito. El cubo se rellena a un ritmo constante. Si el depósito está vacío, sabrá que tendrá que esperar antes de volver a acceder a la API. Los depósitos de tokens generalmente se implementan en el otro extremo (la API), pero también puede usarlos como proxy para evitar obtener un
429 Too Many Requests
. La función rate_limit de Celery utiliza un algoritmo de cubeta de tokens.A continuación, se muestra un ejemplo de una aplicación Python / Celery que utiliza un retroceso exponencial y un depósito de token / limitador 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()
fuente
Otra solución sería falsificar su IP utilizando algún tipo de red VPN pública 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
fuente
if response.status_code == 429: time.sleep(int(response.headers["Retry-After"]))
fuente
Descubrí una buena solución para el bloqueo de IP al raspar sitios. Te permite ejecutar un Scraper indefinidamente ejecutándolo desde Google App Engine y volviéndolo a implementar automáticamente cuando obtienes un 429.
Mira este artículo
fuente