From 29d96742acf5a2242e43510bd6020181efe1608c Mon Sep 17 00:00:00 2001 From: dengqichen Date: Mon, 17 Nov 2025 16:37:32 +0800 Subject: [PATCH] dasdasd --- .env | 3 - src/tools/account-register/sites/windsurf.js | 746 ++----------------- 2 files changed, 68 insertions(+), 681 deletions(-) diff --git a/.env b/.env index 5479cf6..344dd71 100644 --- a/.env +++ b/.env @@ -1,6 +1,3 @@ -# CapSolver API Key -CAPSOLVER_API_KEY=CAP-0FCDDA4906E87D9F4FF68EAECD34E320876FBA70E4F30EA1ADCD264EDB15E4BF - # AdsPower 指纹浏览器配置 ADSPOWER_USER_ID=k1728p8l ADSPOWER_API_KEY=35de43696f6241f3df895f2f48777a99 diff --git a/src/tools/account-register/sites/windsurf.js b/src/tools/account-register/sites/windsurf.js index 816c42b..a60c25f 100644 --- a/src/tools/account-register/sites/windsurf.js +++ b/src/tools/account-register/sites/windsurf.js @@ -17,7 +17,6 @@ const logger = require('../../../shared/logger'); const EmailVerificationService = require('../email-verification'); const { DEFAULT_CONFIG } = require('../config'); const CardGenerator = require('../../card-generator/generator'); -const axios = require('axios'); class WindsurfRegister { constructor() { @@ -31,14 +30,6 @@ class WindsurfRegister { this.currentStep = 0; this.accountData = null; - // 初始化 CapSolver(自动解决 Cloudflare Turnstile) - this.capsolverKey = process.env.CAPSOLVER_API_KEY || null; - if (this.capsolverKey) { - logger.success(this.siteName, '✓ CapSolver 自动化已启用(99%+ 成功率)'); - } else { - logger.warn(this.siteName, '⚠️ 未配置 CAPSOLVER_API_KEY,将使用手动验证'); - } - // 定义所有步骤 this.steps = [ { id: 1, name: '填写基本信息', method: 'step1_fillBasicInfo' }, @@ -316,16 +307,6 @@ class WindsurfRegister { logger.warn(this.siteName, ` → 清除浏览器数据失败: ${e.message}`); } - // 提示:AdsPower 中需要手动安装 CapSolver 扩展 - logger.info(this.siteName, ''); - logger.info(this.siteName, '💡 提示:'); - logger.info(this.siteName, ' AdsPower 指纹浏览器已启动'); - if (this.capsolverKey) { - logger.info(this.siteName, ' 请确保已在 AdsPower 配置中安装 CapSolver 扩展'); - logger.info(this.siteName, ' 扩展路径: extensions/capsolver'); - } - logger.info(this.siteName, ''); - logger.info(this.siteName, '等待浏览器完全准备...'); await this.human.randomDelay(2000, 3000); @@ -511,72 +492,41 @@ class WindsurfRegister { await this.page.keyboard.press('Enter'); } - // 等待页面稳定(优化:减少等待时间) - await this.human.randomDelay(500, 1000); + // 等待页面稳定 + await this.human.randomDelay(1000, 2000); - // ===== Cloudflare Turnstile 验证处理 ===== + // 等待 Cloudflare Turnstile 验证完成(手动或其他方式) + logger.info(this.siteName, ' → 等待 Cloudflare Turnstile 验证...'); + logger.info(this.siteName, ' → 请手动完成验证或等待自动处理...'); - // 首先检查Turnstile API是否加载成功 - logger.info(this.siteName, ' → 检查 Cloudflare Turnstile API 加载状态...'); - const turnstileApiStatus = await this.page.evaluate(() => { - return { - hasTurnstile: typeof window.turnstile !== 'undefined', - hasCallback: typeof window.cf__reactTurnstileOnLoad !== 'undefined', - scripts: Array.from(document.querySelectorAll('script')).map(s => s.src).filter(src => src.includes('turnstile') || src.includes('cloudflare')) - }; - }); + const startTime = Date.now(); + const maxWait = 120000; // 最多等待120秒 - if (turnstileApiStatus.hasTurnstile) { - logger.success(this.siteName, ' → ✓ Turnstile API 已成功加载'); - } else { - logger.error(this.siteName, ' → ⚠️ Turnstile API 未加载!'); - logger.error(this.siteName, ' → 检测到的脚本: ' + JSON.stringify(turnstileApiStatus.scripts)); - logger.warn(this.siteName, ' → 可能原因:'); - logger.warn(this.siteName, ' 1. 网络问题(Cloudflare CDN 在中国大陆可能不稳定)'); - logger.warn(this.siteName, ' 2. 浏览器扩展阻止了脚本加载'); - logger.warn(this.siteName, ' 3. 防火墙/代理问题'); - logger.warn(this.siteName, ' → 建议:检查网络连接或使用VPN/代理'); - logger.info(this.siteName, ' → 等待30秒看是否能延迟加载...'); - await this.human.randomDelay(30000, 30000); + // 轮询检查按钮是否激活 + while (Date.now() - startTime < maxWait) { + const buttonEnabled = await this.page.evaluate(() => { + const button = document.querySelector('button'); + return button && !button.disabled && button.textContent.trim() === 'Continue'; + }); + + if (buttonEnabled) { + const duration = ((Date.now() - startTime) / 1000).toFixed(1); + logger.success(this.siteName, ` → ✓ Turnstile 验证完成!耗时: ${duration}秒`); + break; + } + + // 每10秒输出一次进度 + const elapsed = Date.now() - startTime; + if (elapsed > 0 && elapsed % 10000 === 0) { + logger.info(this.siteName, ` → 等待验证中... 已用时 ${elapsed/1000}秒`); + } + + await new Promise(resolve => setTimeout(resolve, 500)); } - // 如果配置了 CapSolver 扩展,等待扩展自动处理验证 - if (this.capsolverKey) { - logger.info(this.siteName, ' → 检测到 Cloudflare Turnstile 验证'); - logger.info(this.siteName, ' → 等待 CapSolver 扩展处理(请确保已在 AdsPower 中安装扩展)...'); - - const startTime = Date.now(); - let elapsed = 0; - const maxWait = 60000; // 最多等待60秒 - - // 轮询检查按钮是否激活(扩展完成验证后按钮会变绿) - while (elapsed < maxWait) { - const buttonEnabled = await this.page.evaluate(() => { - const button = document.querySelector('button'); - return button && !button.disabled && button.textContent.trim() === 'Continue'; - }); - - if (buttonEnabled) { - const duration = ((Date.now() - startTime) / 1000).toFixed(1); - logger.success(this.siteName, ` → ✓ Turnstile 验证完成!耗时: ${duration}秒`); - logger.success(this.siteName, ' → ✓ 按钮已激活,准备进入下一步'); - break; - } - - // 每10秒输出一次进度 - if (elapsed > 0 && elapsed % 10000 === 0) { - logger.info(this.siteName, ` → 等待验证中... 已用时 ${elapsed/1000}秒`); - } - - // 优化:减少轮询间隔,更快检测到完成状态 - await new Promise(resolve => setTimeout(resolve, 500)); - elapsed = Date.now() - startTime; - } - - if (elapsed >= maxWait) { - logger.error(this.siteName, ' → ⚠️ 验证超时(60秒),可能需要手动处理'); - throw new Error('Turnstile 验证超时'); - } + if (Date.now() - startTime >= maxWait) { + logger.error(this.siteName, ' → ⚠️ 验证超时(120秒)'); + throw new Error('Turnstile 验证超时'); } // 点击 Continue 进入邮箱验证 @@ -593,595 +543,13 @@ class WindsurfRegister { logger.success(this.siteName, `步骤 2 完成`); } - /** - * 使用 CapSolver 自动解决 Cloudflare Turnstile(使用 node-capsolver 库) - * @deprecated 此方法已废弃,现在使用 CapSolver 浏览器扩展自动处理 - * API 方式只能获取 token,无法让 Turnstile checkbox 自动勾选 - * 扩展方式可以直接操作页面元素,实现真正的自动化 - */ - async solveWithCapSolver() { - if (!this.capsolverKey) { - return false; // 未配置,返回 false - } - - try { - logger.info(this.siteName, '[CapSolver] 开始自动解决 Cloudflare Turnstile...'); - - const websiteURL = this.page.url(); - logger.info(this.siteName, `[CapSolver] 页面 URL: ${websiteURL}`); - - // 先快速检查页面上是否真的有 Turnstile(不等待) - const hasTurnstile = await this.page.evaluate(() => { - return !!( - document.querySelector('iframe[src*="challenges.cloudflare.com"]') || - document.querySelector('iframe[src*="turnstile"]') || - document.querySelector('[data-sitekey]') || - document.querySelector('input[name="cf-turnstile-response"]') - ); - }); - - if (!hasTurnstile) { - logger.info(this.siteName, '[CapSolver] 当前页面没有 Turnstile,跳过'); - return false; - } - - logger.info(this.siteName, '[CapSolver] 检测到 Turnstile,开始处理...'); - - // 等待 Turnstile 完全加载(检查多种可能的选择器) - logger.info(this.siteName, '[CapSolver] 等待 Turnstile 完全加载...'); - let turnstileLoaded = false; - - // 尝试多种选择器(缩短超时时间) - const selectors = [ - 'iframe[src*="challenges.cloudflare.com"]', // Turnstile iframe - 'iframe[title*="Turnstile"]', // Turnstile by title - 'iframe[id^="cf-chl-widget"]', // Cloudflare challenge widget - '[id^="cf-chl-widget"]', // Turnstile container - 'input[name="cf-turnstile-response"]' // Turnstile hidden input - ]; - - for (const selector of selectors) { - try { - await this.page.waitForSelector(selector, { timeout: 3000 }); - logger.info(this.siteName, `[CapSolver] ✓ 找到 Turnstile 元素: ${selector}`); - turnstileLoaded = true; - break; - } catch (e) { - // 继续尝试下一个选择器 - } - } - - if (turnstileLoaded) { - // 额外等待 3 秒,确保 Turnstile 完全初始化 - await new Promise(resolve => setTimeout(resolve, 3000)); - logger.info(this.siteName, '[CapSolver] ✓ Turnstile 初始化完成'); - } else { - logger.warn(this.siteName, '[CapSolver] Turnstile 元素未完全加载,尝试继续'); - await new Promise(resolve => setTimeout(resolve, 2000)); - } - - const sitekeyInfo = await this.page.evaluate(() => { - const info = { sitekey: null, method: null, widgetId: null }; - - // 方法 1: 从 iframe 中获取 - const iframe = document.querySelector('iframe[src*="cloudflare"]'); - if (iframe && iframe.src) { - const match = iframe.src.match(/sitekey=([^&]+)/); - if (match && match[1] !== 'explicit') { - info.sitekey = match[1]; - info.method = 'iframe-src'; - // 尝试获取 widget ID - const idMatch = iframe.id.match(/cf-chl-widget-(.+)/); - if (idMatch) info.widgetId = idMatch[1]; - } - } - - // 方法 2: 从 data-sitekey 属性获取 - if (!info.sitekey) { - const turnstileDiv = document.querySelector('[data-sitekey]'); - if (turnstileDiv) { - const key = turnstileDiv.getAttribute('data-sitekey'); - if (key && key !== 'explicit') { - info.sitekey = key; - info.method = 'data-sitekey'; - if (turnstileDiv.id) info.widgetId = turnstileDiv.id; - } - } - } - - // 方法 3: 从页面 JavaScript 中查找 - if (!info.sitekey) { - const scripts = Array.from(document.querySelectorAll('script')); - for (const script of scripts) { - if (script.textContent && script.textContent.includes('turnstile')) { - const match = script.textContent.match(/sitekey['":\s]+['"]([0-9x_A-Za-z-]+)['"]/); - if (match && match[1] !== 'explicit') { - info.sitekey = match[1]; - info.method = 'script'; - break; - } - } - } - } - - // 默认使用已知的 Windsurf sitekey(后备值) - if (!info.sitekey) { - info.sitekey = '0x4AAAAAAA447Bur1xJStKg5'; - info.method = 'fallback'; - } - - return info; - }); - - const sitekey = sitekeyInfo.sitekey; - - logger.info(this.siteName, `[CapSolver] Sitekey: ${sitekey} (来源: ${sitekeyInfo.method})`); - if (sitekeyInfo.widgetId) { - logger.info(this.siteName, `[CapSolver] Widget ID: ${sitekeyInfo.widgetId}`); - } - - // 严格按照官方文档创建任务 - const payload = { - clientKey: this.capsolverKey, - task: { - type: 'AntiTurnstileTaskProxyLess', - websiteKey: sitekey, - websiteURL: websiteURL, - metadata: { - action: '' // optional - } - } - }; - - logger.info(this.siteName, `[CapSolver] 创建任务...`); - const res = await axios.post("https://api.capsolver.com/createTask", payload); - const task_id = res.data.taskId; - - if (!task_id) { - logger.error(this.siteName, `[CapSolver] 创建任务失败: ${JSON.stringify(res.data)}`); - return false; - } - - logger.info(this.siteName, `[CapSolver] 任务ID: ${task_id}`); - - // 轮询获取结果 - let solution = null; - while (true) { - await new Promise(resolve => setTimeout(resolve, 1000)); // 1秒延迟 - - const getResultPayload = { clientKey: this.capsolverKey, taskId: task_id }; - const resp = await axios.post("https://api.capsolver.com/getTaskResult", getResultPayload); - const status = resp.data.status; - - if (status === "ready") { - solution = resp.data.solution; - break; - } - - if (status === "failed" || resp.data.errorId) { - logger.error(this.siteName, `[CapSolver] 解决失败: ${JSON.stringify(resp.data)}`); - return false; - } - } - - if (!solution || !solution.token) { - logger.error(this.siteName, `[CapSolver] 未获取到solution`); - return false; - } - - const token = solution.token; - const userAgent = solution.userAgent; - - logger.success(this.siteName, `[CapSolver] ✓ 获取到token: ${token.substring(0, 20)}...`); - logger.info(this.siteName, `[CapSolver] UserAgent: ${userAgent}`); - - // 先调试:查看页面上的 Turnstile 配置 - const debugInfo = await this.page.evaluate(() => { - const info = { - hasTurnstile: !!window.turnstile, - hasCallback: false, - callbackName: null, - widgetConfig: null - }; - - // 查找回调函数 - const scripts = Array.from(document.querySelectorAll('script')); - for (const script of scripts) { - if (script.textContent && script.textContent.includes('turnstile')) { - // 尝试找到 callback 配置 - const callbackMatch = script.textContent.match(/callback['":\s]*['"]?(\w+)['"]?/); - if (callbackMatch) { - info.hasCallback = true; - info.callbackName = callbackMatch[1]; - } - } - } - - return info; - }); - - logger.info(this.siteName, `[CapSolver] 调试信息: ${JSON.stringify(debugInfo)}`); - - // 3. 注入 token 到页面 - logger.info(this.siteName, '[CapSolver] 等待 input 元素...'); - await this.page.waitForSelector('input[name="cf-turnstile-response"]', { timeout: 10000 }); - - logger.info(this.siteName, `[CapSolver] 注入 token 到页面 (长度: ${token.length})...`); - - // 步骤1: 注入 token 并触发事件 - await this.page.evaluate((token) => { - const input = document.querySelector('input[name="cf-turnstile-response"]'); - if (input) { - input.value = token; - // 触发各种事件以通知页面 - ['input', 'change', 'blur'].forEach(eventType => { - input.dispatchEvent(new Event(eventType, { bubbles: true })); - }); - } - }, token); - - logger.success(this.siteName, '[CapSolver] ✓ Token 已注入到 hidden input'); - - // 步骤2: 查找并触发 Turnstile 回调函数 - logger.info(this.siteName, '[CapSolver] 尝试触发 Turnstile 回调...'); - - const callbackResult = await this.page.evaluate((token) => { - const results = []; - - // 方法A: 查找 React 组件的回调 - if (window.cf__reactTurnstileOnLoad && typeof window.cf__reactTurnstileOnLoad === 'function') { - try { - window.cf__reactTurnstileOnLoad(token); - results.push('✓ cf__reactTurnstileOnLoad'); - } catch (e) { - results.push(`✗ cf__reactTurnstileOnLoad: ${e.message}`); - } - } - - // 方法B: 从 DOM 元素获取回调名称 - const turnstileDiv = document.querySelector('[data-callback]'); - if (turnstileDiv) { - const callbackName = turnstileDiv.getAttribute('data-callback'); - if (callbackName && window[callbackName] && typeof window[callbackName] === 'function') { - try { - window[callbackName](token); - results.push(`✓ data-callback: ${callbackName}`); - } catch (e) { - results.push(`✗ ${callbackName}: ${e.message}`); - } - } - } - - // 方法C: 使用 turnstile API (如果存在) - if (window.turnstile) { - if (typeof window.turnstile.reset === 'function') { - try { - // 查找 widget ID - const widgets = document.querySelectorAll('[id^="cf-chl-widget"]'); - widgets.forEach((widget, index) => { - const widgetId = widget.id; - try { - window.turnstile.reset(widgetId); - results.push(`✓ reset widget: ${widgetId}`); - } catch (e) { - results.push(`✗ reset ${widgetId}: ${e.message}`); - } - }); - } catch (e) { - results.push(`✗ turnstile.reset: ${e.message}`); - } - } - - if (typeof window.turnstile.execute === 'function') { - try { - window.turnstile.execute(); - results.push('✓ turnstile.execute()'); - } catch (e) { - results.push(`✗ turnstile.execute: ${e.message}`); - } - } - } - - // 方法D: 遍历 window 查找包含 turnstile 的函数 - for (let key in window) { - if (key.toLowerCase().includes('turnstile') && - typeof window[key] === 'function' && - !results.some(r => r.includes(key))) { - try { - window[key](token); - results.push(`✓ window.${key}`); - } catch (e) { - // 忽略错误,继续尝试 - } - } - } - - return results; - }, token); - - if (callbackResult.length > 0) { - logger.info(this.siteName, `[CapSolver] 回调触发结果:`); - callbackResult.forEach(result => { - logger.info(this.siteName, ` ${result}`); - }); - } else { - logger.warn(this.siteName, '[CapSolver] ⚠️ 未找到任何回调函数'); - } - - // 等待一下让回调处理 - await new Promise(resolve => setTimeout(resolve, 1000)); - - // 步骤3: 强制激活按钮(后备方案) - logger.info(this.siteName, '[CapSolver] 检查并激活提交按钮...'); - - const buttonActivated = await this.page.evaluate(() => { - const buttons = Array.from(document.querySelectorAll('button')); - let activated = false; - - buttons.forEach(btn => { - if (btn.textContent.trim() === 'Continue' || - btn.textContent.trim() === 'Submit') { - if (btn.disabled) { - // 移除 disabled 属性 - btn.disabled = false; - btn.removeAttribute('disabled'); - - // 移除可能的 disabled class - btn.classList.remove('disabled'); - - activated = true; - } - } - }); - - return activated; - }); - - if (buttonActivated) { - logger.success(this.siteName, '[CapSolver] ✓ 已强制激活按钮'); - } else { - logger.info(this.siteName, '[CapSolver] 按钮已经是激活状态'); - } - - // 步骤4: 等待验证完成确认 - logger.info(this.siteName, '[CapSolver] 等待验证完成确认...'); - - try { - await this.page.waitForFunction( - () => { - // 检查1: 按钮必须激活 - const button = document.querySelector('button'); - const buttonEnabled = button && !button.disabled && - (button.textContent.trim() === 'Continue' || - button.textContent.trim() === 'Submit'); - - // 检查2: hidden input 必须有值 - const input = document.querySelector('[name="cf-turnstile-response"]'); - const hasToken = input && input.value && input.value.length > 0; - - // 检查3: iframe 状态(如果存在) - const iframe = document.querySelector('iframe[src*="challenges.cloudflare.com"]'); - const iframeOk = !iframe || - iframe.getAttribute('data-state') === 'success' || - iframe.getAttribute('data-success') === 'true'; - - // 至少满足:按钮激活 + 有token - return buttonEnabled && hasToken; - }, - { timeout: 10000, polling: 500 } - ); - - logger.success(this.siteName, '[CapSolver] ✓ 验证完成确认通过'); - - } catch (e) { - logger.warn(this.siteName, '[CapSolver] 验证完成检测超时,但将继续尝试...'); - - // 输出调试信息 - const debugInfo = await this.page.evaluate(() => { - const button = document.querySelector('button'); - const input = document.querySelector('[name="cf-turnstile-response"]'); - return { - buttonDisabled: button?.disabled, - buttonText: button?.textContent.trim(), - hasToken: !!input?.value, - tokenLength: input?.value?.length || 0 - }; - }); - - logger.info(this.siteName, `[CapSolver] 当前状态: ${JSON.stringify(debugInfo)}`); - - // 如果按钮已激活且有token,认为成功 - if (!debugInfo.buttonDisabled && debugInfo.hasToken) { - logger.success(this.siteName, '[CapSolver] ✓ 状态检查通过,继续执行'); - } else { - logger.warn(this.siteName, '[CapSolver] 等待 10 秒供手动处理...'); - await new Promise(resolve => setTimeout(resolve, 10000)); - } - } - - // 5. 点击 Continue 按钮 - await this.human.randomDelay(500, 1000); - const button = await this.page.$('button'); - if (button) { - await button.click(); - logger.success(this.siteName, '[CapSolver] ✓ 已点击 Continue 按钮'); - - // 等待页面跳转 - await this.human.randomDelay(3000, 4000); - return true; - } else { - logger.error(this.siteName, '[CapSolver] 未找到 Continue 按钮'); - return false; - } - - } catch (error) { - logger.error(this.siteName, `[CapSolver] 解决失败: ${error.message}`); - return false; - } - } - - /** - * Cloudflare Turnstile验证(步骤2.5)- 使用 CapSolver 扩展自动处理 - */ - async handleCloudflareVerification() { - // 如果安装了 CapSolver 扩展,等待其自动处理 - if (this.capsolverKey) { - logger.info(this.siteName, '[CapSolver扩展] 检测到 Cloudflare Turnstile 验证'); - logger.info(this.siteName, '[CapSolver扩展] 扩展将自动:检测 → 调用API → 勾选checkbox'); - - const startTime = Date.now(); - - // 按照官方文档:等待扩展自动处理(检查按钮是否激活) - try { - // 轮询检查按钮状态,提供实时反馈 - const checkInterval = 2000; // 每2秒检查一次 - let elapsed = 0; - - while (elapsed < 60000) { // 最多60秒 - const buttonEnabled = await this.page.evaluate(() => { - const button = document.querySelector('button'); - return button && !button.disabled; - }); - - if (buttonEnabled) { - const duration = ((Date.now() - startTime) / 1000).toFixed(1); - logger.success(this.siteName, `[CapSolver扩展] ✓ Turnstile 验证完成!耗时: ${duration}秒`); - logger.success(this.siteName, '[CapSolver扩展] ✓ Checkbox 已自动勾选,按钮已激活'); - return 'passed'; - } - - // 每10秒输出一次进度 - if (elapsed % 10000 === 0 && elapsed > 0) { - logger.info(this.siteName, `[CapSolver扩展] 等待中... 已用时 ${elapsed/1000}秒`); - } - - await new Promise(resolve => setTimeout(resolve, checkInterval)); - elapsed += checkInterval; - } - - // 超时 - logger.error(this.siteName, '[CapSolver扩展] ⚠️ 60秒超时,验证未完成'); - logger.warn(this.siteName, '可能原因:'); - logger.warn(this.siteName, ' 1. 扩展未正确加载(检查浏览器扩展图标)'); - logger.warn(this.siteName, ' 2. API Key 未配置或无效'); - logger.warn(this.siteName, ' 3. CapSolver 余额不足'); - logger.warn(this.siteName, ' 4. 网络连接问题'); - logger.warn(this.siteName, '回退到手动模式,请手动点击 Turnstile checkbox...'); - - } catch (e) { - logger.error(this.siteName, `[CapSolver扩展] 错误: ${e.message}`); - } - } - - // 回退到手动模式 - const cloudflareMode = DEFAULT_CONFIG.cloudflare.mode; - - // 自定义检测函数:检查Continue按钮是否激活 - const customCheck = async () => { - try { - const buttonEnabled = await this.page.evaluate(() => { - const button = document.querySelector('button'); - return button && !button.disabled; - }); - return buttonEnabled; - } catch (e) { - return false; - } - }; - - const handler = new CloudflareHandler(this.page, this.human, this.siteName, cloudflareMode, customCheck); - const result = await handler.handle(); - - // 如果验证通过,点击Continue按钮进入下一页 - if (result === 'passed') { - logger.info(this.siteName, '[Cloudflare] 点击Continue按钮进入验证码页面...'); - - try { - let pageChanged = false; - let attempts = 0; - const maxAttempts = 10; // 最多尝试10次 - - while (!pageChanged && attempts < maxAttempts) { - attempts++; - - // 查找并点击Continue按钮 - const button = await this.page.$('button:not([disabled])'); - if (button) { - logger.info(this.siteName, `[Cloudflare] 第${attempts}次点击Continue...`); - await button.click(); - await this.human.randomDelay(2000, 3000); - - // 检查是否有错误提示 - const hasError = await this.page.evaluate(() => { - const errorMsg = document.querySelector('p.caption1.text-sk-error'); - return errorMsg && errorMsg.textContent.includes('An error occurred'); - }); - - if (hasError) { - logger.warn(this.siteName, '[Cloudflare] 检测到错误提示,重新尝试...'); - await this.human.randomDelay(2000, 3000); - continue; - } - - // 检查页面是否已改变 - const checkResult = await this.page.evaluate(() => { - // 方法1: 检查是否有"Check your inbox"文本 - const hasCheckInbox = document.body.textContent.includes('Check your inbox'); - - // 方法2: 检查按钮是否被禁用 - const button = document.querySelector('button'); - const buttonDisabled = button && button.disabled; - - // 方法3: 检查是否还有"verify that you are human"文本 - const stillOnVerifyPage = document.body.textContent.includes('verify that you are human'); - - return { - hasCheckInbox, - buttonDisabled, - stillOnVerifyPage - }; - }); - - logger.info(this.siteName, `[Cloudflare] 页面状态: inbox=${checkResult.hasCheckInbox}, buttonDisabled=${checkResult.buttonDisabled}, stillVerify=${checkResult.stillOnVerifyPage}`); - - // 判断是否成功跳转 - if (checkResult.hasCheckInbox || (!checkResult.stillOnVerifyPage && checkResult.buttonDisabled)) { - pageChanged = true; - logger.success(this.siteName, '[Cloudflare] ✓ 已进入验证码页面'); - break; - } - - // 如果还在验证页面,继续等待 - logger.info(this.siteName, '[Cloudflare] 页面未跳转,继续尝试...'); - await this.human.randomDelay(2000, 3000); - } else { - logger.warn(this.siteName, '[Cloudflare] 未找到可点击的按钮'); - break; - } - } - - if (!pageChanged) { - logger.warn(this.siteName, `[Cloudflare] ${maxAttempts}次尝试后页面仍未跳转`); - } - - // 额外等待确保页面稳定 - await this.human.randomDelay(2000, 3000); - - } catch (e) { - logger.warn(this.siteName, `[Cloudflare] 点击按钮失败: ${e.message}`); - } - } - - return result; - } - /** * 步骤3: 邮箱验证 */ async step3_emailVerification() { logger.info(this.siteName, `[步骤 3/${this.getTotalSteps()}] 邮箱验证`); - // Cloudflare Turnstile 验证已在步骤2中通过 CapSolver 扩展自动完成 + // Cloudflare Turnstile 验证已在步骤2中完成 logger.info(this.siteName, ' → Turnstile 验证已通过,开始邮箱验证...'); try { @@ -1241,39 +609,61 @@ class WindsurfRegister { // 输入完6位验证码后,页面会自动提交 logger.info(this.siteName, ' → 等待邮箱验证完成并跳转到问卷页面...'); + logger.info(this.siteName, ' → 将持续等待直到跳转成功(无时间限制)...'); - // 等待页面跳转到 /account/onboarding?page=source + // 无限等待页面跳转到 /account/onboarding?page=source const startTime = Date.now(); - const maxWait = 20000; // 最多等待20秒 let registrationComplete = false; + let hasClickedButton = false; - while (Date.now() - startTime < maxWait) { + while (!registrationComplete) { const currentUrl = this.page.url(); - // 精确检查:必须是 /account/onboarding?page=source + // 检查1: 页面是否已经跳转成功(自动跳转成功) if (currentUrl.includes('/account/onboarding') && currentUrl.includes('page=source')) { registrationComplete = true; - logger.success(this.siteName, ` → ✓ 邮箱验证成功!已跳转到问卷页面`); + const totalTime = ((Date.now() - startTime) / 1000).toFixed(1); + logger.success(this.siteName, ` → ✓ 邮箱验证成功!已跳转到问卷页面 (耗时: ${totalTime}秒)`); logger.info(this.siteName, ` → 当前页面: ${currentUrl}`); break; } - // 每2秒输出一次进度 + // 检查2: 页面按钮是否变为激活状态(自动跳转失败,需要手动点击) + if (!hasClickedButton) { + const buttonEnabled = await this.page.evaluate(() => { + const buttons = Array.from(document.querySelectorAll('button')); + const continueButton = buttons.find(btn => + btn.textContent.trim() === 'Continue' && !btn.disabled + ); + return !!continueButton; + }); + + if (buttonEnabled) { + const elapsed = ((Date.now() - startTime) / 1000).toFixed(1); + logger.warn(this.siteName, ` → ⚠️ 检测到按钮重新激活 (${elapsed}秒后)`); + logger.info(this.siteName, ' → 自动跳转可能失败,尝试手动点击按钮...'); + + try { + // 点击 Continue 按钮 + await this.human.humanClick(this.page, 'button:not([disabled])'); + hasClickedButton = true; + logger.success(this.siteName, ' → ✓ 已点击按钮,继续等待跳转...'); + await this.human.randomDelay(1000, 2000); + } catch (e) { + logger.warn(this.siteName, ` → 点击按钮失败: ${e.message}`); + } + } + } + + // 每5秒输出一次进度 const elapsed = Date.now() - startTime; - if (elapsed > 0 && elapsed % 2000 === 0) { - logger.info(this.siteName, ` → 等待中... 已用时 ${elapsed/1000}秒`); + if (elapsed > 0 && elapsed % 5000 === 0) { + logger.info(this.siteName, ` → 等待中... 已用时 ${(elapsed/1000).toFixed(0)}秒`); } await new Promise(resolve => setTimeout(resolve, 500)); } - if (!registrationComplete) { - const finalUrl = this.page.url(); - logger.error(this.siteName, ` → ✗ 邮箱验证失败或页面未跳转`); - logger.error(this.siteName, ` → 当前页面: ${finalUrl}`); - throw new Error('步骤3:邮箱验证未成功跳转到问卷页面'); - } - // 额外等待页面稳定 await this.human.randomDelay(2000, 3000);