
Ethan Collins
Pattern Recognition Specialist
Playwright是一个由微软开发的现代浏览器自动化测试框架。它支持Chromium、Firefox和WebKit(分别对应Chrome、Firefox和Safari)的自动化。它提供了一个强大的API用于浏览器控制、元素选择、表单交互、网络拦截等等——使其成为需要与网页进行深度交互的任务的理想选择。
任何浏览器,任何平台,一个API
在Node.js中使用Playwright:
npm i playwright
npx playwright install # 安装所有浏览器(Chromium、Firefox、WebKit)
示例:获取CapSolver的所有博客标题
在下面的示例中,我们使用Playwright导航到CapSolver博客并获取页面上的所有<h5>博客文章标题

const { chromium } = require('playwright');
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
});
const [page] = context.pages();
await page.goto('https://www.capsolver.com/blog/All');
const h5Titles = await page.evaluate(() => {
const headings = Array.from(document.querySelectorAll('h5'));
return headings.map(heading => heading.textContent.trim());
});
console.log(h5Titles);
await context.close();
})();
Playwright功能强大,可以像普通浏览器一样加载浏览器扩展程序。
--disable-extensions-except和--load-extension在Playwright启动参数中指定扩展程序路径。const { chromium } = require('playwright');
const extensionPath = 'path/to/capsolver extension';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
],
});
const [page] = context.pages();
await page.goto('https://www.capsolver.com/blog/All');
await browser.close();
})();
像reCAPTCHA v2/v3、Cloudflare Turnstile、AWS WAF这样的CAPTCHA类型广泛应用于数千个网站。尽管它们很流行,但这些CAPTCHA通常具有稳定且可检测的DOM结构。这就是CapSolver扩展程序的作用——它自动检测并解决这些CAPTCHA,无需手动交互。
让我们以reCAPTCHA v2为例,演示如何使用Playwright中的CapSolver扩展程序来解决它。
**注意:**除非另有说明,否则以下示例使用点击模式(/assets/config.js -> reCaptchaMode: 'click')。
⚠️ 不要忘记解压扩展程序zip文件并在
/assets/config.js中配置你的apiKey
const { chromium } = require('playwright');
// 步骤1:从GitHub下载扩展程序:https://github.com/capsolver/capsolver-browser-extension/releases
// 步骤2:解压扩展程序文件并在/assets/config.js中设置你的apiKey
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
// 扩展程序将自动检测并解决reCAPTCHA。
await page.waitForTimeout(15000); // 等待解决
await page.click('button[type="submit"]');
await page.waitForTimeout(5000);
await context.close();
})();
⚠️ CapSolver扩展程序还支持许多有用的配置选项。以下是一些常见的示例(注意:所有配置都在
/assets/config.js中设置)
solvedCallback你可能已经注意到,在之前的代码中,我们在加载页面后等待了15秒,然后才点击提交按钮。此延迟是为了给CapSolver扩展程序足够的时间来自动解决reCAPTCHA。但是,这种方法并不理想——有时CAPTCHA解决得更快,在网络状况较差的情况下,它可能需要超过15秒。
这就是solvedCallback的作用。它通过在CAPTCHA解决后触发回调来提供更好的解决方案,通知你验证已完成。你可以在/assets/config.js中配置solvedCallback,方法是定义一个自定义函数名——默认情况下,它是captchaSolvedCallback。然后,在Playwright中使用page.exposeFunction在浏览器上下文中公开此函数。
现在让我们使用这种方法改进之前的代码。
const { chromium } = require('playwright');
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('Captcha solved!');
const iframe = await page.$('iframe[src*="recaptcha"]');
if (iframe) {
const frame = await iframe.contentFrame();
const finished = await frame.evaluate(() => {
const element = document.querySelector('.recaptcha-checkbox-border');
return element && window.getComputedStyle(element).display === 'none';
});
if (finished) {
console.log('Verification completed!');
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
await context.close();
} else {
console.log('Verification not complete. Retrying...');
}
}
});
})();
对于reCAPTCHA v2,有时可能会出现多个图像挑战。因此,在每次挑战之后,我们检查“我不是机器人”复选框是否已选中——如果它消失了,则验证被认为已完成。
manualSolving在之前的示例中,CAPTCHA解决会在页面加载后立即开始。但是,在某些情况下,你可能需要先执行其他任务——例如输入用户名/密码——然后再触发CAPTCHA解决。过早开始可能会导致令牌过期。
要处理此问题,请在/assets/config.js中设置manualSolving: true,这允许你手动触发CAPTCHA解决过程。
有两种方法可以触发解决:
window.postMessage({ type: 'capsolverSolve' });⚠️ 注意:此功能仅在v1.16.0以上版本的扩展程序中受支持!
示例:
const { chromium } = require('playwright');
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
// 模拟填写凭据
await page.evaluate(() => {
const inputA = document.querySelector('input[name="ex-a"]');
inputA.value = 'username';
const inputB = document.querySelector('input[name="ex-b"]');
inputB.value = 'password';
});
// 模拟其他延迟或用户活动
for (let i = 1; i <= 5; i++) {
await page.waitForTimeout(1000);
console.log(`Waited ${i} seconds...`);
}
console.log('Start solving CAPTCHA...');
// 方法1:模拟点击CapSolver按钮
await page.evaluate(() => {
document.querySelector('#capsolver-solver-tip-button').click();
});
// 方法2:使用postMessage触发
// await page.evaluate(() => {
// window.postMessage({ type: 'capsolverSolve' });
// });
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('Captcha solved!');
const iframe = await page.$('iframe[src*="recaptcha"]');
if (iframe) {
const frame = await iframe.contentFrame();
const finished = await frame.evaluate(() => {
const element = document.querySelector('.recaptcha-checkbox-border');
return element && window.getComputedStyle(element).display === 'none';
});
if (finished) {
console.log('Verification completed!');
await page.click('button[type="submit"]');
await page.waitForTimeout(3000);
await context.close();
} else {
console.log('Verification not complete. Try again.');
}
}
});
})();
reCaptchaModereCaptchaMode设置支持两种模式:“click”和“token”。
如果你在使用“click”模式时遇到多轮图像选择,这可能是由于浏览器指纹分数较低。建议切换到“token”模式以获得更好的可靠性。
| 点击模式 | 令牌模式 |
|---|---|
![]() |
![]() |
showSolveButton当showSolveButton设置为false(默认为true)时,CapSolver按钮将不再显示在页面上。但是,这不会影响正常的CAPTCHA解决功能。

