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

Hunt 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-apiapi.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. 使用 widgethash 关键字查找请求。
  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="150", "Chromium";v="150"`,
"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="150", "Chromium";v="150"`,
"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);
}
})();