Jak unikać captcha podczas scrapingu (bez łamania zasad)
Większość captcha podczas scrapingu to reakcja na ruch, który wygląda na zautomatyzowany. Najtańszy sposób, by sobie z nimi poradzić, to po prostu ich nie wywoływać. Oznacza to szukanie legalnego źródła danych, sprawdzenie, co zasady serwisu pozwalają robić, wysyłanie mniejszej liczby żądań i wolniej, oraz niepobieranie tej samej strony dwa razy. Rozwiązywanie captcha to awaryjne wyjście dla przypadków, których nie da się uniknąć, a nie plan.
Najpierw sprawdź oficjalne API lub kanał danych
Wiele serwisów, z których się scrapuje, oferuje już sposób na uzyskanie tych samych danych bez captcha: publiczne API, eksport danych, kanał RSS lub sitemap albo program partnerski. Oficjalne źródło jest bardziej niezawodne, rzadziej zmienia się bez zapowiedzi i daje właścicielowi serwisu wpływ na to, jak z niego korzystasz. Szukaj:
- sekcji dla deweloperów lub API w stopce strony,
sitemap.xmlz listą stron,- linków RSS lub Atom w
<head>strony, - strony "data" lub "download" z eksportami zbiorczymi.
Jeśli któreś z tych rozwiązań pokrywa Twoją potrzebę, użyj go. Unikniesz większości captcha, po prostu nie pobierając HTML.
Szanuj robots.txt i wymagane opóźnienie
robots.txt mówi, które ścieżki automatyczni klienci mogą pobierać i czasem jak długo czekać między żądaniami. Standardowa biblioteka Pythona potrafi go odczytać za Ciebie:
import time
from urllib.robotparser import RobotFileParser
import requests
USER_AGENT = "ExampleBot/1.0 (+https://example.com/bot)"
parser = RobotFileParser()
parser.set_url("https://example.com/robots.txt")
parser.read()
delay = parser.crawl_delay(USER_AGENT) or 5 # wróć do ostrożnej wartości 5 sekund
urls = [
"https://example.com/products?page=1",
"https://example.com/products?page=2",
]
last_request = 0.0
for url in urls:
if not parser.can_fetch(USER_AGENT, url):
print("skipped by robots.txt:", url)
continue
wait = delay - (time.monotonic() - last_request)
if wait > 0:
time.sleep(wait)
resp = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=30)
last_request = time.monotonic()
print(url, resp.status_code)
Jeśli robots.txt zabrania dostępu do ścieżki, uczciwą odpowiedzią jest zostawić ją w spokoju lub zapytać właściciela. Obchodzenie tego przez przeglądarkę nie zmienia tego, o co poprosił serwis.
Zwolnij i rozłóż żądania w czasie
Stałe, umiarkowane tempo rzadko wywołuje wyzwanie, podczas gdy seria żądań prawie zawsze to robi. Kilka nawyków robi dużą różnicę:
- Ustal jedno tempo żądań dla każdego serwisu i trzymaj się go, zamiast działać z pełną prędkością.
- Dodaj losowe odchylenie czasu, aby odstępy nie były idealnie regularne.
- Zatrzymaj się i odczekaj chwilę, gdy zobaczysz kod 429 lub stronę captcha.
- Uruchamiaj zadania poza godzinami szczytu, jeśli obciążenie serwisu jest problemem.
Cache'uj i nie pobieraj ponownie
Każde żądanie, którego nie wykonasz, to żądanie, którego serwis nie musi obsłużyć. Zapisuj pobrane strony z datą i hashem treści, a ponownie pobieraj tylko wtedy, gdy zawartość prawdopodobnie się zmieniła. Żądania warunkowe z nagłówkami If-Modified-Since lub ETag pozwalają serwerowi odpowiedzieć tanio "nie zmieniono", jeśli je obsługuje.
Używaj sesji i zwykłych nagłówków
Sesja, która zachowuje ciasteczka między żądaniami, zachowuje się bardziej jak odwiedzający niż skrypt startujący od zera za każdym razem. Używaj requests.Session() dla każdego serwisu i wysyłaj wyraźny, uczciwy User-Agent, który nazywa Twojego bota i zawiera kontakt. Nie podszywaj się pod przeglądarkę, by obejść zasadę. Jeśli serwis wymaga JavaScriptu, aby pokazać treść, użyj narzędzia przeglądarkowego dla tych stron i zachowaj te same limity tempa.
Gdy captcha mimo to się pojawia
Niektóre serwisy pokażą captcha bez względu na to, jak ostrożnie się zachowujesz. Wykrywaj to w kodzie i zatrzymuj to zadanie zamiast uderzać w stronę raz za razem. Wykrywanie i opcjonalne rozwiązywanie PopularCaptcha opisano w artykule captcha przy web scrapingu.
Zaplanuj crawl przed startem
Crawl, który pobiera wszystko każdego dnia, to najłatwiejszy sposób na wywołanie captcha. Najpierw zaplanuj pracę:
- Ustal priorytety. Zdecyduj, które strony zmieniają się często, a które rzadko. Crawluj częste często, a resztę rzadko.
- Wykorzystaj daty w sitemapie. Wiele sitemap zawiera wartość
lastmod. Pomijaj adresy, które nie zmieniły się od Twojej ostatniej wizyty. - Crawluj przyrostowo. Zapisuj ostatnie udane pobranie dla każdego adresu i wznawiaj od tego miejsca, zamiast zaczynać od pierwszej strony po awarii.
- Rozkładaj obciążenie. Podziel dużą listę na partie i uruchamiaj je w ciągu dnia, a nie wszystkie naraz.
Taki plan zmniejsza liczbę żądań, a to największa dźwignia, jaką masz.
Zapisz plan jako krótki plik konfiguracyjny lub tabelę: serwisy, sekcje, interwał odświeżania i dzienny budżet żądań dla każdego z nich. Gdy budżet się wyczerpie, zadanie czeka do następnego okna. Traktowanie budżetu jako twardego limitu, a nie wskazówki, to to, co nie pozwala crawlerowi dryfować w stronę wzorca ruchu, który wywołuje captcha. Przeglądaj budżet co kilka tygodni, bo serwis, który rośnie, może też generować więcej ruchu, a to, co było grzeczne w zeszłym kwartale, dziś może nie być.
Scrapuj odpowiedzialnie
- Sprawdź
robots.txti regulamin przed startem i stosuj się do tego, co mówią. - Utrzymuj niskie tempo żądań i zatrzymuj się, gdy serwis sygnalizuje, że ma problemy.
- Nie zbieraj danych osobowych, których nie masz powodu przechowywać, i usuwaj je, gdy przestaną być potrzebne.
- Nie publikuj ponownie treści chronionych prawem autorskim na masową skalę. Używaj danych do analizy, porównań lub własnego produktu i w odpowiednich przypadkach podawaj źródło.
- Skontaktuj się z właścicielem serwisu, jeśli potrzebujesz większej ilości danych. Może zaoferować kanał danych.