This commit is contained in:
dengqichen 2025-11-17 12:37:56 +08:00
parent 5c74ad349c
commit bfd6c9ef3d

View File

@ -74,49 +74,94 @@ class WindsurfRegister {
} }
/** /**
* 通用方法点击按钮并等待页面跳转 * 通用方法等待按钮激活并点击然后等待页面内容变化
* @param {Function} checkPageChanged - 检查页面是否已跳转的函数返回Promise<boolean> * @param {Object} options - 配置选项
* @param {number} maxAttempts - 最多尝试次数 * @param {string} options.buttonText - 按钮文本用于识别'Continue'
* @param {string} actionName - 操作名称用于日志 * @param {Function} options.checkContentChanged - 检查页面内容是否已变化的函数返回Promise<boolean>
* @returns {Promise<boolean>} - 是否成功跳转 * @param {number} options.waitButtonTimeout - 等待按钮激活的超时时间毫秒默认30000
* @param {number} options.waitContentTimeout - 等待内容变化的超时时间毫秒默认15000
* @param {string} options.actionName - 操作名称用于日志
* @returns {Promise<boolean>} - 是否成功完成
*/ */
async clickButtonAndWaitForPageChange(checkPageChanged, maxAttempts = 5, actionName = '点击按钮') { async clickButtonAndWaitForPageChange(options) {
let pageChanged = false; const {
let attempts = 0; buttonText = 'Continue',
checkContentChanged,
waitButtonTimeout = 30000,
waitContentTimeout = 15000,
actionName = '点击按钮'
} = options;
while (!pageChanged && attempts < maxAttempts) { try {
attempts++; // 阶段1: 等待按钮变为可点击状态enabled
logger.info(this.siteName, ` → 等待"${buttonText}"按钮激活...`);
// 查找未禁用的按钮 const buttonStartTime = Date.now();
const button = await this.page.$('button:not([disabled])'); let buttonEnabled = false;
if (button) {
const text = await this.page.evaluate(el => el.textContent.trim(), button); while (Date.now() - buttonStartTime < waitButtonTimeout) {
logger.info(this.siteName, ` → 第${attempts}${actionName}"${text}"...`); buttonEnabled = await this.page.evaluate((btnText) => {
await button.click(); const buttons = Array.from(document.querySelectorAll('button'));
await this.human.randomDelay(2000, 3000); const targetButton = buttons.find(btn =>
btn.textContent.trim() === btnText && !btn.disabled
);
return !!targetButton;
}, buttonText);
// 使用自定义检查函数判断页面是否跳转 if (buttonEnabled) {
const changed = await checkPageChanged(); const elapsed = ((Date.now() - buttonStartTime) / 1000).toFixed(1);
logger.success(this.siteName, ` → ✓ 按钮已激活 (耗时: ${elapsed}秒)`);
if (changed) {
pageChanged = true;
logger.success(this.siteName, ` → ✓ 页面已跳转`);
break; break;
} }
logger.warn(this.siteName, ` → 页面未跳转,${attempts}/${maxAttempts}`); // 每5秒输出一次进度
await this.human.randomDelay(2000, 3000); const elapsed = Date.now() - buttonStartTime;
} else { if (elapsed > 0 && elapsed % 5000 === 0) {
logger.warn(this.siteName, ` → 未找到可点击的按钮`); logger.info(this.siteName, ` → 等待按钮激活中... 已用时 ${(elapsed/1000).toFixed(0)}`);
break; }
await new Promise(resolve => setTimeout(resolve, 1000));
} }
if (!buttonEnabled) {
logger.error(this.siteName, ` → ⚠️ 等待${waitButtonTimeout/1000}秒后按钮仍未激活`);
return false;
}
// 阶段2: 点击按钮
logger.info(this.siteName, `${actionName}...`);
await this.human.humanClick(this.page, `button:not([disabled])`);
await this.human.randomDelay(1000, 2000);
// 阶段3: 等待页面内容变化
logger.info(this.siteName, ` → 等待页面内容变化...`);
const contentStartTime = Date.now();
let contentChanged = false;
while (Date.now() - contentStartTime < waitContentTimeout) {
contentChanged = await checkContentChanged();
if (contentChanged) {
const elapsed = ((Date.now() - contentStartTime) / 1000).toFixed(1);
logger.success(this.siteName, ` → ✓ 页面内容已变化 (耗时: ${elapsed}秒)`);
break;
}
await new Promise(resolve => setTimeout(resolve, 500));
}
if (!contentChanged) {
logger.warn(this.siteName, ` → ⚠️ 等待${waitContentTimeout/1000}秒后页面内容未变化`);
return false;
}
return true;
} catch (error) {
logger.error(this.siteName, `${actionName}失败: ${error.message}`);
return false;
} }
if (!pageChanged) {
logger.error(this.siteName, `${maxAttempts}次尝试后页面仍未跳转`);
}
return pageChanged;
} }
/** /**
@ -260,30 +305,25 @@ class WindsurfRegister {
} }
// 点击Continue按钮并等待跳转到密码页面 // 点击Continue按钮并等待跳转到密码页面
logger.info(this.siteName, ' → 点击Continue按钮...'); const success = await this.clickButtonAndWaitForPageChange({
buttonText: 'Continue',
checkContentChanged: async () => {
// 检查是否有密码输入框(表示已进入下一步)
return await this.page.evaluate(() => {
return !!document.querySelector('#password');
});
},
waitButtonTimeout: 30000,
waitContentTimeout: 15000,
actionName: '点击Continue进入密码设置页面'
});
// 等待按钮激活 if (!success) {
await this.page.waitForSelector('button:not([disabled])', { timeout: 10000 }); throw new Error('步骤1未能成功进入密码设置页面');
logger.info(this.siteName, ' → 按钮已激活'); }
// 使用通用方法处理页面跳转
const checkPageChanged = async () => {
// 检查是否有密码输入框
const hasPasswordField = await this.page.evaluate(() => {
return !!document.querySelector('#password');
});
// 检查URL是否改变
const currentUrl = this.page.url();
const urlChanged = currentUrl !== this.siteUrl;
return hasPasswordField || urlChanged;
};
await this.clickButtonAndWaitForPageChange(checkPageChanged, 5, '点击Continue');
// 额外等待确保页面稳定 // 额外等待确保页面稳定
await this.human.randomDelay(2000, 3000); await this.human.randomDelay(1000, 2000);
this.currentStep = 1; this.currentStep = 1;
logger.success(this.siteName, `步骤 1 完成`); logger.success(this.siteName, `步骤 1 完成`);
@ -909,28 +949,24 @@ class WindsurfRegister {
} }
logger.success(this.siteName, ' → 验证码已填写完成'); logger.success(this.siteName, ' → 验证码已填写完成');
// 等待按钮激活(填完验证码后按钮会自动启用) // 点击"Create account"按钮并等待页面内容变化
logger.info(this.siteName, ' → 等待按钮激活...'); const success = await this.clickButtonAndWaitForPageChange({
await this.human.randomDelay(2000, 3000); buttonText: 'Create account',
checkContentChanged: async () => {
// 检查验证码输入框是否已消失(表示已进入下一步)
return await this.page.evaluate(() => {
return !document.querySelector('input[type="text"]');
});
},
waitButtonTimeout: 30000,
waitContentTimeout: 15000,
actionName: '点击Create account进入下一步'
});
// 等待按钮激活 if (!success) {
try { throw new Error('步骤3未能成功创建账号');
await this.page.waitForSelector('button:not([disabled])', { timeout: 10000 });
logger.success(this.siteName, ' → 按钮已激活');
} catch (e) {
logger.warn(this.siteName, ` → 按钮等待超时: ${e.message}`);
} }
// 点击按钮并等待页面跳转
const checkPageChanged = async () => {
// 检查是否离开了验证码页面URL改变或页面元素改变
const currentUrl = this.page.url();
return !currentUrl.includes('/register') ||
await this.page.$('input[type="text"]').then(el => !el).catch(() => true);
};
await this.clickButtonAndWaitForPageChange(checkPageChanged, 3, '点击Create account');
this.currentStep = 3; this.currentStep = 3;
logger.success(this.siteName, `步骤 3 完成`); logger.success(this.siteName, `步骤 3 完成`);
@ -957,26 +993,54 @@ class WindsurfRegister {
logger.info(this.siteName, `[步骤 4/${this.getTotalSteps()}] 跳过问卷`); logger.info(this.siteName, `[步骤 4/${this.getTotalSteps()}] 跳过问卷`);
try { try {
// 等待页面加载 // 初始等待页面加载
await this.human.readPage(2, 3); await this.human.readPage(2, 3);
// 查找并点击"Skip this step"按钮 logger.info(this.siteName, ' → 持续查找"Skip this step"按钮...');
logger.info(this.siteName, ' → 查找"Skip this step"按钮...');
// 方式1: 通过button文本查找 const startTime = Date.now();
const buttons = await this.page.$$('button'); const maxWait = 60000; // 最多等待60秒
let elapsed = 0;
let skipButton = null; let skipButton = null;
let buttonFound = false;
for (const button of buttons) { // 轮询查找按钮
const text = await this.page.evaluate(el => el.textContent?.trim(), button); while (elapsed < maxWait && !buttonFound) {
if (text && text.toLowerCase().includes('skip')) { try {
skipButton = button; // 查找所有按钮
logger.info(this.siteName, ` → 找到按钮: "${text}"`); const buttons = await this.page.$$('button');
break;
for (const button of buttons) {
const text = await this.page.evaluate(el => el.textContent?.trim(), button);
if (text && text.toLowerCase().includes('skip')) {
skipButton = button;
buttonFound = true;
logger.success(this.siteName, ` → ✓ 找到按钮: "${text}" (耗时: ${((Date.now() - startTime) / 1000).toFixed(1)}秒)`);
break;
}
}
if (buttonFound) {
break;
}
// 每5秒输出一次进度
if (elapsed > 0 && elapsed % 5000 === 0) {
logger.info(this.siteName, ` → 等待按钮出现... 已用时 ${elapsed/1000}`);
}
// 等待2秒后继续查找
await new Promise(resolve => setTimeout(resolve, 2000));
elapsed = Date.now() - startTime;
} catch (error) {
logger.warn(this.siteName, ` → 查找按钮时出错: ${error.message},继续尝试...`);
await new Promise(resolve => setTimeout(resolve, 2000));
elapsed = Date.now() - startTime;
} }
} }
if (skipButton) { if (skipButton && buttonFound) {
logger.info(this.siteName, ' → 点击"Skip this step"按钮...'); logger.info(this.siteName, ' → 点击"Skip this step"按钮...');
await skipButton.click(); await skipButton.click();
@ -985,8 +1049,10 @@ class WindsurfRegister {
this.currentStep = 4; this.currentStep = 4;
logger.success(this.siteName, `步骤 4 完成`); logger.success(this.siteName, `步骤 4 完成`);
} else { } else if (elapsed >= maxWait) {
logger.warn(this.siteName, ' → 未找到Skip按钮可能已跳过此页面'); logger.warn(this.siteName, ` → ⚠️ 等待${maxWait/1000}秒后仍未找到Skip按钮`);
logger.warn(this.siteName, ' → 可能原因:页面已自动跳过或页面结构已变化');
logger.info(this.siteName, ' → 尝试继续执行下一步...');
this.currentStep = 4; this.currentStep = 4;
} }