Playwright处理验证码的自动化解决方案

简介: 验证码是自动化测试的常见难题。本文总结了Playwright处理验证码的五种实用方案:测试环境禁用、凭证缓存、OCR识别、智能重试及专项处理滑动/点选验证码,并提出分层策略与最佳实践,助你提升测试稳定性,兼顾效率与合规。

验证码(CAPTCHA)一直是自动化测试中最让人头疼的环节之一。每次碰到那些扭曲的文字、点选图片的挑战,自动化脚本就像撞上了一堵墙。我负责的电商项目最近就卡在了登录自动化这个环节——那个该死的滑动验证码让我们的回归测试屡屡失败。

经过几周的实战踩坑和方案对比,我总结出几种用Playwright处理验证码的可行方案。这些方案各有适用场景,没有绝对的“银弹”,但足够帮你绕过大多数验证码障碍。

方案一:最直接的方式——测试环境关闭验证码
如果你们公司有测试环境的管理权限,这是最干净利落的解决方案。

// 在测试环境中,通过修改配置或调用管理接口禁用验证码
asyncfunction disableCaptchaInTestEnv(page) {
// 方式1:如果有管理后台接口
await page.goto('http://test-admin.example.com/features');
await page.click('#toggle-captcha');

// 方式2:通过设置测试用户白名单
await page.evaluate(() => {
localStorage.setItem('bypass_captcha', 'true');
});

// 方式3:修改hosts或使用mock服务(需运维配合)
console.log('验证码已在测试环境关闭');
}
优点:零成本,100%稳定,执行速度快。
缺点:仅限测试环境,生产环境模拟不了完整流程。

方案二:半自动方案——人工介入一次,重复使用凭证
对于无法关闭验证码但又不频繁变更的场景,这个方案很实用。

const fs = require('fs');
const path = require('path');

class CaptchaHandler {
constructor() {
this.tokenFile = path.join(__dirname, '.auth_token');
}

async handleCaptcha(page) {
// 检查是否有缓存的登录凭证
if (fs.existsSync(this.tokenFile)) {
const token = fs.readFileSync(this.tokenFile, 'utf8');
awaitthis.useCachedToken(page, token);
returntrue;
}

// 首次需要人工处理
console.log('请手动完成验证码验证...');

// Playwright会暂停,等待人工操作
await page.pause();  // 这是关键!手动完成后按回车继续

// 保存获取到的凭证(如cookie、token)
const cookies = await page.context().cookies();
const authToken = cookies.find(c => c.name === 'auth_token');

if (authToken) {
  fs.writeFileSync(this.tokenFile, authToken.value);
  console.log('凭证已保存,后续测试将自动使用');
}

returntrue;

}

async useCachedToken(page, token) {
// 使用缓存的token设置cookie
await page.context().addCookies([{
name: 'auth_token',
value: token,
domain: 'your-domain.com',
path: '/'
}]);

// 刷新页面使cookie生效
await page.reload();

}
}

// 使用示例
const handler = new CaptchaHandler();
await handler.handleCaptcha(page);
await page.goto('https://your-app.com/dashboard');
优点:平衡了自动化与可靠性,只需人工介入一次。
缺点:凭证过期后需要重新人工处理。

方案三:全自动方案——第三方OCR服务
当需要完全自动化且验证码不算太复杂时,可以考虑OCR方案。

const axios = require('axios');
const fs = require('fs');

asyncfunction solveCaptchaWithOCR(page) {
// 1. 定位并截图验证码元素
const captchaElement = await page.$('.captcha-image');
const screenshotPath = 'captcha.png';
await captchaElement.screenshot({ path: screenshotPath });

// 2. 读取图片并编码为base64
const imageBuffer = fs.readFileSync(screenshotPath);
const base64Image = imageBuffer.toString('base64');

try {
// 3. 调用OCR API(这里以2Captcha为例,需注册获取API key)
const apiKey = process.env.CAPTCHA_API_KEY;
const response = await axios.post('https://2captcha.com/in.php', {
key: apiKey,
method: 'base64',
body: base64Image,
json: 1
});

const requestId = response.data.request;

// 4. 轮询获取结果
let result = null;
for (let i = 0; i < 30; i++) {
  await page.waitForTimeout(2000);

  const checkResponse = await axios.get(
    `https://2captcha.com/res.php?key=${apiKey}&action=get&id=${requestId}&json=1`
  );

  if (checkResponse.data.status === 1) {
    result = checkResponse.data.request;
    break;
  }
}

if (!result) thrownewError('OCR识别超时');

// 5. 输入识别结果
await page.fill('#captcha-input', result);
await page.click('#submit-btn');

returntrue;

} catch (error) {
console.error('OCR识别失败:', error.message);
// 失败时保存截图供后续分析
fs.renameSync(screenshotPath, failed_${Date.now()}.png);
returnfalse;
}
}
费用提示:2Captcha每1000次识别约$1-3,具体看复杂度。对于大型测试套件,这是笔不小的开销。

