This commit is contained in:
dengqichen 2025-11-17 17:53:28 +08:00
parent fb68de0206
commit 06d39edb64
3 changed files with 241 additions and 3 deletions

29
batch-start.js Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env node
/**
* 批量注册启动脚本
*/
require('dotenv').config();
const BatchRegister = require('./src/tools/account-register/batch-register');
// 配置你的3个 AdsPower Profile ID
const PROFILES = [
'k172d58u',
'k172d4mb',
'k1728p8l'
];
// 启动批量注册
const batch = new BatchRegister({
profiles: PROFILES, // 3个profile
concurrency: 1, // 并发3个
maxCount: Infinity, // 无限循环
delayBetweenRuns: 10000, // 批次间隔10秒
maxRetries: 3, // 单次失败重试3次
retryDelay: 30000 // 重试间隔30秒
});
batch.start().catch(error => {
console.error('批量注册异常:', error);
process.exit(1);
});

View File

@ -0,0 +1,206 @@
/**
* Batch Register - 批量自动注册支持并发
*/
const logger = require('../../shared/logger');
const WindsurfRegister = require('./sites/windsurf');
class BatchRegister {
constructor(options = {}) {
// AdsPower profile配置
this.profiles = options.profiles || [process.env.ADSPOWER_USER_ID];
this.concurrency = Math.min(options.concurrency || 1, this.profiles.length);
// 执行配置
this.maxCount = options.maxCount || Infinity;
this.delayBetweenRuns = options.delayBetweenRuns || 10000;
this.maxRetries = options.maxRetries || 3;
this.retryDelay = options.retryDelay || 30000;
// 统计数据
this.stats = {
total: 0,
success: 0,
failed: 0,
running: 0,
startTime: null
};
this.running = false;
}
/**
* 执行单次注册带重试
*/
async runOnce(profileId, taskId) {
let retryCount = 0;
while (retryCount < this.maxRetries) {
try {
logger.info('BatchRegister', `\n${'='.repeat(60)}`);
logger.info('BatchRegister', `[任务${taskId}] 使用Profile: ${profileId}`);
logger.info('BatchRegister', `[任务${taskId}] 第 ${this.stats.total + 1} 次注册 (重试: ${retryCount}/${this.maxRetries})`);
logger.info('BatchRegister', `${'='.repeat(60)}\n`);
this.stats.running++;
const register = new WindsurfRegister({ adspowerUserId: profileId });
const result = await register.register();
this.stats.running--;
if (result.success) {
this.stats.success++;
logger.success('BatchRegister', `[任务${taskId}] ✓ 注册成功!邮箱: ${result.account.email}`);
return true;
}
} catch (error) {
this.stats.running--;
retryCount++;
logger.error('BatchRegister', `[任务${taskId}] 注册失败: ${error.message}`);
if (retryCount < this.maxRetries) {
logger.warn('BatchRegister', `[任务${taskId}] ${this.retryDelay/1000}秒后进行第 ${retryCount + 1} 次重试...`);
await this.delay(this.retryDelay);
}
}
}
// 所有重试都失败
this.stats.failed++;
logger.error('BatchRegister', `[任务${taskId}] ✗ 注册失败,已达最大重试次数 (${this.maxRetries})`);
return false;
}
/**
* 延迟函数
*/
async delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* 格式化时长
*/
formatDuration(ms) {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours > 0) {
return `${hours}小时${minutes % 60}分钟`;
} else if (minutes > 0) {
return `${minutes}分钟${seconds % 60}`;
} else {
return `${seconds}`;
}
}
/**
* 打印统计信息
*/
printStats() {
const duration = Date.now() - this.stats.startTime;
const successRate = this.stats.total > 0
? ((this.stats.success / this.stats.total) * 100).toFixed(2)
: 0;
logger.info('BatchRegister', '\n' + '='.repeat(60));
logger.info('BatchRegister', '📊 批量注册统计');
logger.info('BatchRegister', '='.repeat(60));
logger.info('BatchRegister', `⏱️ 运行时长: ${this.formatDuration(duration)}`);
logger.info('BatchRegister', `🔄 并发数: ${this.concurrency} (Profiles: ${this.profiles.length}个)`);
logger.info('BatchRegister', `🏃 运行中: ${this.stats.running}`);
logger.info('BatchRegister', `📈 总次数: ${this.stats.total}`);
logger.info('BatchRegister', `✅ 成功: ${this.stats.success} (${successRate}%)`);
logger.info('BatchRegister', `❌ 失败: ${this.stats.failed}`);
logger.info('BatchRegister', `⚡ 平均耗时: ${this.stats.total > 0 ? this.formatDuration(duration / this.stats.total) : '0秒'}`);
logger.info('BatchRegister', '='.repeat(60) + '\n');
}
/**
* 启动批量注册并发版本
*/
async start() {
this.running = true;
this.stats.startTime = Date.now();
logger.info('BatchRegister', '\n🚀 批量注册启动');
logger.info('BatchRegister', `目标次数: ${this.maxCount === Infinity ? '无限' : this.maxCount}`);
logger.info('BatchRegister', `并发数: ${this.concurrency}`);
logger.info('BatchRegister', `Profiles: ${this.profiles.join(', ')}`);
logger.info('BatchRegister', `注册间隔: ${this.delayBetweenRuns/1000}`);
logger.info('BatchRegister', `单次重试: ${this.maxRetries}\n`);
// 捕获 Ctrl+C
process.on('SIGINT', async () => {
logger.warn('BatchRegister', '\n\n⚠ 收到停止信号,等待当前任务完成...');
this.running = false;
});
// 并发控制:使用 profile 池
const tasks = [];
let profileIndex = 0;
while (this.running && this.stats.total < this.maxCount) {
// 如果当前运行任务数 < 并发数,启动新任务
while (tasks.length < this.concurrency && this.stats.total < this.maxCount && this.running) {
this.stats.total++;
const taskId = this.stats.total;
const profileId = this.profiles[profileIndex % this.profiles.length];
profileIndex++;
const task = this.runOnce(profileId, taskId).then((success) => {
// 任务完成后,从任务列表中移除
const index = tasks.indexOf(task);
if (index > -1) {
tasks.splice(index, 1);
}
return success;
});
tasks.push(task);
// 短暂延迟,避免同时启动
await this.delay(1000);
}
// 等待至少一个任务完成
if (tasks.length > 0) {
await Promise.race(tasks);
}
// 定期打印统计每完成5次
if (this.stats.total % 5 === 0 && tasks.length === 0) {
this.printStats();
}
// 任务间隔
if (tasks.length === 0 && this.running && this.stats.total < this.maxCount) {
logger.info('BatchRegister', `⏳ 等待 ${this.delayBetweenRuns/1000} 秒后继续...\n`);
await this.delay(this.delayBetweenRuns);
}
}
// 等待所有剩余任务完成
if (tasks.length > 0) {
logger.info('BatchRegister', `等待 ${tasks.length} 个任务完成...`);
await Promise.all(tasks);
}
// 结束统计
this.printStats();
logger.success('BatchRegister', '🎉 批量注册完成!');
}
/**
* 停止批量注册
*/
stop() {
this.running = false;
logger.warn('BatchRegister', '⚠️ 正在停止批量注册...');
}
}
module.exports = BatchRegister;

