auto-account-machine/src/tools/account-register/utils/capsolver-api.js
dengqichen 75986287d1 aaaaa
2025-11-17 21:14:17 +08:00

227 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* CapSolver API - hCaptcha/Turnstile 自动识别
* 使用官方API方式不依赖浏览器扩展
*/
const axios = require('axios');
const logger = require('../../../shared/logger');
class CapSolverAPI {
constructor(apiKey) {
this.apiKey = apiKey || process.env.CAPSOLVER_API_KEY;
this.apiUrl = 'https://api.capsolver.com';
if (!this.apiKey) {
logger.warn('CapSolver', '未配置API Key自动识别将不可用');
}
}
/**
* 解决 hCaptcha
* @param {string} siteKey - 网站的 siteKey
* @param {string} pageUrl - 当前页面URL
* @returns {Promise<string>} token
*/
async solveHCaptcha(siteKey, pageUrl) {
if (!this.apiKey) {
throw new Error('CapSolver API Key 未配置');
}
logger.info('CapSolver', '开始识别 hCaptcha...');
logger.info('CapSolver', `SiteKey: ${siteKey.substring(0, 20)}...`);
try {
// 1. 创建任务
const requestBody = {
clientKey: this.apiKey,
task: {
type: 'HCaptchaTaskProxyless',
websiteURL: pageUrl,
websiteKey: siteKey
}
};
logger.info('CapSolver', `请求 URL: ${pageUrl}`);
logger.info('CapSolver', `API Key: ${this.apiKey.substring(0, 10)}...`);
const createTaskResponse = await axios.post(`${this.apiUrl}/createTask`, requestBody);
if (createTaskResponse.data.errorId !== 0) {
logger.error('CapSolver', `API 返回错误: ${JSON.stringify(createTaskResponse.data)}`);
throw new Error(`创建任务失败: ${createTaskResponse.data.errorDescription}`);
}
const taskId = createTaskResponse.data.taskId;
logger.info('CapSolver', `任务创建成功 (ID: ${taskId})`);
// 2. 轮询获取结果
let attempts = 0;
const maxAttempts = 60; // 最多等待2分钟
while (attempts < maxAttempts) {
attempts++;
await this.delay(2000); // 每2秒查询一次
const getResultResponse = await axios.post(`${this.apiUrl}/getTaskResult`, {
clientKey: this.apiKey,
taskId: taskId
});
if (getResultResponse.data.errorId !== 0) {
throw new Error(`获取结果失败: ${getResultResponse.data.errorDescription}`);
}
const status = getResultResponse.data.status;
if (status === 'ready') {
const token = getResultResponse.data.solution.gRecaptchaResponse;
logger.success('CapSolver', `✓ hCaptcha 识别成功!(耗时: ${attempts * 2}秒)`);
return token;
}
if (status === 'failed') {
throw new Error('CapSolver 识别失败');
}
// status === 'processing'
if (attempts % 5 === 0) {
logger.info('CapSolver', `识别中... (${attempts * 2}/${maxAttempts * 2}秒)`);
}
}
throw new Error('CapSolver 识别超时2分钟');
} catch (error) {
// 详细的错误日志
if (error.response) {
// API 返回了错误响应
logger.error('CapSolver', `HTTP ${error.response.status}: ${error.response.statusText}`);
logger.error('CapSolver', `响应数据: ${JSON.stringify(error.response.data)}`);
if (error.response.status === 400) {
logger.error('CapSolver', '可能原因:');
logger.error('CapSolver', ' 1. API Key 无效或已过期');
logger.error('CapSolver', ' 2. 余额不足');
logger.error('CapSolver', ' 3. siteKey 或 URL 格式错误');
}
} else if (error.request) {
// 请求已发送但没有收到响应
logger.error('CapSolver', '无法连接到 CapSolver API');
} else {
// 其他错误
logger.error('CapSolver', `识别失败: ${error.message}`);
}
throw error;
}
}
/**
* 解决 Cloudflare Turnstile
* @param {string} siteKey - 网站的 siteKey
* @param {string} pageUrl - 当前页面URL
* @returns {Promise<string>} token
*/
async solveTurnstile(siteKey, pageUrl) {
if (!this.apiKey) {
throw new Error('CapSolver API Key 未配置');
}
logger.info('CapSolver', '开始识别 Turnstile...');
logger.info('CapSolver', `SiteKey: ${siteKey.substring(0, 20)}...`);
try {
// 1. 创建任务
const createTaskResponse = await axios.post(`${this.apiUrl}/createTask`, {
clientKey: this.apiKey,
task: {
type: 'AntiTurnstileTaskProxyLess',
websiteURL: pageUrl,
websiteKey: siteKey
}
});
if (createTaskResponse.data.errorId !== 0) {
throw new Error(`创建任务失败: ${createTaskResponse.data.errorDescription}`);
}
const taskId = createTaskResponse.data.taskId;
logger.info('CapSolver', `任务创建成功 (ID: ${taskId})`);
// 2. 轮询获取结果
let attempts = 0;
const maxAttempts = 60; // 最多等待2分钟
while (attempts < maxAttempts) {
attempts++;
await this.delay(2000);
const getResultResponse = await axios.post(`${this.apiUrl}/getTaskResult`, {
clientKey: this.apiKey,
taskId: taskId
});
if (getResultResponse.data.errorId !== 0) {
throw new Error(`获取结果失败: ${getResultResponse.data.errorDescription}`);
}
const status = getResultResponse.data.status;
if (status === 'ready') {
const token = getResultResponse.data.solution.token;
logger.success('CapSolver', `✓ Turnstile 识别成功!(耗时: ${attempts * 2}秒)`);
return token;
}
if (status === 'failed') {
throw new Error('CapSolver 识别失败');
}
if (attempts % 5 === 0) {
logger.info('CapSolver', `识别中... (${attempts * 2}/${maxAttempts * 2}秒)`);
}
}
throw new Error('CapSolver 识别超时2分钟');
} catch (error) {
logger.error('CapSolver', `识别失败: ${error.message}`);
throw error;
}
}
/**
* 检查余额
*/
async getBalance() {
if (!this.apiKey) {
throw new Error('CapSolver API Key 未配置');
}
try {
const response = await axios.post(`${this.apiUrl}/getBalance`, {
clientKey: this.apiKey
});
if (response.data.errorId !== 0) {
throw new Error(`获取余额失败: ${response.data.errorDescription}`);
}
const balance = response.data.balance;
logger.info('CapSolver', `账户余额: $${balance}`);
return balance;
} catch (error) {
logger.error('CapSolver', `获取余额失败: ${error.message}`);
throw error;
}
}
/**
* 延迟函数
*/
async delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
module.exports = CapSolverAPI;