方案四:智能等待与重试机制
有时候验证码的出现是有条件的,可以通过优化测试逻辑来减少触发。

async function smartLogin(page, username, password) {
const MAX_RETRIES = 3;

for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
await page.goto('https://example.com/login');

  // 填写登录表单
  await page.fill('#username', username);
  await page.fill('#password', password);

  // 检测验证码是否出现
  const captchaVisible = await page.isVisible('.captcha-container');

  if (captchaVisible) {
    console.log(`第${attempt}次尝试出现验证码,尝试绕过...`);

    // 尝试刷新验证码(有时新的验证码更简单)
    await page.click('.refresh-captcha');
    await page.waitForTimeout(1000);

    // 这里可以集成上述的任一解决方案
    // await solveCaptchaWithOCR(page);

    // 或者使用备用账号
    if (attempt > 1) {
      await page.fill('#username', `${username}_backup`);
    }
  }

  // 提交登录
  await page.click('#login-btn');

  // 等待登录成功标志
  await page.waitForSelector('.user-dashboard', { timeout: 5000 });

  console.log('登录成功!');
  returntrue;

} catch (error) {
  console.log(`第${attempt}次登录尝试失败: ${error.message}`);

  if (attempt === MAX_RETRIES) {
    thrownewError(`登录失败,已重试${MAX_RETRIES}次`);
  }

  // 等待一段时间后重试
  await page.waitForTimeout(2000);
}

}
}
方案五:针对特定类型验证码的专项处理
滑动验证码处理
async function handleSlideCaptcha(page) {
const slider = await page.$('.slider');
const sliderBox = await slider.boundingBox();
const target = await page.$('.slider-target');
const targetBox = await target.boundingBox();

// 计算需要滑动的距离
const slideDistance = targetBox.x - sliderBox.x;

// 模拟人类滑动(先快后慢)
await slider.hover();
await page.mouse.down();

// 分段滑动,模拟真实轨迹
const steps = 10;
const stepDistance = slideDistance / steps;

for (let i = 0; i < steps; i++) {
// 越靠近目标越慢
const speed = 50 + Math.random() 100 - i 10;
await page.mouse.move(
sliderBox.x + stepDistance (i + 1),
sliderBox.y + (Math.random()
10 - 5), // 加入微小垂直抖动
{ steps: 1 }
);
await page.waitForTimeout(speed);
}

await page.mouse.up();
}
点选文字验证码(简单版)
async function handleClickCaptcha(page) {
// 获取需要点击的文字
const promptText = await page.$eval('.captcha-prompt', el => el.textContent);
const wordsToClick = promptText.match(/点击【(.*?)】/)[1].split('');

// 获取所有可点击的文字元素
const charElements = await page.$$('.captcha-char');

for (const char of wordsToClick) {
for (const element of charElements) {
const text = await element.textContent();
if (text === char) {
// 随机延迟后点击,模拟人类反应时间
await page.waitForTimeout(300 + Math.random() * 500);
await element.click();
break;
}
}
}
}
最佳实践建议
根据我们项目的经验,我推荐以下策略:

分层处理策略:

// 策略优先级:禁用 > 缓存 > OCR > 重试
class CaptchaStrategy {
async solve(page) {
if (awaitthis.tryDisableCaptcha(page)) return;
if (awaitthis.tryCachedToken(page)) return;
if (awaitthis.tryOCR(page)) return;
if (awaitthis.tryAlternativeAccount(page)) return;

// 最后手段:标记测试失败并保存截图
awaitthis.saveDebugInfo(page);
thrownewError('无法处理验证码');

}
}
验证码监控:

// 记录验证码出现频率,用于优化测试策略
const captchaStats = {
totalAttempts: 0,
captchaShown: 0,
successRate: 0,
lastCaptchaTime: null
};
环境感知配置:

// 根据环境选择不同策略
const CAPTCHA_CONFIG = {
development: { strategy: 'disable' },
staging: { strategy: 'cached_token' },
production: { strategy: 'mixed', fallback: 'ocr' }
};
总结
验证码的处理没有一劳永逸的方案,但通过组合策略,我们基本能保证自动化测试的稳定性。我们团队目前的方案是:测试环境完全禁用,预发环境使用缓存令牌,只有少量的生产环境监控脚本会使用OCR服务。