View File

@ -20,7 +20,7 @@ const CardGenerator = require('../../card-generator/generator');
const database = require('../../database');
class WindsurfRegister {
constructor() {
constructor(options = {}) {
this.siteName = 'Windsurf';
this.siteUrl = 'https://windsurf.com/account/register';
this.dataGen = new AccountDataGenerator();
@ -31,6 +31,9 @@ class WindsurfRegister {
this.currentStep = 0;
this.accountData = null;
// AdsPower配置支持多profile并发
this.adspowerUserId = options.adspowerUserId || process.env.ADSPOWER_USER_ID;
// 记录注册时间和额外信息
this.registrationTime = null;
this.quotaInfo = null;
@ -194,12 +197,12 @@ class WindsurfRegister {
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
// 检查 AdsPower 配置
const adspowerUserId = process.env.ADSPOWER_USER_ID;
const adspowerUserId = this.adspowerUserId;
if (!adspowerUserId) {
logger.error(this.siteName, '');
logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID');
logger.error(this.siteName, '');
logger.error(this.siteName, '请在 .env 文件中配置');
logger.error(this.siteName, '请在 .env 文件中配置或传入 options.adspowerUserId');
logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id');
logger.error(this.siteName, '');
throw new Error('未配置 AdsPower 用户ID');