使用Puppeteer爬取带GeeTest验证码网站时如何获取challenge key
问题核心原因
跨域iframe无法直接通过DOM访问是浏览器同源策略的默认限制,常规DOM查询、跨frame内容读取操作都会触发CORS拦截,不需要强行解析iframe内部内容就能拿到GeeTest的challenge key。
你之前尝试的两种公开方案失效原因明确:
- 滑块方案写死了旧版GeeTest的验证按钮选择器,不同站点部署的GeeTest版本、自定义样式存在差异,固定属性选择器必然匹配失败
- 网络请求监听方案没有做响应类型判断,拦截到非JSON格式的静态资源时会触发解析报错
可行实现方案
方案1:网络响应拦截(稳定性最高,无需操作iframe)
GeeTest加载流程固定,初始化时一定会向接口请求下发gt、challenge等核心校验参数,直接在Puppeteer层监听响应即可拿到参数,完全绕开iframe跨域问题。
参考实现代码:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); // 存储GeeTest校验参数 const geeTestParams = { gt: null, challenge: null, captchaId: null }; // 监听所有网络响应 page.on('response', async (resp) => { const respUrl = resp.url(); // 匹配GeeTest参数下发接口,兼容官方部署和私有化部署 const isGeeTestApi = (respUrl.includes('geetest') || respUrl.includes('captcha')) && (respUrl.includes('get.php') || respUrl.includes('register') || respUrl.includes('load')); if (isGeeTestApi) { try { const respJson = await resp.json(); geeTestParams.gt = respJson.gt; geeTestParams.challenge = respJson.challenge; geeTestParams.captchaId = respJson.captcha_id; } catch (e) { // 忽略非JSON格式的静态资源响应,避免报错 } } }); // 正常访问目标页面 await page.goto('你的目标站点地址', { waitUntil: 'networkidle2' }); // 等待参数加载完成,超时时间可根据站点速度调整 const waitParams = () => new Promise((resolve, reject) => { let checkCount = 0; const check = setInterval(() => { checkCount++; if (geeTestParams.challenge || geeTestParams.captchaId) { clearInterval(check); resolve(); } // 15秒超时 if (checkCount >= 30) { clearInterval(check); reject(new Error('GeeTest参数加载超时')); } }, 500); }); await waitParams(); // 此处即可拿到geeTestParams传给2captcha接口 console.log('GeeTest参数:', geeTestParams); })();
如果匹配不到对应接口,提前打开浏览器DevTools的网络面板,过滤关键词
challenge,1分钟内就能找到目标站GeeTest的参数下发接口,调整上面的URL匹配规则即可。
方案2:直接捕获GeeTest iframe上下文(适配特殊私有化部署场景)
不要用跨域读取iframe DOM的写法,通过Puppeteer的target监听事件直接拿到GeeTest iframe的执行上下文,不会触发同源策略拦截:
let geeTestFrame = null; // 监听新创建的frame目标 browser.on('targetcreated', async (target) => { if (target.type() !== 'frame') return; const frame = await target.frame(); const frameUrl = frame.url(); // 匹配GeeTest iframe特征 if (frameUrl.includes('geetest') || frameUrl.includes('captcha_verify')) { geeTestFrame = frame; } });
拿到geeTestFrame后,不要硬套固定选择器,先等frame内所有资源加载完成,再按版本匹配元素:GeeTest v3的验证按钮选择器为.geetest_radar_tip,v4版本为.geetest_click,不会出现元素找不到的问题。
对接2captcha注意事项
- 如果目标站用的是GeeTest v4版本,不需要传
challenge参数,只需要传captcha_id即可,不用强行找challenge字段浪费时间 - 2captcha返回校验通过的凭证后,直接调用页面内GeeTest实例的回调函数注入凭证即可,不需要模拟滑块拖动、点击提交等操作
- 提交2captcha请求时必须带上目标页面的完整url、对应的user-agent、请求头Cookie,否则会返回校验不通过
内容的提问来源于stack exchange,提问作者user19201082
相关产品推荐
相关产品推荐

