This commit is contained in:
dengqichen 2025-11-19 14:51:05 +08:00
parent 41b6510b4e
commit d2fd4d2b1a
6 changed files with 62 additions and 11 deletions

View File

@ -57,6 +57,9 @@ class ClickAction extends BaseAction {
this.log('warn', `滚动失败,继续尝试点击: ${error.message}`); this.log('warn', `滚动失败,继续尝试点击: ${error.message}`);
} }
// 模拟人类"准备点击"的短暂停顿
await this.pauseDelay();
// 点击(支持人类行为模拟) // 点击(支持人类行为模拟)
const humanLike = this.config.humanLike !== false; // 默认使用人类行为 const humanLike = this.config.humanLike !== false; // 默认使用人类行为
if (humanLike) { if (humanLike) {
@ -68,6 +71,9 @@ class ClickAction extends BaseAction {
this.log('info', '✓ 点击完成'); this.log('info', '✓ 点击完成');
// 点击后的自然延迟(等待页面反应)
await this.pauseDelay();
// 验证点击后的变化(新元素出现 / 旧元素消失) // 验证点击后的变化(新元素出现 / 旧元素消失)
if (this.config.verifyAfter) { if (this.config.verifyAfter) {
await this.verifyAfterClick(this.config.verifyAfter); await this.verifyAfterClick(this.config.verifyAfter);

View File

@ -16,12 +16,22 @@ class FillFormAction extends BaseAction {
this.log('info', `填写表单,共 ${Object.keys(fields).length} 个字段`); this.log('info', `填写表单,共 ${Object.keys(fields).length} 个字段`);
// 填写每个字段 // 填写每个字段
for (const [key, fieldConfig] of Object.entries(fields)) { const fieldEntries = Object.entries(fields);
for (let i = 0; i < fieldEntries.length; i++) {
const [key, fieldConfig] = fieldEntries[i];
await this.fillField(key, fieldConfig, humanLike); await this.fillField(key, fieldConfig, humanLike);
// 字段间的停顿(不是最后一个字段时)
if (i < fieldEntries.length - 1) {
await this.pauseDelay();
}
} }
this.log('info', '✓ 表单填写完成'); this.log('info', '✓ 表单填写完成');
// 模拟人类填写后的思考时间
await this.thinkDelay();
return { success: true }; return { success: true };
} }

View File

@ -47,13 +47,16 @@ class NavigateAction extends BaseAction {
await this.verifyElements(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) { if (this.config.waitAfter) {
await new Promise(resolve => setTimeout(resolve, this.config.waitAfter)); await new Promise(resolve => setTimeout(resolve, this.config.waitAfter));
} }
this.log('info', `✓ 页面加载完成${attempt > 0 ? ` (尝试 ${attempt + 1} 次)` : ''}`);
return { success: true, url: currentUrl }; return { success: true, url: currentUrl };
} catch (error) { } catch (error) {

View File

@ -58,11 +58,14 @@ class ScrollAction extends BaseAction {
throw new Error(`不支持的滚动类型: ${type}`); throw new Error(`不支持的滚动类型: ${type}`);
} }
// 等待滚动完成 // 等待滚动动画完成
await new Promise(resolve => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));
this.log('debug', '✓ 滚动完成'); this.log('debug', '✓ 滚动完成');
// 模拟人类滚动后查看内容的停顿
await this.pauseDelay();
return { success: true }; return { success: true };
} }

View File

@ -32,7 +32,6 @@ workflow:
# 1.2 填写基本信息 # 1.2 填写基本信息
- action: fillForm - action: fillForm
name: "填写基本信息" name: "填写基本信息"
humanLike: true
fields: fields:
firstName: firstName:
find: find:
@ -58,7 +57,6 @@ workflow:
selector: selector:
- css: 'input[type="checkbox"]' - css: 'input[type="checkbox"]'
optional: true optional: true
waitAfter: 500
# 1.4 点击 Continue # 1.4 点击 Continue
- action: click - action: click
@ -72,7 +70,6 @@ workflow:
appears: appears:
- '#password' - '#password'
- 'input[type="password"]' - 'input[type="password"]'
waitAfter: 2000
# ==================== 步骤 2: 设置密码 ==================== # ==================== 步骤 2: 设置密码 ====================
- action: wait - action: wait
@ -84,7 +81,6 @@ workflow:
- action: fillForm - action: fillForm
name: "设置密码" name: "设置密码"
humanLike: true
fields: fields:
password: password:
find: find:
@ -186,7 +182,6 @@ workflow:
# 填写银行卡信息(使用重新生成的卡号) # 填写银行卡信息(使用重新生成的卡号)
- action: fillForm - action: fillForm
name: "填写银行卡信息" name: "填写银行卡信息"
humanLike: false
fields: fields:
cardNumber: cardNumber:
find: find:
@ -226,13 +221,17 @@ workflow:
# 填写地址(动态字段) # 填写地址(动态字段)
- action: fillForm - action: fillForm
name: "填写地址" name: "填写地址"
humanLike: false
fields: fields:
addressLine1: addressLine1:
find: find:
- css: 'input[placeholder*="地址"]' - css: 'input[placeholder*="地址"]'
- css: 'input[placeholder*="Address"]' - css: 'input[placeholder*="Address"]'
value: "kowloon" value: "kowloon"
addressLine2:
find:
- css: 'input[placeholder*="Address line 2"]'
- css: 'input[name="billingAddressLine2"]'
value: "Macau"
# 滚动到页面底部(确保订阅按钮可见) # 滚动到页面底部(确保订阅按钮可见)
- action: scroll - action: scroll

View File

@ -50,6 +50,36 @@ class BaseAction {
console.log(`[${level.toUpperCase()}] ${message}`); console.log(`[${level.toUpperCase()}] ${message}`);
} }
} }
/**
* 人类行为延迟工具方法
*/
// 随机延迟
async randomDelay(min, max) {
const delay = min + Math.random() * (max - min);
await new Promise(resolve => setTimeout(resolve, delay));
}
// 阅读页面延迟1-3秒
async readPageDelay() {
await this.randomDelay(1000, 3000);
}
// 思考延迟500-1500ms
async thinkDelay() {
await this.randomDelay(500, 1500);
}
// 短暂停顿200-500ms
async pauseDelay() {
await this.randomDelay(200, 500);
}
// 步骤间延迟1-2秒
async stepDelay() {
await this.randomDelay(1000, 2000);
}
} }
module.exports = BaseAction; module.exports = BaseAction;