/** * CAPTCHA_PROXY 解析与 Chrome 代理注入(与 CapSolver AntiCloudflareTask 使用同一 IP) * * 仅在实际检测到 CF 挑战、需要 Managed 过盾时由 server.js 显式启用(useCaptchaProxy=true)。 * 格式:ip:port:username:password */ const CAPTCHA_PROXY_RAW = (process.env.CAPTCHA_PROXY || '').trim(); /** * @returns {{ * host: string, * port: string, * username: string, * password: string, * chromeProxyServer: string, * capsolverString: string, * }|null} */ function parseCaptchaProxy(raw = CAPTCHA_PROXY_RAW) { const value = (raw || '').trim(); if (value === '') { return null; } const parts = value.split(':'); if (parts.length < 4) { return null; } const host = parts[0]; const port = parts[1]; const username = parts[2]; const password = parts.slice(3).join(':'); if (!host || !port || !username || !password) { return null; } return { host, port, username, password, chromeProxyServer: `http://${host}:${port}`, capsolverString: value, }; } /** @returns {boolean} */ function hasCaptchaProxy() { return parseCaptchaProxy() !== null; } /** * 是否属于可能走 CapSolver Managed 的工单(A2C 等) * 注意:仅表示候选,不代表本次任务一定挂代理 * @param {object|null|undefined} antiBot */ function isManagedCfCandidate(antiBot) { if (!antiBot?.enabled) { return false; } if (antiBot.cfChallengeMode === 'managed') { return true; } if (antiBot.cfCloudflareSolver === true) { return true; } return false; } /** * @deprecated 请使用 isManagedCfCandidate + 显式 useCaptchaProxy 参数 */ function shouldUseCaptchaProxyForAntiBot(antiBot) { return false; } /** * Chrome 启动参数 --proxy-server(须 useCaptchaProxy=true 时调用) * @returns {string[]} */ function getCaptchaProxyChromeArgs() { const parsed = parseCaptchaProxy(); if (!parsed) { return []; } return [ `--proxy-server=${parsed.chromeProxyServer}`, '--proxy-bypass-list=<-loopback>,localhost,127.0.0.1', ]; } /** * 为 Page 设置代理认证(须配合 --proxy-server) * @param {import('puppeteer').Page} page * @returns {Promise} */ async function applyCaptchaProxyToPage(page) { const parsed = parseCaptchaProxy(); if (!parsed || !page) { return false; } await page.authenticate({ username: parsed.username, password: parsed.password, }); return true; } module.exports = { parseCaptchaProxy, hasCaptchaProxy, isManagedCfCandidate, shouldUseCaptchaProxyForAntiBot, getCaptchaProxyChromeArgs, applyCaptchaProxyToPage, };