You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 06:06:26