最后提醒一点:尊重网站的验证码机制。这些措施旨在提升测试效率,而不是滥用或攻击服务。对于特别复杂的验证码(如行为验证),与其花费大量精力破解,不如考虑与开发团队协商,为自动化测试提供专门的测试接口或令牌。

如果你有更好的验证码处理方案,欢迎在评论区分享——毕竟,每个项目的验证码实现都可能不一样,多交流才能少踩坑。

相关文章
|
5天前
|
人工智能 定位技术 SEO
我学 GEO 第 15 天:终于知道AI GEO该如何做?
我是暴走的莉莉酱,边旅行边研究AI GEO的数字游民。专注普通人如何提升“AI可见度”——让AI在回答用户问题时准确识别、理解并推荐你。不讲玄学,只做可测、可调、可持续的GEO实践。
419 125
|
8天前
|
机器学习/深度学习 人工智能 调度
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
HappyHorse 1.1 是新一代视频生成大模型,全面升级动态表现力、角色一致性、指令遵循、视觉质感与音画协同能力。支持I2V/T2V/R2V三类生成,适配短剧、电商广告、品牌营销等场景,提供高质、流畅、可控的AI视频生产力。
707 5
🐴 HappyHorse 1.1 现已上线阿里云百炼!快来查收模型使用指南,现在调用享 6 折~
|
5天前
|
缓存 人工智能 运维
阿里云618百炼大模型Qwen3.7-Max功能、免费试用、订阅计费、配置接入详解
Qwen3.7-MAX是阿里云百炼平台推出的通义千问3.7系列旗舰大语言模型,专为智能体时代复杂任务打造,依托阿里云全域算力与自研技术,在逻辑推理、长文本处理、代码工程、长周期自主执行等领域达到行业顶尖水平。2026年618期间,该模型推出多重免费试用权益、按量计费5折、订阅套餐优惠等专属福利,覆盖个人开发者、团队与企业全场景需求,以下从核心功能、免费试用、订阅计费、配置接入四方面展开详细解析。
410 123
|
3天前
|
人工智能 自然语言处理 API
阿里云Token Plan团队版解析:功能、三档套餐与省钱订阅指南
阿里云百炼平台推出的Token Plan团队版,是面向企业与团队的AI大模型订阅服务,以Credits为统一计量单位,整合文本与图像生成模型,提供团队管理、数据安全、多工具兼容等核心能力,解决团队零散订阅AI服务的管理混乱、成本失控、数据安全等痛点。本文将从核心定位、套餐详情、计费规则、团队管理、工具兼容、便宜订阅技巧等方面,全面解析Token Plan团队版,帮助企业与团队高效、低成本地使用AI服务。
307 108
|
5天前
|
存储 人工智能 数据可视化
别再手动复制 Skill 了:多 Agent 时代的 Skill 管理方案
多 Agent 场景下 Skill 的统一管理与同步。
254 123
|
18天前
|
缓存 测试技术 API
Qwen 3.7 Plus 与 Max 实测:性价比与多模态能力差异解析(2026)
2026 年 6 月 1 日,阿里悄无声息地发布了 Qwen 3.7 Plus,距 Qwen 3.7 Max 上线刚好 11 天。同样的 1M 上下文,同样的 35 小时自治上限。但价格才是头条:Plus 是 0.40/M输入,Max是 2.50/M——便宜约 6 倍——并且还能看图、看视频。Vision Arena 上 Plus 已经排到 #16。所以这周真正值得讨论的问题不是”要不要为视觉能力买单”,而是”Max 凭什么用 6 倍价格换来 2 个百分点的 benchmark 领先”。
|
12天前
|
缓存 人工智能 运维
GLM 5.2自托管全流程实战:硬件选型、vLLM/SGLang部署与成本盈亏测算
2026年智谱发布GLM 5.2超大混合专家模型,区别于以往仅开放API的闭源大模型,该模型权重以MIT开源协议对外发布,企业与开发者可完整下载、本地审计、私有化部署,实现数据不出环境、自定义微调、自主调度推理资源。GLM 5.2拥有753B总参数,原生支持百万级上下文窗口,在代码生成、长文档推理、数学逻辑等多项基准测试中对标国际顶尖商用模型,是首款可完整自托管的前沿代码向大模型。
928 0
|
13天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)