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

190 lines
4.9 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.

/**
* 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<any>;
/**
* 替换配置中的变量(增强版)
*
* 支持特性:
* - 多数据源:{{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<void> {
const delay = min + Math.random() * (max - min);
await new Promise(resolve => setTimeout(resolve, delay));
}
// 阅读页面延迟2-5秒- 模拟用户查看页面内容
async readPageDelay(): Promise<void> {
await this.randomDelay(2000, 5000);
}
// 思考延迟1-2.5秒)- 模拟填写表单后的思考
async thinkDelay(): Promise<void> {
await this.randomDelay(1000, 2500);
}
// 短暂停顿300-800ms- 模拟操作间的自然停顿
async pauseDelay(): Promise<void> {
await this.randomDelay(300, 800);
}
// 步骤间延迟1.5-3秒- 模拟步骤之间的过渡
async stepDelay(): Promise<void> {
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;