跳转到主要内容
获取令牌时遇到问题吗
联系支持

Hunt Captcha

CapMonster Cloud MCP
还可以使用 CapMonster Cloud MCP 检测并解决 CAPTCHA

Hunt CAPTCHA 是一种反机器人系统,会分析用户行为,并在检测到可疑活动时启动交互式验证。

任务示例​

以下是目前 CapMonster Cloud 服务支持的 Hunt Captcha 任务类型示例:

Puzzle CAPTCHA
Click CAPTCHA
Checkbox CAPTCHA

CapMonster Cloud 支持:

  • 生成 X-HD;
  • 通过 meta.token 解决 CAPTCHA;
  • 通过 widgetUrl 解决 CAPTCHA。
注意:

执行此任务时,请使用您自己的代理。

选择场景​

场景metadata 中的参数结果
生成 X-HDapiGetLibX-HD
通过 meta.token 解决apiGetLib, dataCAPTCHA 解决令牌
通过 widgetUrl 解决apiGetLib, widgetUrlCAPTCHA 解决令牌

如果页面中可以获取完整的组件链接,请使用 widgetUrl。在此场景中,无需获取 X-HD 和 meta.token。

如果无法获取 widgetUrl,请先生成 X-HD,从网站获取 meta.token,然后使用 data 参数创建任务(详情请参阅通过 data 解决 Hunt CAPTCHA 的示例)。

请求参数​


重要:部分参数值是动态的,每次渲染包含 Hunt 的页面时都会发生变化。
请在创建任务前立即提取这些参数,以避免解决过程中出现错误。 自动提取参数的示例请参阅如何获取 widgetUrl和通过 data 解决 Hunt CAPTCHA 的示例。


type<string>required

CustomTask


class<string>required

HUNT


websiteURL<string>required

使用 Hunt CAPTCHA 的页面完整 URL。


apiGetLib (位于 metadata 中)<string>required

api.js 文件的完整链接。

示例:

https://example.com/hd-api/external/apps/<app-hash>/api.js

在 DevTools 的 Network 选项卡中查找对 api.js 的请求。可使用 hd-api 或 api.js 进行搜索。


data(位于 metadata 中)<string>optional

从网站获取的 meta.token 值。

重要:仅在通过 meta.token 解决 CAPTCHA 时传递。不要与 widgetUrl 同时使用。


widgetUrl(位于 metadata 中)<string>optional

Hunt CAPTCHA 组件的完整 URL。

示例:

https://captcha.example.com/widget?hash=<widget-hash>

重要:请传递完整链接,包括域名、路径和请求参数。不要与 data 同时使用。


userAgent<string>optional

浏览器 User-Agent。请使用 CapMonster Cloud 当前支持的值:userAgentPlaceholder

可通过以下地址获取最新值:https://capmonster.cloud/api/useragent/actual。


proxyType<string>required

http - 常规 HTTP/HTTPS 代理;
https - 当 http 不可用时使用(某些自定义代理必填);
socks4 - SOCKS4 代理;
socks5 - SOCKS5 代理。


proxyAddress<string>required

代理 IP 地址(IPv4/IPv6)。禁止使用:

  • 透明代理
  • 本地机器代理


proxyPort<integer>required

代理端口


proxyLogin<string>required

代理登录名


proxyPassword<string>required

代理密码

创建任务的方法​

使用 createTask 方法:

POST
https://api.capmonster.cloud/createTask

生成 X-HD​

仅在 metadata 中传递 apiGetLib。

请求示例

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://yourwebsite.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

响应示例

{
"errorId": 0,
"taskId": 407533072
}

通过 meta.token 解决​

如果无法获取 widgetUrl 参数,请使用此方案。

步骤 1:获取 X-HD​

  1. 创建任务时仅传递 apiGetLib。
  2. 从 getTaskResult 响应中获取 X-HD。

步骤 2:获取 meta.token​

将获取到的 X-HD 发送到目标网站,例如在请求短信验证码时。

如果网站要求进行 CAPTCHA 验证,将返回类似以下内容的响应:

{
"errors": [
{
"code": "113",
"title": "Captcha error"
}
],
"meta": {
"token": "SITE_META_TOKEN"
}
}

步骤 3:解决 CAPTCHA​

创建一个新任务,并传递:

  • apiGetLib;
  • 在 data 参数中传递获取到的 meta.token。

请求示例

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://example.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js",
"data": "SITE_META_TOKEN"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

响应示例

{
"errorId": 0,
"taskId": 407533072
}

通过 widgetUrl 解决​

