This commit is contained in:
dengqichen 2025-11-17 18:15:04 +08:00
parent 82d62145f1
commit 13cd9fbb49
2 changed files with 230 additions and 146 deletions

View File

@ -19,6 +19,7 @@ const { DEFAULT_CONFIG } = require('../config');
const CardGenerator = require('../../card-generator/generator');
const database = require('../../database');
const CapSolverAPI = require('../utils/capsolver-api');
const BrowserManager = require('../utils/browser-manager');
class WindsurfRegister {
constructor(options = {}) {
@ -28,14 +29,17 @@ class WindsurfRegister {
this.human = new HumanBehavior();
this.emailService = new EmailVerificationService();
this.capsolver = new CapSolverAPI();
// 浏览器管理器支持多profile并发
this.browserManager = new BrowserManager({
profileId: options.adspowerUserId || process.env.ADSPOWER_USER_ID,
siteName: this.siteName
});
this.browser = null;
this.page = null;
this.currentStep = 0;
this.accountData = null;
// AdsPower配置支持多profile并发
this.adspowerUserId = options.adspowerUserId || process.env.ADSPOWER_USER_ID;
// 记录注册时间和额外信息
this.registrationTime = null;
this.quotaInfo = null;
@ -190,114 +194,22 @@ class WindsurfRegister {
}
/**
* 初始化浏览器 - 使用 AdsPower 指纹浏览器
* 初始化浏览器
*/
async initBrowser(options = {}) {
const puppeteer = require('puppeteer');
const axios = require('axios');
async initBrowser() {
const result = await this.browserManager.launch();
this.browser = result.browser;
this.page = result.page;
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
// 检查 AdsPower 配置
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 文件中配置或传入 options.adspowerUserId');
logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id');
logger.error(this.siteName, '');
throw new Error('未配置 AdsPower 用户ID');
}
const apiBase = process.env.ADSPOWER_API || 'http://local.adspower.net:50325';
const apiKey = process.env.ADSPOWER_API_KEY;
const startUrl = `${apiBase}/api/v1/browser/start?user_id=${encodeURIComponent(adspowerUserId)}`;
// 配置请求头
const headers = {};
if (apiKey && apiKey.trim()) {
headers['Authorization'] = `Bearer ${apiKey}`;
logger.info(this.siteName, '✓ 使用 API Key 认证');
}
logger.info(this.siteName, ` → 启动 AdsPower 配置: ${adspowerUserId}`);
try {
const response = await axios.get(startUrl, { headers });
const data = response.data;
if (data.code !== 0) {
logger.error(this.siteName, '');
logger.error(this.siteName, `AdsPower API 返回错误: ${JSON.stringify(data)}`);
logger.error(this.siteName, '');
logger.error(this.siteName, '解决方案:');
logger.error(this.siteName, '1. 确保 AdsPower 应用已启动并登录');
logger.error(this.siteName, '2. 检查配置文件 ID 是否正确: ' + adspowerUserId);
logger.error(this.siteName, '3. 如果需要 API Key请在 AdsPower 设置中生成');
logger.error(this.siteName, '4. 尝试在 AdsPower 中手动打开一次浏览器配置');
logger.error(this.siteName, '');
throw new Error(`AdsPower 启动失败: ${data.msg || JSON.stringify(data)}`);
}
// 获取 WebSocket 端点
const wsEndpoint = data.data.ws && (
data.data.ws.puppeteer ||
data.data.ws.selenium ||
data.data.ws.ws ||
data.data.ws
);
if (!wsEndpoint) {
throw new Error('AdsPower 未返回 WebSocket 端点');
}
logger.info(this.siteName, ` → WebSocket: ${wsEndpoint}`);
// 连接到 AdsPower 浏览器
this.browser = await puppeteer.connect({
browserWSEndpoint: wsEndpoint,
defaultViewport: null
});
// 获取已存在的页面
const pages = await this.browser.pages();
this.page = pages[0] || await this.browser.newPage();
// 关闭多余的标签页AdsPower 需要至少保留一个)
if (pages.length > 1) {
for (let i = 1; i < pages.length; i++) {
try {
await pages[i].close();
} catch (e) {
// 忽略关闭失败
}
}
}
logger.success(this.siteName, '✓ AdsPower 浏览器连接成功');
logger.info(this.siteName, '✓ 使用真实指纹,可同时绕过 Cloudflare 和 Stripe');
logger.info(this.siteName, '等待浏览器完全准备...');
await this.human.randomDelay(2000, 3000);
} catch (error) {
logger.error(this.siteName, '');
logger.error(this.siteName, `❌ AdsPower 连接失败: ${error.message}`);
logger.error(this.siteName, '');
throw error;
}
logger.info(this.siteName, '等待浏览器完全准备...');
await this.human.randomDelay(2000, 3000);
}
/**
* 关闭浏览器
*/
async closeBrowser() {
if (this.browser) {
await this.browser.close();
logger.info(this.siteName, '浏览器已关闭');
}
await this.browserManager.close();
}
/**
@ -1417,49 +1329,7 @@ class WindsurfRegister {
logger.info(this.siteName, `[步骤 9/${this.getTotalSteps()}] 清理并关闭浏览器`);
try {
// 清除所有浏览器数据(类似 Ctrl+Shift+Delete
logger.info(this.siteName, ' → 清除所有浏览器数据Cookies、Cache、Storage等...');
try {
// 使用 Chrome DevTools Protocol 进行深度清理
const client = await this.page.target().createCDPSession();
// 1. 清除浏览器 Cookies
await client.send('Network.clearBrowserCookies');
logger.success(this.siteName, ' → ✓ 已清除所有 Cookies');
// 2. 清除浏览器缓存
await client.send('Network.clearBrowserCache');
logger.success(this.siteName, ' → ✓ 已清除浏览器缓存');
// 3. 清除所有存储数据localStorage, sessionStorage, IndexedDB, WebSQL, Cache Storage, Service Workers
await client.send('Storage.clearDataForOrigin', {
origin: '*',
storageTypes: 'all'
});
logger.success(this.siteName, ' → ✓ 已清除所有存储数据');
// 4. 额外清理:访问目标网站并清除其存储
await this.page.goto('https://windsurf.com', { waitUntil: 'domcontentloaded' });
await this.page.evaluate(() => {
try {
localStorage.clear();
sessionStorage.clear();
} catch (e) {}
});
// 5. 关闭 CDP 会话
await client.detach();
logger.success(this.siteName, ' → ✓ 浏览器数据清除完成(全新状态)');
} catch (e) {
logger.warn(this.siteName, ` → 清除浏览器数据失败: ${e.message}`);
}
// 关闭浏览器
logger.info(this.siteName, ' → 关闭浏览器...');
await this.closeBrowser();
logger.success(this.siteName, ' → ✓ 浏览器已关闭');
await this.browserManager.clearAndClose();
this.currentStep = 9;
logger.success(this.siteName, `步骤 9 完成`);

View File

@ -0,0 +1,214 @@
/**
* Browser Manager - AdsPower 指纹浏览器管理器
* 统一管理浏览器的启动连接关闭等操作
*/
const puppeteer = require('puppeteer');
const axios = require('axios');
const logger = require('../../../shared/logger');
class BrowserManager {
constructor(options = {}) {
this.profileId = options.profileId || process.env.ADSPOWER_USER_ID;
this.apiBase = options.apiBase || process.env.ADSPOWER_API || 'http://local.adspower.net:50325';
this.apiKey = options.apiKey || process.env.ADSPOWER_API_KEY;
this.siteName = options.siteName || 'Browser';
this.browser = null;
this.page = null;
}
/**
* 启动 AdsPower 浏览器
*/
async launch() {
logger.info(this.siteName, '启动 AdsPower 指纹浏览器...');
// 检查配置
if (!this.profileId) {
logger.error(this.siteName, '');
logger.error(this.siteName, '❌ 未配置 ADSPOWER_USER_ID');
logger.error(this.siteName, '');
logger.error(this.siteName, '请在 .env 文件中配置或传入 profileId');
logger.error(this.siteName, 'ADSPOWER_USER_ID=your_profile_id');
logger.error(this.siteName, '');
throw new Error('未配置 AdsPower 用户ID');
}
const startUrl = `${this.apiBase}/api/v1/browser/start?user_id=${encodeURIComponent(this.profileId)}`;
// 配置请求头
const headers = {};
if (this.apiKey && this.apiKey.trim()) {
headers['Authorization'] = `Bearer ${this.apiKey}`;
logger.info(this.siteName, '✓ 使用 API Key 认证');
}
logger.info(this.siteName, ` → 启动 AdsPower 配置: ${this.profileId}`);
try {
const response = await axios.get(startUrl, { headers });
const data = response.data;
if (data.code !== 0) {
logger.error(this.siteName, '');
logger.error(this.siteName, `AdsPower API 返回错误: ${JSON.stringify(data)}`);
logger.error(this.siteName, '');
logger.error(this.siteName, '解决方案:');
logger.error(this.siteName, '1. 确保 AdsPower 应用已启动并登录');
logger.error(this.siteName, `2. 检查配置文件 ID 是否正确: ${this.profileId}`);
logger.error(this.siteName, '3. 如果需要 API Key请在 AdsPower 设置中生成');
logger.error(this.siteName, '4. 尝试在 AdsPower 中手动打开一次浏览器配置');
logger.error(this.siteName, '');
throw new Error(`AdsPower 启动失败: ${data.msg || JSON.stringify(data)}`);
}
// 获取 WebSocket 端点
const wsEndpoint = data.data.ws && (
data.data.ws.puppeteer ||
data.data.ws.selenium ||
data.data.ws.ws ||
data.data.ws
);
if (!wsEndpoint) {
throw new Error('AdsPower 未返回 WebSocket 端点');
}
logger.info(this.siteName, ` → WebSocket: ${wsEndpoint}`);
// 连接到 AdsPower 浏览器
this.browser = await puppeteer.connect({
browserWSEndpoint: wsEndpoint,
defaultViewport: null
});
// 获取已存在的页面
const pages = await this.browser.pages();
this.page = pages[0] || await this.browser.newPage();
// 关闭多余的标签页
if (pages.length > 1) {
for (let i = 1; i < pages.length; i++) {
try {
await pages[i].close();
} catch (e) {
// 忽略关闭失败
}
}
}
logger.success(this.siteName, '✓ AdsPower 浏览器连接成功');
logger.info(this.siteName, '✓ 使用真实指纹,可同时绕过 Cloudflare 和 Stripe');
return { browser: this.browser, page: this.page };
} catch (error) {
logger.error(this.siteName, '');
logger.error(this.siteName, `❌ AdsPower 连接失败: ${error.message}`);
logger.error(this.siteName, '');
throw error;
}
}
/**
* 获取当前页面
*/
getPage() {
if (!this.page) {
throw new Error('浏览器页面未初始化,请先调用 launch()');
}
return this.page;
}
/**
* 获取浏览器实例
*/
getBrowser() {
if (!this.browser) {
throw new Error('浏览器未初始化,请先调用 launch()');
}
return this.browser;
}
/**
* 清除浏览器数据
*/
async clearData() {
if (!this.page) {
logger.warn(this.siteName, '页面未初始化,跳过清除数据');
return;
}
logger.info(this.siteName, ' → 清除所有浏览器数据Cookies、Cache、Storage等...');
try {
const client = await this.page.target().createCDPSession();
// 1. 清除浏览器 Cookies
await client.send('Network.clearBrowserCookies');
logger.success(this.siteName, ' → ✓ 已清除所有 Cookies');
// 2. 清除浏览器缓存
await client.send('Network.clearBrowserCache');
logger.success(this.siteName, ' → ✓ 已清除浏览器缓存');
// 3. 清除所有存储数据
await client.send('Storage.clearDataForOrigin', {
origin: '*',
storageTypes: 'all'
});
logger.success(this.siteName, ' → ✓ 已清除所有存储数据');
// 4. 额外清理:访问目标网站并清除其存储
const currentUrl = this.page.url();
if (currentUrl && currentUrl.startsWith('http')) {
await this.page.evaluate(() => {
try {
localStorage.clear();
sessionStorage.clear();
} catch (e) {}
});
}
// 5. 关闭 CDP 会话
await client.detach();
logger.success(this.siteName, ' → ✓ 浏览器数据清除完成(全新状态)');
} catch (e) {
logger.warn(this.siteName, ` → 清除浏览器数据失败: ${e.message}`);
}
}
/**
* 关闭浏览器
*/
async close() {
if (!this.browser) {
logger.warn(this.siteName, '浏览器未初始化,无需关闭');
return;
}
try {
logger.info(this.siteName, ' → 关闭浏览器...');
await this.browser.disconnect();
this.browser = null;
this.page = null;
logger.success(this.siteName, ' → ✓ 浏览器已关闭');
} catch (error) {
logger.error(this.siteName, `关闭浏览器失败: ${error.message}`);
throw error;
}
}
/**
* 清除数据并关闭浏览器
*/
async clearAndClose() {
await this.clearData();
await this.close();
}
}
module.exports = BrowserManager;