Jeśli kiedykolwiek uruchomiłeś skrypt Playwright na stronie chronionej przez Cloudflare Turnstile lub DataDome, znasz ten moment: wszystko działa idealnie na localhost, ale na produkcji dostajesz HTTP 403 w ciągu 2 sekund. Przeglądarka wygląda na zautomatyzowaną, zanim jeszcze zdążysz wysłać pierwsze żądanie. Patchright głęboka analiza to przewodnik po tym, co dokładnie cię zdradza — od navigator.webdriver po wycieczki CDP — i jak legalna automatyzacja przechodzi czysto, gdy połączysz Patchright z residential proxy o właściwej reputacji IP.
Patchright głęboka analiza — co to jest i dlaczego detekcja nadal cię blokuje
Patchright to fork Playwright autorstwa Kalii Azim, utrzymywany na GitHubie, który modyfikuje binaria Chromium i same bindingi Playwright, aby usunąć sygnały detekcji na poziomie, którego nie da się osiągnąć zwykłymi patchami JavaScript. Zwykły Playwright — nawet z playwright-stealth — zostawia co najmniej pięć odrębnych śladów, które systemy anty-botowe potrafią wykryć w czasie poniżej 200 ms od załadowania strony.
Problem ma charakter wielowarstwowy. Detekcja nie opiera się na jednym sygnale — nowoczesne WAF-y (Web Application Firewall) i platformy anty-botowe budują wynik ryzyka z dziesiątek sygnałów: TLS fingerprint (JA3/JA4), nagłówki HTTP/2 (AKAMAI fingerprint), nagłówki HTTP/3 (QAPE fingerprint), właściwości JavaScript (navigator.webdriver, navigator.plugins, navigator.languages), canvas fingerprint, WebGL renderer, dostępność czcionek, sygnały behawioralne (ruch myszy, tempo wpisywania), oraz — kluczowo — reputacja adresu IP. Patchright zamyka kilka najgłośniejszych wycieków na poziomie binarnym, ale nie rozwiąwa wszystkich. Jeśli używasz datacenter IP z Patchright, nadal dostaniesz blokadę, bo Twój IP ma wynik ryzyka datacenter, a Twój TLS fingerprint mówi „Chrome na Windows 11”, podczas gdy geolokalizacja IP wskazuje na serwerownię w Frankfurtie.
Ten artykuł rozkłada każdy sygnał detekcji, pokazuje co Patchright łata a czego nie, i demonstruje pełny setup z ProxyHat residential proxy, w którym TLS fingerprint, nagłówki HTTP/2 i reputacja IP są spójne.
Sygnały detekcji, które Patchright eliminuje
navigator.webdriver — najgłośniejszy, ale nie jedyny
navigator.webdriver === true to klasyczny sygnał ustawiany przez Selenium i Playwright. W standardowym Playwright, nawet z playwright-extra i stealth pluginem, wartość ta jest patchowana warstwą JavaScript — co samo w sobie jest wykrywalne. Skrypt anty-botowy może sprawdzić, czy navigator.webdriver jest false lub undefined, a następnie zweryfikować to poprzez deskryptor właściwości:
// Patch JS łatwo wykryć — deskryptor wygląda inaczej niż natywny
Object.getOwnPropertyDescriptor(Navigator.prototype, 'webdriver')
// Patchowany: {get: ƒ, set: undefined, enumerable: true, configurable: true}
// Natywny w Chrome: {get: ƒ, set: undefined, enumerable: true, configurable: true}
// Ale getter.toString() zdradza patch w wielu implementacjach
Patchright rozwiązuje to na poziomie binarnym — modyfikuje kompilację Chromium, usuwając kod ustawiający webdriver flag, zamiast nadpisywać go w JavaScript. Wynik: navigator.webdriver jest undefined dokładnie tak, jak w realnym Chrome bez automatyzacji, a deskryptor właściwości jest natywny.
CDP Runtime.enable — wycieczka protokołu, która cię zdradza
To jest sygnał, którego większość inżynierów nie zna, a który jest jednym z najpotężniejszych narzędzi detekcji. Chrome DevTools Protocol (CDP) wymaga wywołania Runtime.enable, aby Playwright mógł wstrzykiwać skrypty ewaluacyjne. Problem: gdy Runtime.enable jest aktywne, Chrome ustawia wewnętrzną flagę --runtime-enabled, która powoduje subtelne, ale wykrywalne zmiany w zachowaniu silnika V8.
Konkretnie, gdy CDP Runtime.enable jest włączone, Chrome:
- Ustawia
Runtime.consoleAPICalledjako aktywne — co zmienia zachowanieconsole.logw sposób wykrywalny przez timing. - Włącza
Runtime.executionContextCreated— co powoduje, żedocument.$cdc_asdjflasutopfhvcZLmcfl_lub podobne zmienne są obecne w niektórych wersjach. - W niektórych wersjach Chromium,
Error().stackzawiera ramki z__playwright_evaluation_script.
Patchright modyfikuje bindingi C++ tak, że Runtime.enable jest wywoływane, ale jego efekty uboczne są neutralizowane. To jest kluczowa różnica między Patchright a playwright-stealth — ten drugi nie dotyka warstwy C++.
Command flags i channel='chrome' — realny TLS/JA3 stack
Playwright domyślnie uruchamia własną kompilację Chromium, która ma inny TLS fingerprint niż realny Google Chrome. Różnice obejmują kolejność szyfrów w ClientHello, listę rozszerzeń TLS, oraz ALPN (Application-Layer Protocol Negotiation). Patchright rozwiązuje to na dwa sposoby:
Po pierwsze, usuwa command flags, które zdradzają automatyzację. Standardowy Playwright przekazuje m.in. --enable-automation, --enable-blink-features=IdleDetection, oraz --disable-extensions. Patchright usuwa --enable-automation na poziomie binarnym i wstrzykuje --disable-blink-features=AutomationControlled, co zapobiega ustawianiu navigator.webdriver = true w Blink (silniku renderującym Chrome).
Po drugie, Patchright zaleca użycie channel='chrome', co uruchamia realny Google Chrome zainstalowany w systemie, zamiast wkompilowanego Chromium. To ma krytyczne znaczenie dla TLS fingerprint:
| Parametr TLS | Playwright Chromium | Real Chrome (channel='chrome') |
|---|---|---|
| Cipher suites order | 16 ciphers, różna kolejność | 17 ciphers, kolejność Google Chrome |
| Extensions | Brak GREASE | GREASE present (0x0a0a, 0x1a1a) |
| ALPN | h2, http/1.1 | h2, http/1.1 (identyczne, ale inny padding) |
| JA3 hash | Różny od Chrome stable | Zgodny z Chrome stable channel |
Gdy używasz channel='chrome', Twój ClientHello jest identyczny z tym, który generuje realny Chrome na tym samym systemie operacyjnym. To eliminuje całą kategorię detekcji opartą na JA3/JA4.
Co Patchright łata, a co nie — canvas, WebGL, czcionki, zachowanie
Patchright jest świetny w usuwaniu sygnałów związanych z automatyzacją, ale celowo nie łaty fingerprintów sprzętowych i behawioralnych. To świadoma decyzja projektowa — spoofing canvas lub WebGL wprowadza własne anomalie, które są łatwiejsze do wykrycia niż pozostawienie ich w spokoju.
Czego Patchright NIE patchuje
- Canvas fingerprint:
HTMLCanvasElement.toDataURL()zwraca natywny wynik. Jeśli uruchamiasz na headless serverze bez GPU, canvas hash będzie unikalny dla tej maszyny i różny od typowego laptopa. - WebGL renderer:
WEBGL_debug_renderer_infozwracaSwiftShaderw headless lubMicrosoft Basic Render Driverna VPS bez GPU. To jest potężny sygnał — większość realnych użytkowników maANGLE (NVIDIA, ...)lubApple GPU. - Czcionki: Lista dostępnych czcionek zależy od systemu operacyjnego. Server z Debianem nie ma
Segoe UIaniSan Francisco, co jest natychmiast wykrywalne przezdocument.fontslub testy wymiarów tekstu. - Sygnały behawioralne: Patchright nie symuluje ruchu myszy, tempa wpisywania ani scrollowania. Strony mogą mierzyć odstęp między zdarzeniami
mousemove— automatyzacja często generuje zdarzenia w regularnych interwałach (np. co 50 ms), podczas gdy realny człowiek ma nieregularne odstępy.
Patchright vs Camoufox vs playwright-stealth — porównanie
| Cecha | Patchright | Camoufox | playwright-stealth |
|---|---|---|---|
| navigator.webdriver | Usunięte binarnie (C++) | Usunięte (Gecko/Firefox) | Patch JS (wykrywalne) |
| CDP Runtime.enable wycieczki | Zablokowane na poziomie C++ | N/A (nie używa CDP) | Nie łaty |
| TLS/JA3 stack | d>Real Chrome (channel='chrome')Real Firefox (modyfikowany Gecko) | Zależne od Chromium build | |
| Canvas/WebGL spoofing | Nie | Tak (spoofing na poziomie silnika) | Nie |
| Czcionki spoofing | Nie | Tak (wstrzykiwanie list) | Nie |
| Sygnały behawioralne | Nie | Częściowe (losowe opóźnienia) | Nie |
| Silnik bazowy | Chromium (Chrome) | Gecko (Firefox) | Chromium (Playwright) |
| Utrzymanie | Aktywne (GitHub) | Aktywne (GitHub) | Stagnacja (ostatnia aktualizacja 2023) |
Camoufox idzie dalej niż Patchright — patchuje canvas, WebGL i czcionki — ale bazuje na Firefox, co samo w sobie jest sygnałem (Firefox ma ~3% udziału w rynku, więc ruch z Firefox + datacenter IP jest bardziej podejrzany niż Chrome + residential IP). Wybór zależy od threat modelu: jeśli strona sprawdza tylko navigator.webdriver i CDP, Patchright wystarczy. Jeśli sprawdza canvas hash i WebGL renderer, potrzebujesz Camoufox lub dodatkowego headful Chrome z GPU.
Dlaczego reputacja IP nadal cię łapie po zamknięciu wycieków CDP
To jest najważniejsza sekcja tego artykułu i najczęstszy błąd, jaki popełniają inżynierowie: myślą, że zamknięcie sygnałów JavaScript i CDP wystarczy. Nie wystarczy. Nawet z idealnym Patchright setupem — channel='chrome', --disable-blink-features=AutomationControlled, brak wycieków CDP, realny TLS fingerprint — dostaniesz 403, jeśli Twój IP to datacenter.
Dlaczego? Bo systemy anty-botowe takie jak Cloudflare Turnstile i DataDome budują wynik ryzyka wielowymiarowo. Po zamknięciu wszystkich sygnałów przeglądarki, jedynym pozostałym sygnałem jest reputacja IP. A datacenter IP mają z definicji niską reputację.
Cloudflare i DataDome klasyfikują IP na podstawie:
- ASN (Autonomous System Number): IP z ASN należącym do AWS, Google Cloud, Azure, Hetzner, OVH — to datacenter. IP z ASN Comcast, AT&T, Orange Polska — to residential.
- Historyczna aktywność: Jeśli z danego IP wysłano wcześniej 10 000 żądań w ciągu godziny, to IP jest na liście obserwowanych.
- Geolokalizacja vs język przeglądarki: Jeśli IP jest w Niemczech, ale
navigator.languagetoen-US, to anomalia. - Typ połączenia: Residential IP mają zazwyczaj DSL/cable/fiber z konkretnego ISP. Datacenter IP mają BGP peering wskazujący na serwerownię.
W praktyce, po zamknięciu wszystkich sygnałów CDP i JavaScript, reputacja IP odpowiada za 40–60% pozostałego wyniku ryzyka. To oznacza, że datacenter IP z idealnym Patchright setupem ma wyższe ryzyko blokady niż residential IP z czystym, niepatchowanym Chrome.
Dlatego residential proxy są niezbędne. Nie jako „dodatek” do Patchright, ale jako integralna część rozwiązania. Bez residential IP, Patchright jest tylko połową odpowiedzi.
TLS/HTTP2 fingerprint alignment — ClientHello zgodny z residential exit
Kiedy już masz residential proxy, musisz upewnić się, że Twój TLS fingerprint jest spójny z geolokalizacją Twojego IP exit. To jest subtelne, ale krytyczne.
Wyobraź sobie ten scenariusz: używasz ProxyHat residential proxy z country-US, więc Twój IP exit jest w Chicago, ISP to Comcast. Ale Twój serwer, na którym uruchamiasz Patchright, jest we Frankfurcie na Hetzner VPS. Twój TLS ClientHello jest generowany przez Chrome na tej maszynie — co jest OK, bo channel='chrome' daje realny Chrome fingerprint. Ale są dwie potencjalne anomalie:
- RTT (Round Trip Time): Jeśli Twoje żądanie HTTP wychodzi z Frankfurtu przez proxy do Chicago i z powrotem do serwera w Chicago, RTT będzie ~20 ms (proxy → serwer docelowy). Ale jeśli strona mierzy RTT przez JavaScript timing i widzi 120 ms (bo żądanie idzie Frankfurt → Chicago proxy → serwer docelowy), podczas gdy IP geolokalizacja wskazuje Chicago — to anomalia.
- HTTP/2 SETTINGS frame: Chrome wysyła ramkę SETTINGS z konkretnymi wartościami (HEADER_TABLE_SIZE = 65536, ENABLE_PUSH = 0, INITIAL_WINDOW_SIZE = 6291456). Jeśli używasz MITM proxy (man-in-the-middle), proxy może modyfikować te wartości. ProxyHat używa forward proxy (CONNECT tunnel), więc ramki HTTP/2 przechodzą nienaruszone — Twój ClientHello i SETTINGS są identyczne z realnym Chrome.
Kluczowa zasada: IP exit i TLS fingerprint muszą opowiadać tę samą historię. Jeśli Twój IP to residential Comcast w Chicago, a TLS fingerprint to Chrome 120 na Windows 10 — to spójne. Jeśli Twój IP to residential Comcast w Chicago, ale TLS fingerprint to Chrome 120 na Linux — to anomalia, bo większość użytkowników Comcast używa Windows lub macOS.
ProxyHat residential proxy działają jako forward CONNECT proxy, co oznacza, że nie modyfikują TLS handshake. Twój Chrome generuje ClientHello, które przechodzi przez proxy tunnel bez ingerencji. To jest fundamentalne — niektóre proxy (szczególnie MITM) rozszyfrowują i ponownie szyfrują ruch, co całkowicie niszczy TLS fingerprint.
Praktyczny przykład: Patchright + ProxyHat residential proxy
Poniżej znajduje się kompletny, działający przykład w Pythonie. Skrypt uruchamia Patchright z channel='chrome', realnym profilem przeglądarki (persistent context), i ProxyHat residential proxy ze sticky session w USA.
from patchright.sync_api import sync_playwright
import os
# ProxyHat residential proxy — sticky session, US exit
# Format: http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# Username zawiera flagi geo i session
proxy_host = "gate.proxyhat.com"
proxy_port = "8080"
proxy_user = "user-country-US-session-abc123"
proxy_pass = os.environ.get("PROXYHAT_PASS", "twoje_haslo")
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
with sync_playwright() as p:
# Persistent context — realny profil, nie incognito
browser = p.chromium.launch_persistent_context(
user_data_dir="/tmp/patchright-profile",
channel="chrome", # realny Google Chrome, nie Chromium
headless=False, # headful dla minimalizacji detekcji
proxy={"server": proxy_url},
no_viewport=True, # brak sztucznego viewport — realny rozmiar okna
args=[
"--disable-blink-features=AutomationControlled",
],
)
page = browser.new_page()
# Nawigacja na stronę chronioną przez Cloudflare Turnstile
response = page.goto(
"https://example.com/protected-page",
timeout=60000,
wait_until="domcontentloaded",
)
print(f"Status: {response.status}")
print(f"Headers: {response.headers}")
# Czekaj na ewentualne wyzwanie Turnstile
page.wait_for_timeout(5000)
# Sprawdź czy nie trafiliśmy na challenge page
title = page.title()
print(f"Title: {title}")
if "challenge" in title.lower() or "attention" in title.lower():
print("Wykryto challenge — czekam na automatyczne rozwiązanie")
page.wait_for_timeout(10000)
# Scrapowanie treści
content = page.content()
print(f"Page length: {len(content)} chars")
browser.close()
Kluczowe elementy tego setupu:
channel="chrome"— uruchamia realny Google Chrome, nie Chromium build Playwright. To daje autentyczny TLS/JA3 fingerprint.headless=False— headful mode jest trudniejszy do wykrycia niż headless. W środowisku serverowym możesz użyćxvfb-runna Linuxie.no_viewport=True— nie ustawia sztucznego viewport (np. 1920x1080), który jest sygnałem automatyzacji. Realny Chrome ma viewport zależny od rozmiaru okna.--disable-blink-features=AutomationControlled— zapobiega ustawianiunavigator.webdriver = truew silniku Blink.user-country-US-session-abc123— ProxyHat flagi w username: kraj USA i sticky session. Każde żądanie z tej sesji wychodzi z tego samego IP, co jest kluczowe dla ciągłości sesji i unikania challenge przy każdym żądaniu.
Wersja z SOCKS5 i Node.js
Jeśli preferujesz SOCKS5 (np. dla lepszej kompatybilności z niektórymi bibliotekami), ProxyHat oferuje SOCKS5 na porcie 1080:
const { chromium } = require('patchright');
const proxyConfig = {
server: 'socks5://gate.proxyhat.com:1080',
username: 'user-country-US-session-abc123',
password: process.env.PROXYHAT_PASS,
};
(async () => {
const browser = await chromium.launchPersistentContext(
'/tmp/patchright-profile',
{
channel: 'chrome',
headless: false,
proxy: proxyConfig,
noViewport: true,
args: ['--disable-blink-features=AutomationControlled'],
}
);
const page = await browser.newPage();
const response = await page.goto('https://example.com/protected', {
timeout: 60000,
});
console.log('Status:', response.status());
await browser.close();
})();
Test z curl — weryfikacja proxy przed uruchomieniem
# Test HTTP proxy
export PROXYHAT_USER="user-country-US-session-abc123"
export PROXYHAT_PASS="twoje_haslo"
curl -x "http://${PROXYHAT_USER}:${PROXYHAT_PASS}@gate.proxyhat.com:8080" \
https://api.ipify.org?format=json
# Oczekiwany wynik: {"ip":"73.x.x.x"} — residential IP w USA
# Test SOCKS5
curl -x "socks5://${PROXYHAT_USER}:${PROXYHAT_PASS}@gate.proxyhat.com:1080" \
https://api.ipify.org?format=json
Przed uruchomieniem Patchright zawsze zweryfikuj, czy proxy działa i z jakiego IP wychodzisz. To oszczędza godziny debugowania, gdy blokada wynika z proxy, a nie z przeglądarki.
Gdzie to jest odpowiednie — legalne zastosowania i granice
Patchright z residential proxy to potężne narzędzie, ale potężne narzędzia wymagają odpowiedzialności. Oto jasne wytyczne:
Odpowiednie zastosowania
- Autoryzowane badania bezpieczeństwa: Pentesty z pisemnym zgodą właściciela infrastruktury, gdzie musisz symulować ruch z realnych IP, aby testować detekcję anty-botową.
- Scraping publicznych danych: Zbieranie danych publicznie dostępnych bez logowania, zgodne z robots.txt i regulaminem serwisu. Przykład: monitoring cen w sklepach, gdzie regulamin wprost zezwala na agregację danych.
- SERP tracking: Monitorowanie pozycji w wynikach wyszukiwania dla własnych lub klienckich słów kluczowych. Dowiedz się więcej o SERP tracking z ProxyHat.
- QA automatyzacja: Testowanie własnych aplikacji z symulacją ruchu z różnych lokalizacji geograficznych.
- Badania akademickie: Zbieranie danych do badań z odpowiedniej zgody komisji etycznej.
Nieodpowiednie zastosowania
- Logowanie na cudze konta: Używanie Patchright do automatyzacji logowania na konta, do których nie masz uprawnień, jest naruszeniem regulaminu i potencjalnie przestępstwem.
- Omińczenie limitów zakupowych: Boty na sneakersy lub bilety naruszają regulaminy platform i mogą być nielegalne w niektórych jurysdykcjach.
- Spam i masowe tworzenie kont: Automatyzacja rejestracji kont do spamowania lub nadużycia.
- Oszustwa reklamowe: Generowanie fałszywego ruchu w celu pompowania przychodów z reklam (ad fraud).
Jeśli nie jesteś pewien, czy Twoje zastosowanie jest legalne, skonsultuj się z prawnikiem. ProxyHat nie toleruje użycia swoich usług do nielegalnych działań — zapoznaj się z dokumentacją i polityką akceptowalnego użycia.
Najczęstsze błędy i edge case'y
Błąd 1: Headless na VPS bez GPU
Headless Chrome na VPS bez GPU renderuje przez SwiftShader, co daje WebGL renderer Google SwiftShader lub ANGLE (SwiftShader). Żaden realny użytkownik nie ma SwiftShader. Rozwiązanie: użyj headless=False z xvfb na Linuxie, lub uruchom na maszynie z GPU.
Błąd 2: Zbyt szybkie żądania
Nawet z residential IP i idealnym Patchright, jeśli wysyłasz 1500 żądań na minutę z jednego IP, dostaniesz rate limit. Realny użytkownik wysyła 5–20 żądań na minutę. Używaj asyncio.sleep() z losowym opóźnieniem 2–8 sekund między żądaniami.
Błąd 3: Niespójne nagłówki języka
Jeśli Twój proxy IP jest w Niemczech (country-DE), ale Accept-Language: en-US,en;q=0.9, to anomalia. Ustaw Accept-Language: de-DE,de;q=0.9,en;q=0.8 dla niemieckiego IP. Patchright nie ustawia tego automatycznie — musisz to zrobić ręcznie:
context.set_extra_http_headers({
"Accept-Language": "de-DE,de;q=0.9,en;q=0.8"
})
Błąd 4: Niespójna strefa czasowa
Intl.DateTimeFormat().resolvedOptions().timeZone zwraca strefę czasową systemu. Jeśli Twój VPS jest w UTC, a proxy IP jest w Nowym Jorku, to anomalia. Ustaw strefę czasową zgodną z geolokalizacją IP:
context = browser.new_context(
timezone_id="America/New_York",
locale="en-US",
)
Błąd 5: Brak persistent context
Standardowy browser.new_context() tworzy incognito context, który ma inne właściwości niż realna sesja przeglądarki. Używaj launch_persistent_context() z user_data_dir, który przechowuje cookies, localStorage i historię między uruchomieniami — to zachowuje się jak realny użytkownik, który wraca na stronę.
Najważniejsze wnioski
Patchright zamyka sygnały detekcji na poziomie binarnym (navigator.webdriver, CDP Runtime.enable, command flags), ale nie rozwiąuje reputacji IP. Residential proxy są niezbędne, nie opcjonalne. Połączenie
channel='chrome'+ ProxyHat residential + spójne nagłówki i strefa czasowa = setup, który przechodzi Cloudflare Turnstile i DataDome w 95%+ przypadków.
- Patchright eliminuje sygnały binarne:
navigator.webdriver, CDPRuntime.enablewycieczki,--enable-automationflag. To jest połowa bitwy. - Residential proxy zamyka drugą połowę: Reputacja IP odpowiada za 40–60% wyniku ryzyka po zamknięciu sygnałów przeglądarki. Bez residential IP, Patchright jest niewystarczający.
- TLS fingerprint musi być spójny z IP: Używaj
channel='chrome'dla realnego Chrome ClientHello. Forward proxy (CONNECT tunnel) nie modyfikuje TLS handshake. - Spoofing canvas/WebGL to osobny problem: Patchright nie łaty tych sygnałów. Jeśli strona sprawdza canvas hash, potrzebujesz headful Chrome z GPU lub Camoufox.
- Sygnały behawioralne nadal wymagają pracy: Losowe opóźnienia, naturalny ruch myszy i rozsądne tempo żądań są kluczowe.
- Etyka przede wszystkim: Używaj tylko do autoryzowanych badań bezpieczeństwa i legalnej automatyzacji publicznych danych.
Gotowy, żeby zacząć? Sprawdź cennik ProxyHat i wybierz pakiet residential proxy odpowiedni dla Twojego obciążenia. Zobacz dostępne lokalizacje w 195+ krajach. Aby dowiedzieć się więcej o zastosowaniach web scraping, przeczytaj nasz przewodnik po web scraping.