如果页面中可以获取 Hunt CAPTCHA 组件的完整链接,请使用此场景。

无需获取 X-HD 和 meta.token。

如何获取 widgetUrl​

  1. 打开包含 Hunt CAPTCHA 的页面。
  2. 打开 DevTools,并切换到 Network 选项卡。
  3. 执行会触发 CAPTCHA 的操作。
  4. 使用 widget 或 hash 关键字查找请求。
  5. 复制完整的 Request URL。
  6. 将其传递到 widgetUrl(位于 metadata 内)。


重要:

请在同一会话中、创建任务前立即获取当前有效的 widgetUrl。

不要只传递 hash 值:服务需要完整 URL。

请求示例

{
"clientKey": "API_KEY",
"task": {
"type": "CustomTask",
"class": "HUNT",
"websiteURL": "https://example.com/page-with-hunt",
"metadata": {
"apiGetLib": "https://example.com/hd-api/external/apps/<app-hash>/api.js",
"widgetUrl": "https://captcha.example.com/widget?hash=<widget-hash>"
},
"userAgent": "userAgentPlaceholder",
"proxyType": "your-proxy-type",
"proxyAddress": "your-proxy-address",
"proxyPort": 1234,
"proxyLogin": "your-proxy-login",
"proxyPassword": "your-proxy-password"
}
}

响应示例

{
"errorId": 0,
"taskId": 407533072
}

获取任务结果的方法​

使用 getTaskResult 方法获取 X-HD 指纹或 Hunt CAPTCHA 解决结果:

POST
https://api.capmonster.cloud/getTaskResult

请求示例

{
"clientKey": "API_KEY",
"taskId": 407533072
}

响应示例

{
"errorId": 0,
"status": "ready",
"solution": {
"data": {
"token": "6IyDCCpDdSK...YGs1Wug/z/kLNSpjewI="
}
}
}

solution.data.token 的值取决于所选场景:

  • 生成 X-HD 时,该字段包含 X-HD;
  • 通过 data 解决时,该字段包含 CAPTCHA 解决令牌;
  • 通过 widgetUrl 解决时,该字段包含 CAPTCHA 解决令牌。
重要:

目标网站可能会使用特定 Cookie 管理会话。如果缺少这些 Cookie,或请求中未传递这些 Cookie,服务器可能会拒绝请求或要求重新验证。

从网站获取的 Cookie 示例:

platform_type=desktop; typeBetNames=full; _glhf=1234567890; coefview=0; visit=1-123abc012345d1be726746568edc62d9; fast_coupon=true;
v3fr=1; lng=en; flaglng=en; SESSION=12a3aea8cdcfdbb9e7df8ee99b526a84; auid=ab0dW2mqlz1Tjo2AAwplAg==; ggru=195; che_g=12abcede-691f-c7b2-d1e8-8488bc557d98

Cookie 的一般工作原理:

  1. 首先打开网站页面,或向所需页面发送 GET 请求。这样服务器就可以初始化用户会话并设置必要的 Cookie。

  2. 服务器通过响应头 Set-Cookie 返回 Cookie。这些 Cookie 可能包含会话标识符、安全参数和反机器人保护数据。

  3. 请保存收到的 Cookie,因为后续请求会使用它们识别客户端。

  4. 向 API 发送后续请求时,应在 Cookie 请求头中将 Cookie 传回服务器,以便服务器识别该请求属于同一会话。

  5. 所有请求都应在同一会话中执行,并使用相同的 IP(或代理)和 User-Agent。否则,服务器可能会将请求视为可疑请求,并要求重新验证。

  6. 部分 Cookie 可能在客户端生成,例如由页面中的 JavaScript 创建。在自动化或测试过程中,有时需要从浏览器中提取这些 Cookie,或以类似方式生成。

通过 data 解决 Hunt CAPTCHA 的示例​

下面提供了通过 X-HD 和 meta.token 解决问题的完整示例。如果无法获取 widgetUrl,请使用此示例。

代码展示了如何:

  • 打开网站页面时获取初始 Cookie;
  • 生成可能在客户端创建的其他 Cookie;
  • 通过 CapMonster Cloud 创建网站用于验证请求的指纹(X-HD);
  • 向网站 API 发送请求以触发操作,例如发送短信;
  • 将获得的数据发送到 CAPTCHA 解决服务;
  • 获取解决结果后,使用必要参数向 API 发送最终请求。
重要:

请使用最新的 HTTP 请求头(详情请参阅此部分)以及正确的 User-Agent。