设置useProxy: true后,你可以指定以下参数:proxyType、hostOrIp、port、proxyLogin和proxyPassword。通过此设置,我们将使用你的自定义代理来解决CAPTCHA。你应该在什么情况下使用你自己的代理?通常在以下情况下:
以上是一些常用的配置选项。你可以根据实际需要调整其他设置。如有任何疑问,请联系我们的客户支持。
与reCAPTCHA、Cloudflare Turnstile、AWS WAF或GeeTest等第三方CAPTCHA不同,还有一种类型的CAPTCHA需要识别图像中的字母或数字。我们称之为ImageToText CAPTCHA。它们通常如下所示:

ImageToText是由网站管理员自己实现的CAPTCHA。与第三方CAPTCHA不同,ImageToText CAPTCHA是由网站所有者定制的。由于这些CAPTCHA在不同网站和页面的位置各不相同,因此CapSolver扩展程序无法自动检测哪些图像是CAPTCHA。因此,你必须在代码中明确告知CapSolver扩展程序。以下是操作方法:
0的capsolver-image-to-text-source属性;0的capsolver-image-to-text-result属性。这些属性——capsolver-image-to-text-source和capsolver-image-to-text-result——可以在/assets/config.js中使用字段textCaptchaSourceAttribute和textCaptchaResultAttribute分别进行配置。
让我们来看一个使用该网站的示例:
https://captcha.com/demos/features/captcha-demo.aspx
首先,检查页面源代码以找到CAPTCHA图像元素和结果输入字段。在本例中:
demoCaptcha_CaptchaImagecaptchaCode
现在,让我们使用 Playwright 自动化解决此验证码,方法是相应地标记这些元素:
const { chromium } = require('playwright');
// 步骤 1:从 GitHub 获取扩展程序 (https://github.com/capsolver/capsolver-browser-extension/releases)
// 步骤 2:解压扩展程序 zip 文件并在 /assets/config.js 中配置您的 apiKey
const extensionPath = 'path/to/CapSolver Browser Extension-v1.16.0';
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`,
'--lang=en-US'
],
});
const [page] = context.pages();
await page.goto('https://captcha.com/demos/features/captcha-demo.aspx');
await page.waitForSelector('#demoCaptcha_CaptchaImage');
// 告诉 CapSolver 扩展程序验证码图像位于何处
await page.evaluate(() => {
const imgElement = document.querySelector('#demoCaptcha_CaptchaImage');
if (imgElement) {
imgElement.setAttribute('capsolver-image-to-text-source', '0');
}
});
// 告诉 CapSolver 扩展程序应在何处输入识别结果
await page.evaluate(() => {
const resultElement = document.querySelector('#captchaCode');
if (resultElement) {
resultElement.setAttribute('capsolver-image-to-text-result', '0');
}
});
// 等待验证码被解决并提交表单
await page.exposeFunction('captchaSolvedCallback', async () => {
console.log('验证码已解决!');
await page.waitForTimeout(3000);
await page.click('#validateCaptchaButton');
await page.waitForTimeout(3000);
await context.close();
});
})();
结果:

使用 CapSolver 扩展程序 方便快捷,但如果您是一位经验丰富的开发者,我们强烈建议您改用 API 集成。与基于扩展程序的方法相比,API 方法具有以下几个主要优势:
在我们深入研究代码演示之前,以下是使用 CapSolver API 的简要概述:
要创建任务,您需要向 CapSolver 发送一个 JSON 对象。此 JSON 包括您的clientKey、websiteURL、websiteKey以及其他数据。这些字段会根据验证码类型和网站而有所不同。
👉 有关详细信息,请参阅我们的文档:documentation
在解决 reCAPTCHA v2 之前,请阅读此处的文档:
📖 ReCaptchaV2
本指南说明了创建任务时要包含哪些 JSON 参数。
此外,您可以使用 CapSolver 扩展程序 快速生成 API 请求的 JSON 数据。
请参阅此博客以获得帮助:
🔗 获取 JSON 数据
让我们以以下示例为例:
🔗 https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php
此页面创建任务所需的 JSON 为:
{
"type": "ReCaptchaV2TaskProxyLess",
"websiteKey": "6LfW6wATAAAAAHLqO2pb8bDBahxlMxNdo9g947u9",
"websiteURL": "https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php"
}
我们还在我们的文档中提供了使用 API 的 JavaScript 代码示例:

在 Playwright 中集成:
const { chromium } = require('playwright');
const axios = require('axios');
// 将其替换为您的 API 密钥
const api_key = 'YOUR_API_KEY';
const captcha_type = 'ReCaptchaV2TaskProxyLess';
const site_key = '6LfW6wATAAAAAHLqO2pb8bDBahxlMxNdo9g947u9';
const site_url = 'https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php';
async function capSolver() {
const payload = {
clientKey: api_key,
task: {
type: captcha_type,
websiteKey: site_key,
websiteURL: site_url
}
};
try {
const res = await axios.post('https://api.capsolver.com/createTask', payload);
const task_id = res.data.taskId;
if (!task_id) {
console.log('创建任务失败:', res.data);
return;
}
console.log('获取 taskId:', task_id);
while (true) {
await new Promise(resolve => setTimeout(resolve, 1000)); // 延迟 1 秒
const getResultPayload = { clientKey: api_key, taskId: task_id };
const resp = await axios.post('https://api.capsolver.com/getTaskResult', getResultPayload);
const status = resp.data.status;
if (status === 'ready') {
return resp.data.solution.gRecaptchaResponse;
}
if (status === 'failed' || resp.data.errorId) {
console.log('解决失败!响应:', resp.data);
return;
}
}
} catch (error) {
console.error('错误:', error);
}
}
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: ['--lang=en-US'],
});
const [page] = context.pages();
await page.goto('https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php');
await page.waitForSelector('form[action="/recaptcha-v2-checkbox.php"]');
const token = await capSolver();
console.log("Token:", token);
// 设置 token 值
await page.evaluate((token) => {
const textarea = document.getElementById('g-recaptcha-response');
if (textarea) {
textarea.value = token;
}
}, token);
await page.click('button[type="submit"]');
await page.waitForTimeout(5000);
await context.close();
})();
我们仍然使用 https://captcha.com/demos/features/captcha-demo.aspx 的示例,其中验证码图像元素的 id 为demoCaptcha_CaptchaImage,结果输入元素的 id 为captchaCode,如下图所示:

对于 ImageToTextTask,我们需要将验证码图像的 base64 值传递给 CapSolver。示例代码如下:
const { chromium } = require('playwright');
const axios = require('axios');
// 将其替换为您的 API 密钥
const api_key = 'YOUR_API_KEY';
const captcha_type = 'ImageToTextTask';
const site_url = 'https://captcha.com/demos/features/captcha-demo.aspx';
async function capSolver(base64Image) {
const payload = {
clientKey: api_key,
task: {
type: captcha_type,
websiteURL: site_url,
body: base64Image,
}
};
try {
const res = await axios.post('https://api.capsolver.com/createTask', payload);
const status = res.data.status;
if (status === 'ready') {
return res.data.solution.text;
}
if (status === 'failed' || res.data.errorId) {
console.log('解决失败!响应:', res.data);
return "";
}
} catch (error) {
console.error('错误:', error);
}
}
(async () => {
const context = await chromium.launchPersistentContext('', {
headless: false,
viewport: { width: 1920, height: 1080 },
args: ['--lang=en-US'],
});
const [page] = context.pages();
await page.goto('https://captcha.com/demos/features/captcha-demo.aspx');
await page.waitForSelector('#demoCaptcha_CaptchaImage');
// 获取验证码图像的 base64 值
const captchaImage = await page.evaluate(() => {
const img = document.querySelector('img[id="demoCaptcha_CaptchaImage"]');
return img ? img.getAttribute('src') : null;
});
const base64Image = captchaImage.split(',')[1];
const text = await capSolver(base64Image);
console.log("文本:", text);
// 设置已解决的验证码文本
await page.evaluate((text) => {
document.getElementById('captchaCode').value = text;
}, text);
await page.click('#validateCaptchaButton');
await page.waitForTimeout(5000);
await context.close();
})();
此外,对于某些特殊的 ImageToText 类型,您可以指定不同的模型以提高准确性。有关详细信息,请参阅我们的文档:https://docs.capsolver.com/en/guide/recognition/ImageToTextTask/

包含 CapSolver 扩展程序的演示视频:
此外,CapSolver 还提供 开发者收入分成计划,允许开发者和合作伙伴通过集成或推广 CapSolver 解决方案来赚取佣金。这是一种在帮助他人高效解决验证码的同时,将您的工作货币化的绝佳方式。有关完整详细信息,请查看:CapSolver 开发者计划
Playwright 的强大功能与 CapSolver 处理验证码的能力相结合,为 Web 自动化提供了全面的解决方案。无论是为了方便使用 CapSolver 扩展程序,还是为了获得更大的控制力而使用 API,这种集成都可以简化复杂的任务并增强自动化工作流程。除了解决验证码之外,请记住 CapSolver 还提供了一个开发者收入分成计划,这为通过集成或推广其解决方案来赚取佣金提供了绝佳机会。
比较人工智能驱动的和人工驱动的验证码解决服务在速度、准确性、可扩展性、可靠性和成本效益方面的差异,用于现代自动化工作流程。
