auto-account-machine/browser-automation-ts/src/providers/adspower/actions/NavigateAction.ts
2025-11-21 17:59:49 +08:00

108 lines
3.4 KiB
TypeScript
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.

import BaseAction from '../core/BaseAction';
import { ValidationError, ElementNotFoundError } from '../../../core/errors/CustomErrors';
/**
* 导航动作 - 打开页面
*/
class NavigateAction extends BaseAction {
async execute(): Promise<any> {
const url = this.replaceVariables(this.config.url);
const options = this.config.options || {
waitUntil: 'networkidle2',
timeout: 30000
};
// 重试配置
const maxRetries = this.config.maxRetries || 5;
const retryDelay = this.config.retryDelay || 3000;
const totalTimeout = this.config.totalTimeout || 180000; // 默认3分钟
const startTime = Date.now();
let lastError: any = null;
for (let attempt = 0; attempt < maxRetries; attempt++) {
// 检查总超时
if (Date.now() - startTime > totalTimeout) {
this.log('error', `总超时 ${totalTimeout}ms停止重试`);
break;
}
try {
if (attempt > 0) {
this.log('info', `${attempt + 1} 次尝试导航...`);
} else {
this.log('info', `导航到: ${url}`);
}
// 尝试导航
await this.page.goto(url, options);
// 验证页面URL是否正确避免重定向到会员中心等
const currentUrl = this.page.url();
if (this.config.verifyUrl && !currentUrl.includes(this.config.verifyUrl)) {
throw new ValidationError(
`页面跳转异常`,
`URL包含: ${this.config.verifyUrl}`,
`实际URL: ${currentUrl}`,
{ expectedUrl: this.config.verifyUrl, actualUrl: currentUrl }
);
}
// 验证关键元素存在(确保页面加载正确)
if (this.config.verifyElements) {
await this.verifyElements(this.config.verifyElements);
}
this.log('info', `✓ 页面加载完成${attempt > 0 ? ` (尝试 ${attempt + 1} 次)` : ''}`);
// 模拟人类阅读页面1-3秒
await this.readPageDelay();
// 可选的额外等待时间
if (this.config.waitAfter) {
await new Promise(resolve => setTimeout(resolve, this.config.waitAfter));
}
return { success: true, url: currentUrl };
} catch (error: any) {
lastError = error;
this.log('warn', `导航失败 (尝试 ${attempt + 1}/${maxRetries}): ${error.message}`);
// 如果不是最后一次尝试,等待后重试
if (attempt < maxRetries - 1) {
this.log('debug', `等待 ${retryDelay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
}
// 所有重试都失败
this.log('error', `导航失败: ${lastError.message}`);
throw lastError;
}
/**
* 验证关键元素存在
*/
async verifyElements(selectors: string[]): Promise<void> {
this.log('debug', '验证页面元素...');
for (const selector of selectors) {
try {
await this.page.waitForSelector(selector, { timeout: 10000 });
} catch (error: any) {
throw new ElementNotFoundError(selector, {
action: 'navigate',
operation: 'verifyElements',
url: this.page.url()
});
}
}
this.log('debug', `✓ 已验证 ${selectors.length} 个关键元素`);
}
}
export default NavigateAction;