显示代码(Node.js)
import { gotScraping } from "got-scraping";
import crypto from "crypto";

/* ================= CONFIG (建议保存在 .env 中) ================= */
// CapMonster Cloud API、网站和用户数据设置

const API_KEY = "YOUR_API_KEY"; // 您的 CapMonster Cloud API 密钥
const SOLVER_URL = "https://api.capmonster.cloud";

const BASE_URL = "https://example.com"; // 网站基础 URL
const API_GET_LIB =
"https://example.com/hd-api/external/apps/a1047eab1035d58682a53557e0b2a75edbfd15fd/api.js"; // 网站的 api.js

const PHONE = "91123456789"; // 用于注册的电话号码(不含国家代码)
const COUNTRY_CODE = "54"; // 国家代码

const UA = "userAgentPlaceholder"; // 请求使用的 User-Agent

/* ================= 代理设置 ================= */

const PROXY_HOST = "proxyAddress";
const PROXY_PORT = 8080;
const PROXY_USER = "proxyLogin";
const PROXY_PASS = "proxyPassword";

const PROXY = `http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}`;

/* ================= HEADERS ================= */
// HTTP 请求头
// htmlHeaders — 用于页面 GET 请求
// apiHeaders — 用于网站 API 请求

const htmlHeaders = {
accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9,ru;q=0.8",
"cache-control": "no-cache",
pragma: "no-cache",
priority: "u=0, i",
"sec-ch-ua": `"Not:A-Brand";v="99", "Google Chrome";v="154", "Chromium";v="154"`,
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": `"Windows"`,
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": UA,
};

const apiHeaders = {
accept: "application/vnd.api+json",
"accept-encoding": "gzip, deflate, br, zstd",
"accept-language": "en-US,en;q=0.9,ru;q=0.8",
"cache-control": "no-cache",
pragma: "no-cache",
priority: "u=1, i",
"content-type": "application/vnd.api+json",
origin: BASE_URL,
referer: BASE_URL + "/", // 网站当前有效的 referer
"sec-ch-ua": `"Not:A-Brand";v="99", "Google Chrome";v="154", "Chromium";v="154"`,
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": `"Windows"`,
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": UA,
"x-requested-with": "XMLHttpRequest",
};

/* ================= UTILS ================= */
// 辅助函数

const delay = (ms) => new Promise((r) => setTimeout(r, ms));

function randomString(len = 20) {
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < len; i++) {
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}

/* ================= CAPMONSTER CLOUD ================= */
// 创建任务并等待 CAPTCHA 解决结果

async function createTask(task) {
const { body } = await gotScraping.post(`${SOLVER_URL}/createTask`, {
json: { clientKey: API_KEY, task },
responseType: "json",
});

if (body.errorId !== 0)
throw new Error("createTask error: " + JSON.stringify(body));

return body.taskId;
}

async function waitResult(taskId) {
while (true) {
const { body } = await gotScraping.post(`${SOLVER_URL}/getTaskResult`, {
json: { clientKey: API_KEY, taskId },
responseType: "json",
});

if (body.status === "ready")
return body.solution?.token || body.solution?.data?.token;

await delay(3000);
}
}

/* ================= MAIN FLOW ================= */
// 带 CAPTCHA 的自动注册主流程

