Heroku上使用Puppeteer无头Chrome绕过Cloudflare验证码失效问询
问题核心原因
- 最高优先级诱因:Heroku所有出口IP均属于公开的云服务机房IP段,Cloudflare的IP风险库默认会给这类IP打高风险标签,直接触发人机验证,这也是本地家用/办公IP正常但部署后出问题的最常见原因。
- 次优先级诱因:你当前的无头Chrome配置仍有可被识别的特征:
- 使用的是旧版
headless: true模式,Chrome旧无头模式本身存在大量独有特征,哪怕搭配stealth插件也不能完全覆盖,Cloudflare可以轻松识别。 - 启动参数缺失部分反识别常用配置,没有禁用WebGL指纹追踪、隐藏自动化标记的相关参数。
- 当前视口高度设置为3000+随机值,不符合普通用户的正常设备视口尺寸,反而会成为异常识别特征。
- 使用的是旧版
修复方案
1. 优先解决IP问题
在Puppeteer启动参数里配置民用住宅IP段的代理,避开Heroku自带的机房IP,是解决Cloudflare验证成本最低的方案。
2. 优化Puppeteer配置
修改启动配置如下:
const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); puppeteer.use(StealthPlugin()); const randomUseragent = require('random-useragent'); let browser = await puppeteer.launch( { // 替换旧的headless: true为headless: 'new',Chrome 112及以上版本支持,特征和普通浏览器几乎一致 headless: 'new', executablePath: process.env.CHROME_BIN || null, args: [ '--enable-features=NetworkService', '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', // 新增反识别参数 '--disable-blink-features=AutomationControlled', '--disable-webgl', '--disable-extensions', '--no-first-run', '--no-default-browser-check', '--disable-background-networking', '--disable-sync', '--disable-translate', '--hide-scrollbars', '--metrics-recording-only', '--mute-audio', '--no-pings', '--password-store=basic', '--use-mock-keychain' ], ignoreHTTPSErrors: true, dumpio: false } ); let page = await browser.newPage(); // 限定随机UA为110版本以上的Chrome,避免旧版本UA触发风险检测 const userAgent = randomUseragent.getRandom(ua => ua.browserName === 'Chrome' && parseInt(ua.browserVersion) >= 110); const UA = userAgent || 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'; // 修正视口范围,符合普通桌面用户的正常尺寸 await page.setViewport({ width: 1280 + Math.floor(Math.random() * 640), height: 720 + Math.floor(Math.random() * 360), deviceScaleFactor: Math.random() > 0.5 ? 1 : 2, hasTouch: false, isLandscape: false, isMobile: false, }); await page.setUserAgent(UA); await page.setJavaScriptEnabled(true); await page.setDefaultNavigationTimeout(0); // 新增删除webdriver自动化标记 await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'webdriver', { get: () => undefined, }); }); // 把networkidle0替换为networkidle2,避免给检测脚本留过长的特征收集时间 await page.goto('https://external.site.example', { waitUntil: 'networkidle2' });
内容的提问来源于stack exchange,提问作者meacuna
相关产品推荐
相关产品推荐

