Większość scraperów pada, zanim zostanie odczytany chociaż jeden header.
Serwer patrzy na handshake TLS (kolejność zestawów szyfrów, kolejność rozszerzeń, preferencje krzywych) i decyduje, czy jesteś przeglądarką, czy biblioteką kliencką, która ją udaje. Python requests, net/http od Go, zwykły curl: wszystkie przekazują charakterystyczny fingerprint w momencie przywitania. Strony, które o to dbają (Datadome, Akamai, Imperva, zarządzana część Cloudflare), zrywają połączenie lub serwują challenge page, zanim Twój User-Agent zacznie mieć jakiekolwiek znaczenie.
To właśnie rozwiązuje unblocker: true na platformie FourA. W zeszłym miesiącu dopracowaliśmy elementy, które sprawiają, że działa to niezawodnie.
Co nowego
unblocker: true to pojedyncza flaga przy każdym wywołaniu /api/single. Włącz ją, a zrobimy trzy rzeczy: wstrzykniemy zestaw headerów przeglądarki, wyślemy request przez curl-impersonate z fingerprintem TLS prawdziwej przeglądarki i zdekompresujemy wszystko, co zwróci serwer (gzip, brotli, deflate). Dwie pierwsze funkcje były dostępne od wersji beta. Trzecia (automatyczna dekompresja brotli) weszła 25 marca, a prace nad przypinaniem wersji przeglądarki wylądowały dzień później, aby utrzymać headery i TLS w pełnej synchronizacji.
Jak to działa
Oto jak wygląda request:
curl -X POST "https://api.foura.ai/api/single" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"url": "https://example.com/products",
"method": "GET",
"unblocker": true
}'
Pod spodem działają trzy warstwy.
Wstrzykiwanie headerów. Ustawiamy pełny pakiet headerów przeglądarki: User-Agent, Sec-Ch-Ua, Sec-Ch-Ua-Platform, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Accept, Accept-Language i Accept-Encoding. Kolejność ma znaczenie. Prawdziwe przeglądarki wysyłają je w określonej sekwencji, a biblioteki detekcyjne to sprawdzają.
Fingerprint TLS. curl-impersonate 0.8.2 kompiluje libcurl z BoringSSL i zmienia kolejność rozszerzeń TLS, aby pasowała do tego, co wersja docelowej przeglądarki faktycznie wysyła po sieci. Twoje hashe JA3 i JA4 będą identyczne z sesją prawdziwej przeglądarki. Standardowy curl, Python requests i net/http od Go generują fingerprinty, które na chronionej infrastrukturze są automatycznie oznaczane jako podejrzane w ciągu milisekund.
Automatyczna dekompresja. Gdy unblocker jest włączony, ustawiamy Accept-Encoding na gzip, deflate, br i pozwalamy libcurl rozpakować body. Otrzymujesz z powrotem zdekodowany ciąg znaków (lub Buffer, jeśli przekażesz returnBuffer: true). Bez ręcznej obsługi brotli, bez niezgodności między headerami a body, gdy strona wybierze deflate zamiast gzip.
Dlaczego przypinanie wersji ma znaczenie
Fingerprinty TLS są powiązane z konkretną wersją. Kolejność szyfrów w przeglądarce w tym miesiącu różni się od tej z zeszłego miesiąca, a strona, która dokładnie analizuje fingerprinty, zauważy tę różnicę. curl-impersonate dostarcza profile dla konkretnych kompilacji przeglądarek, a my przypisujemy nasz binarny plik prawdziwej przeglądarki do wersji, w którą celuje obecnie curl-impersonate. Headery, obiekty navigator i TLS zgłaszają tę samą wersję.
Jeśli brzmi to jak upierdliwa robota, to dlatego, że tak jest. Nadzialiśmy się na niedopasowanie podczas marcowej migracji monorepo, kiedy przeglądarka automatycznie się zaktualizowała, a headery rozjechały się z curl-impersonate. Rozwiązaniem były dwa commity: przypięcie pliku binarnego przeglądarki i zasada, by nigdy nie ufać menedżerowi pakietów w kwestii ich synchronizacji.
Wpływ
W wewnętrznych testach na mocno zabezpieczonych celach (finanse, podróże, chroniony e-commerce), różnica między unblocker: false a unblocker: true to różnica między challenge page a statusem 200. Zwykły curl uderzający w zarządzany Cloudflare od razu trafia na 403. Ten sam URL z unblocker: true przechodzi bez problemu, ponieważ TLS hello wygląda jak handshake prawdziwej przeglądarki.
Jednak w przypadku stron, które nie sprawdzają fingerprintów (większość publicznych API, starsze szablony CMS, wszystko, co jest ograniczone tylko przez rate limit na IP), wyłączenie unblocker jest w porządku i oszczędza kilka milisekund negocjacji TLS. Używaj go tam, gdzie jest potrzebny.
Dla zaawansowanych użytkowników
Kilka wzorców, które warto znać.
Połącz unblocker z residential proxy, gdy cel sprawdza również reputację IP. IP z datacenter w połączeniu z idealnym handshakiem TLS i tak zostaną oznaczone na ASN-ach, które strona ma na czarnej liście. Nasz endpoint proxy (/api/proxy) rotuje według domeny docelowej, więc dodanie "proxy": "residential" do requestu zazwyczaj wystarcza.
Pomiń unblocker przy wywoływaniu JSON API, które nie dbają o przeglądarki. Dodatkowe headery mogą wyglądać podejrzanie dla API oczekującego klienta programistycznego, na przykład gdy backend wywołuje własny mikroserwis.
Jeśli strona korzysta z zabezpieczeń JavaScript anti-bot (interaktywne wyzwania Turnstile, Perimeter X w najbardziej rygorystycznym trybie, Akamai Bot Manager z podkręconą heurystyką), sam unblocker nie wystarczy. Potrzebujesz endpointu browser, który uruchamia prawdziwe Chromium i potrafi wykonać challenge. To inny produkt z innym cennikiem kredytów, który opisaliśmy w Browser Tasks: Jak scrapować strony z dużą ilością JavaScriptu.
Możesz też połączyć unblocker z blokiem validate, aby odrzucać odpowiedzi, które technicznie zwracają 200, ale zawierają challenge page:
{
"url": "https://example.com/products",
"method": "GET",
"unblocker": true,
"validate": {
"data": { "fail": ["captcha", "Access Denied"] }
}
}
To zamienia ciche błędy w błędy sklasyfikowane, co ma znaczenie dla śledzenia wskaźnika sukcesu w dashboardzie.
Co dalej
Przeglądarki wydają nową wersję stabilną co cztery tygodnie. Maintainer curl-impersonate zazwyczaj nadrabia zaległości miesiąc później, a my podbijamy nasz stack, gdy to nastąpi. Nie musisz nic zmieniać po swojej stronie: unblocker: true stale wskazuje na wersję przeglądarki, którą zweryfikowaliśmy end-to-end.
Trudniejsze zadania dopiero przed nami. Fingerprinting HTTP/3 pojawia się już w zarządzanych systemach anti-bot, transport QUIC jest trudniejszy do sfałszowania niż TLS 1.3, a migracja ze statycznych pakietów headerów w stronę prawdziwie dynamicznej emulacji właśnie się rozpoczyna. Chronione strony przeszły na sprawdzanie kolejności ramek HTTP/2 i wariantów JA4+, a przepaść między „curlem, który wygląda jak przeglądarka” a „przeglądarką” będzie się kurczyć z obu stron. Napiszemy o tym, kiedy to wdrożymy.