(async () => {
try {
// ---------------- STEP 1: 获取 Cookie ----------------
console.log("STEP 1 — Getting cookies...");

const base = await gotScraping.get(
BASE_URL + "/registration?type=phone_reg", // 替换为网站当前有效的注册页面
{
headers: htmlHeaders,
proxyUrl: PROXY,
},
);

// 保存服务器返回的 Cookie
let cookies = (base.headers["set-cookie"] || [])
.map((c) => c.split(";")[0])
.join("; ");

// 生成在客户端创建的其他 Cookie
const che_g = crypto.randomUUID();
const ggru = randomString();

cookies += `; che_g=${che_g}`;
cookies += `; ggru=${ggru}`;

console.log("Cookies:", cookies);

// ---------------- STEP 2: 创建指纹 ----------------
console.log("\nSTEP 2 — Creating fingerprint...");

const fingerprintTaskId = await createTask({
type: "CustomTask",
class: "HUNT",
websiteURL: BASE_URL + "/",
userAgent: UA,
metadata: { apiGetLib: API_GET_LIB },
proxyType: "http",
proxyAddress: PROXY_HOST,
proxyPort: PROXY_PORT,
proxyLogin: PROXY_USER,
proxyPassword: PROXY_PASS,
});

const xhd = await waitResult(fingerprintTaskId);
console.log("X-HD:", xhd);

// ---------------- STEP 3: 发送短信请求 ----------------
console.log("\nSTEP 3 — Trigger SMS...");

const smsResp = await gotScraping.post(
BASE_URL + "/web-api/api/web/registration/v2/sms", // 替换为网站当前有效的 API 端点
{
headers: { ...apiHeaders, cookie: cookies, "x-hd": xhd },
json: {
data: { attributes: { phone: PHONE, country_code: COUNTRY_CODE } },
},
proxyUrl: PROXY,
responseType: "json",
},
);

const metaToken = smsResp.body?.meta?.token;
if (!metaToken) {
console.log("SMS response:", smsResp.body);
throw new Error("meta.token not received");
}

console.log("meta.token:", metaToken);

// ---------------- STEP 4: 解决 CAPTCHA ----------------
console.log("\nSTEP 4 — Solving Hunt captcha...");

const solveTaskId = await createTask({
type: "CustomTask",
class: "HUNT",
websiteURL: BASE_URL + "/",
userAgent: UA,
metadata: { apiGetLib: API_GET_LIB, data: metaToken },
proxyType: "http",
proxyAddress: PROXY_HOST,
proxyPort: PROXY_PORT,
proxyLogin: PROXY_USER,
proxyPassword: PROXY_PASS,
});

const captchaToken = await waitResult(solveTaskId);
console.log("Captcha token:", captchaToken);

// ---------------- STEP 5: 最终请求 ----------------
console.log("\nSTEP 5 — Sending final request...");

const finalResp = await gotScraping.post(
BASE_URL + "/api/web/registration/v2/sms", // 替换为网站当前有效的 API 端点
{
headers: { ...apiHeaders, cookie: cookies, "x-hd": xhd },
body: JSON.stringify({
data: {
attributes: {
phone: PHONE,
country_code: parseInt(COUNTRY_CODE),
captcha: captchaToken,
},
},
}),
proxyUrl: PROXY,
},
);

console.log("\nFINAL RESPONSE HEADERS:", finalResp.headers);
console.log("\nFINAL RESPONSE BODY:", finalResp.body);
} catch (err) {
console.error("\nFATAL ERROR:");
console.error(err);
}
})();

使用 SDK 库​

生成 X-HD 参数
// https://github.com/CapMonsterCloud/capmonster-nodejs-captcha-solver

import {
CapMonsterCloudClientFactory,
ClientOptions,
HuntRequest
} from "@zennolab_com/capmonstercloud-client";

document.addEventListener("DOMContentLoaded", async () => {

const API_KEY = "YOUR_API_KEY"; // 请指定您的 CapMonster Cloud API 密钥

const client = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: API_KEY })
);

// 要解决 HUNT,必须使用您自己的代理
const proxy = {
proxyType: "http",
proxyAddress: "123.45.67.89",
proxyPort: 8080,
proxyLogin: "username",
proxyPassword: "password",
};

const huntRequest = new HuntRequest({
websiteURL: "https://yourwebsite.com/page-with-hunt",
userAgent: "userAgentPlaceholder",
metadata: {
apiGetLib: "your-api-get-lib-url",
},
proxy,
});

// 如有需要,可以检查余额
const balance = await client.getBalance();
console.log("Balance:", balance);

const result = await client.Solve(huntRequest);
console.log("Solution:", result.solution);
});
解决 CAPTCHA
// https://github.com/CapMonsterCloud/capmonster-nodejs-captcha-solver

import {
CapMonsterCloudClientFactory,
ClientOptions,
HuntRequest
} from "@zennolab_com/capmonstercloud-client";

document.addEventListener("DOMContentLoaded", async () => {

const API_KEY = "YOUR_API_KEY"; // 请指定您的 CapMonster Cloud API 密钥

const client = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: API_KEY })
);

// 要解决 HUNT,必须使用您自己的代理
const proxy = {
proxyType: "http",
proxyAddress: "123.45.67.89",
proxyPort: 8080,
proxyLogin: "username",
proxyPassword: "password",
};

const huntRequest = new HuntRequest({
websiteURL: "https://yourwebsite.com/page-with-hunt",
userAgent: "userAgentPlaceholder",
metadata: {
apiGetLib: "your-api-get-lib-url",
data: "your-site-meta-token",
},
proxy,
});

// 如有需要,可以检查余额
const balance = await client.getBalance();
console.log("Balance:", balance);

const result = await client.Solve(huntRequest);
console.log("Solution:", result.solution);
});