| 106 | captchaSolver: { provider: string; requested: number; solved: number; failed: number; spentUsd: number; lastError: string | null } | null; |
106 | captchaSolver: { provider: string; requested: number; solved: number; failed: number; spentUsd: number; lastError: string | null } | null; |
| 107 | } |
107 | } |
| 108 | |
108 | |
| |
109 | +/** Assets that anti-bot vendors use to verify a real browser (trace pixels, widget assets): never block them. */ |
| |
110 | +const ANTIBOT_ASSET_RE = /\/cdn-cgi\/|challenges\.cloudflare\.com|captcha-delivery\.com|datadome|perimeterx|px-cdn|px-cloud|kasada|kpsdk|imperva|incapsula|_Incapsula_Resource|hcaptcha\.com|recaptcha|gstatic\.com\/recaptcha|arkoselabs|funcaptcha|awswaf|distil|shape-security|vercel\.com\/_vercel|\/_vercel\/|akamaihd|akam\/|\/akam\//i; |
| |
111 | + |
| 109 | const CHALLENGE_SELECTORS = ["#challenge-running", "#challenge-form", "#challenge-stage", ".cf-turnstile", "iframe[src*='challenges.cloudflare.com']", "#px-captcha", "#datadome", "iframe[src*='captcha-delivery.com']", "#sec-cpt-if", "form#challenge", "#cmsg", "[data-testid='challenge']"]; |
112 | const CHALLENGE_SELECTORS = ["#challenge-running", "#challenge-form", "#challenge-stage", ".cf-turnstile", "iframe[src*='challenges.cloudflare.com']", "#px-captcha", "#datadome", "iframe[src*='captcha-delivery.com']", "#sec-cpt-if", "form#challenge", "#cmsg", "[data-testid='challenge']"]; |
| 110 | |
113 | |
| 111 | export class BrowserPool { |
114 | export class BrowserPool { |
| 386 | // fallback() (not continue()) lets Patchright's context-level route inject the init scripts. |
389 | // fallback() (not continue()) lets Patchright's context-level route inject the init scripts. |
| 387 | return route.fallback(); |
390 | return route.fallback(); |
| 388 | } |
391 | } |
| 389 | − if (blockResources) { |
392 | + if (blockResources && !ANTIBOT_ASSET_RE.test(r.url())) { |
| 390 | const type = r.resourceType(); |
393 | const type = r.resourceType(); |
| 391 | if (type === "image" || type === "media" || type === "font" || type === "manifest" || type === "texttrack") return route.abort("blockedbyclient"); |
394 | if (type === "image" || type === "media" || type === "font" || type === "manifest" || type === "texttrack") return route.abort("blockedbyclient"); |
| 392 | } |
395 | } |