Node.js 使用 fetch 实现验证码求解器:可运行示例(2026)
在 Node.js 中,验证码求解就是一次 HTTP 请求。Node 18 及更新版本内置了 fetch,因此调用 API 无需安装任何包。发送 sitekey 和页面 URL,等待响应,然后把 token 放入表单。本指南展示了针对 PopularCaptcha 的完整流程,Scarnox 目前以无代理方式支持该类型的求解。
先获取免费试用额度,无需信用卡,并先在测试页面上运行下面的代码。
环境要求
- Node.js 18 或更新版本(使用
node --version检查)。 - 一个 Scarnox API 密钥。请将其保存在环境变量中。
- 页面 PopularCaptcha 组件的 sitekey。如果你还没有它,请参阅如何找到验证码 sitekey。
求解器模块
下面的模块只包含一个函数。它携带 Bearer 请求头向 API 发送请求,185 秒后中止,并在 errorId 不为 0 时抛出错误:
// solver.mjs
const API_URL = "https://api.scarnox.com/api/tasks/create";
export async function solveCaptcha(sitekey, pageUrl, { invisible = false } = {}) {
const body = {
captcha_type: "PopularCaptchaTaskProxyless",
site_key: sitekey,
site_url: pageUrl,
};
if (invisible) body.is_invisible = true;
const res = await fetch(API_URL, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCARNOX_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(185_000), // 调用会在 token 准备好后返回
});
const data = await res.json().catch(() => null);
if (!data) throw new Error(`HTTP ${res.status}: response was not JSON`);
if (data.errorId !== 0) {
throw new Error(`${data.errorCode}: ${data.errorDescription}`);
}
return data.solution.token;
}
这里没有轮询。请求会保持打开,直到 token 准备好。成功时 token 位于 solution.token 中。
重试
求解失败时,errorId 不为 0,且你不会因此被计费。对于临时性失败,简单的重试循环就足够了。请保持较少的尝试次数,以免 sitekey 或页面 URL 错误时白白浪费时间:
export async function solveWithRetry(sitekey, pageUrl, attempts = 3) {
let lastError;
for (let i = 1; i <= attempts; i++) {
try {
return await solveCaptcha(sitekey, pageUrl);
} catch (err) {
lastError = err;
console.warn(`Attempt ${i} failed: ${err.message}`);
await new Promise((r) => setTimeout(r, 1000 * i));
}
}
throw lastError;
}
更完整的错误处理策略,请参阅验证码求解器错误处理。
提交 token
token 要放入网站期望的表单字段中。大多数 PopularCaptcha 页面会读取 h-captcha-response,许多页面也会读取 g-recaptcha-response。为了稳妥起见,请同时发送两者:
// submit.mjs
import { solveWithRetry } from "./solver.mjs";
const pageUrl = "https://example.com/signup";
const token = await solveWithRetry("YOUR-SITEKEY-UUID", pageUrl);
const form = new URLSearchParams({
email: "you@example.com",
"h-captcha-response": token,
"g-recaptcha-response": token,
});
const res = await fetch(pageUrl, {
method: "POST",
body: form,
redirect: "manual",
});
console.log("Status:", res.status);
运行方式:
SCARNOX_API_KEY=scarnox_YOURAPIKEY node submit.mjs
Cookie 与会话
普通的 fetch 不会在请求之间保留 cookie。许多注册和搜索页面会将验证码与会话 cookie 绑定,因此没有对应 cookie 的 token 可能会被拒绝。有两种处理方式:
- 从 GET 响应中复制
set-cookie的值,并在 POST 请求中带回。 - 使用浏览器自动化工具,由它替你保持会话。参见 Playwright 与 Puppeteer 验证码求解。
当表单比较简单、网站也不需要运行太多 JavaScript 时,选择第一种。对于更复杂的情况,选择第二种。
一个实用的检查方法:POST 之后,查看状态码和最终 URL。跳转到成功页面通常意味着 token 已被接受。如果页面再次显示组件,通常说明 token 被拒绝,或者 GET 请求中的 cookie 没有被带上。在最初几次运行中记录响应体,以便你弄清楚究竟是哪种情况。
时机
token 约在两分钟内过期。请在接近提交的时刻求解。常见的错误是在长时间任务开始时求解,然后在很久之后才提交。请求解后立即提交。验证码 token 过期对此有更详细的说明。
无感验证码
如果页面的组件带有 data-size="invisible",请传入 { invisible: true }。该函数随后会在请求中发送 is_invisible: true:
const token = await solveCaptcha("YOUR-SITEKEY-UUID", pageUrl, { invisible: true });
如果页面还为组件绑定了回调,表单可能需要调用该函数并传入 token。请阅读页面脚本以找到它。无感验证码指南涵盖了相关模式。
结合求解器进行抓取
有时验证码出现在你抓取的页面上,而不是你要提交的表单中。同样的模式依然适用:在 HTML 中检测组件,求解它,然后将其提交到组件所指向的 URL。请保持较低的请求频率,并先检查网站的条款。负责任地抓取:遵守 robots.txt,避免收集不需要的个人数据,也不要对服务器施加过大压力。
价格
Scarnox 按每次成功的求解计费,失败的求解不收费。当前费率请查看定价页面。要开始使用,请先获取免费试用额度,无需信用卡。