/** * AdsPower Provider的BaseAction * 扩展了核心BaseAction,添加人类行为模拟和变量替换 */ import { Page } from 'puppeteer'; export interface ActionContext { page: Page; logger?: any; data?: any; siteConfig?: any; config?: any; siteName?: string; adapter?: any; // 自定义适配器,用于CustomAction和WaitAction } export abstract class BaseAction { protected context: ActionContext; protected config: any; protected page: Page; protected logger: any; constructor(context: ActionContext, config: any) { this.context = context; this.config = config; this.page = context.page; this.logger = context.logger; } /** * 执行动作(子类必须实现) */ abstract execute(): Promise; /** * 替换配置中的变量(增强版) * * 支持特性: * - 多数据源:{{account.email}}, {{site.url}}, {{config.timeout}} * - 默认值:{{var|default}}, {{user.name|Guest}} * - 变量不存在时警告 */ replaceVariables(value: any): any { if (typeof value !== 'string') return value; return value.replace(/\{\{(.+?)\}\}/g, (match, expression) => { // 解析默认值:{{var|default}} const [path, defaultValue] = expression.split('|').map((s: string) => s.trim()); // 获取变量值 const result = this.resolveVariablePath(path); // 如果找到值,返回 if (result !== undefined && result !== null) { return result; } // 如果有默认值,使用默认值 if (defaultValue !== undefined) { this.log('debug', `变量 "${path}" 不存在,使用默认值: "${defaultValue}"`); return defaultValue; } // 变量不存在且无默认值,发出警告 this.log('warn', `⚠️ 变量 "${path}" 不存在,返回原始值: ${match}`); return match; }); } /** * 解析变量路径,支持多个数据源 */ resolveVariablePath(path: string): any { const keys = path.split('.'); const rootKey = keys[0]; // 确定数据源 let dataSource: any; let startIndex = 1; // 从第二个key开始 switch (rootKey) { case 'site': // {{site.url}} -> context.siteConfig.url dataSource = this.context.siteConfig; break; case 'config': // {{config.timeout}} -> context.config dataSource = this.context.config; break; case 'env': // {{env.API_KEY}} -> process.env dataSource = process.env; break; default: // 默认从 context.data 读取 // {{account.email}} -> context.data.account.email dataSource = this.context.data; startIndex = 0; // 从第一个key开始 } if (!dataSource) { return undefined; } // 遍历路径获取值 let result = dataSource; for (let i = startIndex; i < keys.length; i++) { if (result && typeof result === 'object') { result = result[keys[i]]; } else { return undefined; } } return result; } /** * 记录日志 */ log(level: string, message: string): void { if (this.logger && this.logger[level]) { this.logger[level](this.context.siteName || 'Automation', message); } else { console.log(`[${level.toUpperCase()}] ${message}`); } } /** * 人类行为延迟工具方法(模拟真实用户操作节奏) */ // 随机延迟 async randomDelay(min: number, max: number): Promise { const delay = min + Math.random() * (max - min); await new Promise(resolve => setTimeout(resolve, delay)); } // 阅读页面延迟(2-5秒)- 模拟用户查看页面内容 async readPageDelay(): Promise { await this.randomDelay(2000, 5000); } // 思考延迟(1-2.5秒)- 模拟填写表单后的思考 async thinkDelay(): Promise { await this.randomDelay(1000, 2500); } // 短暂停顿(300-800ms)- 模拟操作间的自然停顿 async pauseDelay(): Promise { await this.randomDelay(300, 800); } // 步骤间延迟(1.5-3秒)- 模拟步骤之间的过渡 async stepDelay(): Promise { await this.randomDelay(1500, 3000); } /** * 获取Action类(用于动态加载) */ getActionClass(actionType: string): any { const actionMap: any = { navigate: require('./NavigateAction').default, fillForm: require('./FillFormAction').default, click: require('./ClickAction').default, wait: require('./WaitAction').default, custom: require('./CustomAction').default, scroll: require('./ScrollAction').default, verify: require('./VerifyAction').default, extract: require('./ExtractAction').default, retryBlock: require('./RetryBlockAction').default }; const ActionClass = actionMap[actionType]; if (!ActionClass) { throw new Error(`未知的 action 类型: ${actionType}`); } return ActionClass; } } export default BaseAction;