| 106 |
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 |
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 |
114 |
export class BrowserPool { |
| 386 |
389 |
// fallback() (not continue()) lets Patchright's context-level route inject the init scripts. |
| 387 |
390 |
return route.fallback(); |
| 388 |
391 |
} |
| 389 |
|
− if (blockResources) { |
|
392 |
+ if (blockResources && !ANTIBOT_ASSET_RE.test(r.url())) { |
| 390 |
393 |
const type = r.resourceType(); |
| 391 |
394 |
if (type === "image" || type === "media" || type === "font" || type === "manifest" || type === "texttrack") return route.abort("blockedbyclient"); |
| 392 |
395 |
} |