Próbuję użyć języka Python, aby zalogować się do witryny internetowej i zebrać informacje z kilku stron internetowych i otrzymuję następujący błąd:
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
Użyłem time.sleep()
i działa, ale wydaje się nieinteligentny i zawodny, czy jest jakiś inny sposób na uniknięcie tego błędu?
Oto mój kod:
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
źródło
źródło
sleep
.Odpowiedzi:
Otrzymanie statusu 429 nie jest błędem , to jest inny serwer "uprzejmie" proszący o zaprzestanie spamowania żądań. Oczywiście liczba żądań była zbyt wysoka, a serwer nie chce tego zaakceptować.
Nie powinieneś próbować tego „omijać”, a nawet próbować ominąć ustawień bezpieczeństwa serwera, próbując sfałszować swój adres IP, powinieneś po prostu uszanować odpowiedź serwera, nie wysyłając zbyt wielu żądań.
Jeśli wszystko jest poprawnie skonfigurowane, otrzymasz także nagłówek „Ponów próbę po” wraz z odpowiedzią 429. Ten nagłówek określa liczbę sekund, które należy odczekać przed wykonaniem kolejnego połączenia. Właściwym sposobem radzenia sobie z tym „problemem” jest przeczytanie tego nagłówka i uśpienie procesu na tak wiele sekund.
Więcej informacji na temat statusu 429 można znaleźć tutaj: http://tools.ietf.org/html/rfc6585#page-3
źródło
HTTPError as my_exception
jest dostępny wmy_exception.headers
, przynajmniej dla urllib2.Napisanie tego fragmentu kodu rozwiązało mój problem:
requests.get(link, headers = {'User-agent': 'your bot 0.1'})
źródło
Jak powiedział MRA, nie powinieneś próbować unikać,
429 Too Many Requests
ale zamiast tego odpowiednio sobie z tym poradzić. Masz kilka opcji w zależności od przypadku użycia:1) Uśpij swój proces . Serwer zwykle zawiera
Retry-after
nagłówek w odpowiedzi z liczbą sekund, które należy odczekać przed ponowną próbą. Należy pamiętać, że uśpienie procesu może powodować problemy, np. W kolejce zadań, w której zamiast tego należy wykonać zadanie ponownie później, aby zwolnić pracownika do innych rzeczy.2) Wykładnicze wycofanie . Jeśli serwer nie poinformuje Cię, jak długo masz czekać, możesz ponowić żądanie, używając coraz dłuższych przerw. Popularna kolejka zadań Seler ma tę funkcję wbudowaną bezpośrednio .
3) Wiadro z tokenami . Ta technika jest przydatna, jeśli wiesz z góry, ile żądań jesteś w stanie złożyć w danym czasie. Za każdym razem, gdy uzyskujesz dostęp do interfejsu API, najpierw pobierasz token z zasobnika. Wiaderko jest uzupełniane w stałym tempie. Jeśli zasobnik jest pusty, wiesz, że będziesz musiał poczekać przed ponownym naciśnięciem interfejsu API. Zasobniki tokenów są zwykle implementowane na drugim końcu (API), ale można ich również używać jako serwera proxy, aby uniknąć kiedykolwiek uzyskania pliku
429 Too Many Requests
. Funkcja rate_limit selera używa algorytmu zasobnika tokenów.Oto przykład aplikacji w języku Python / Celery używającej wykładniczego wycofywania i zasobnika ograniczającego szybkość / tokenów:
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()
źródło
Innym obejściem byłoby sfałszowanie swojego adresu IP za pomocą jakiejś publicznej sieci VPN lub sieci Tor. Byłoby to przy założeniu ograniczenia szybkości na serwerze na poziomie IP.
Istnieje krótki post na blogu demonstrujący sposób używania tor wraz z urllib2:
http://blog.flip-edesign.com/?p=119
źródło
if response.status_code == 429: time.sleep(int(response.headers["Retry-After"]))
źródło
Znalazłem fajne obejście blokowania adresów IP podczas skrobania witryn. Pozwala uruchamiać Scrapera w nieskończoność, uruchamiając go z Google App Engine i automatycznie wdrażając ponownie, gdy otrzymasz 429.
Przeczytaj ten artykuł
źródło