auto-account-machine/src/tools/automation-framework
2025-11-19 10:12:54 +08:00
..
actions dasdasd 2025-11-19 10:12:54 +08:00
configs/sites dasdasd 2025-11-19 10:12:54 +08:00
core dasdasd 2025-11-19 10:12:54 +08:00
sites dasdasd 2025-11-18 23:02:49 +08:00
index.js dasdasd 2025-11-18 23:02:49 +08:00
README.md dasdasd 2025-11-18 23:02:49 +08:00

自动化框架使用教程

目录


框架概述

这是一个配置驱动的浏览器自动化框架,基于 Puppeteer 构建。核心理念:

  • 90% 配置10% 代码 - 大部分操作通过 YAML 配置
  • 声明式编程 - 只需描述"做什么",不需要"怎么做"
  • 可复用 - 一次配置,多处使用
  • 易维护 - 修改配置即可调整流程

快速开始

1. 创建站点配置文件

src/automation-framework/configs/sites/ 创建 mysite.yaml:

# 站点信息
site:
  name: MySite
  url: https://mysite.com/register

# 工作流定义
workflow:
  - action: navigate
    name: "打开注册页面"
    url: "https://mysite.com/register"
  
  - action: fillForm
    name: "填写注册信息"
    fields:
      username:
        find:
          - css: '#username'
        value: "{{account.username}}"
      
      email:
        find:
          - css: '#email'
        value: "{{account.email}}"
  
  - action: click
    name: "提交注册"
    selector:
      - css: 'button[type="submit"]'

2. 创建站点适配器

src/automation-framework/sites/ 创建 mysite-adapter.js:

const SiteAdapter = require('../core/site-adapter');

class MySiteAdapter extends SiteAdapter {
  constructor(context) {
    super(context, 'mysite');
  }
  
  async beforeWorkflow() {
    await super.beforeWorkflow();
    
    // 生成测试数据
    this.context.data = {
      account: {
        username: 'testuser',
        email: 'test@example.com'
      }
    };
  }
}

module.exports = MySiteAdapter;

3. 运行

const AutomationFactory = require('./src/automation-framework');

const factory = new AutomationFactory({
  logger: console,
  adspowerUserId: 'your-profile-id'
});

await factory.execute('mysite');

YAML 配置结构

基本结构

# 站点信息
site:
  name: 站点名称
  url: 站点URL

# 工作流定义
workflow:
  - action: 动作类型
    name: 步骤名称
    # 动作特定参数
    ...

# 错误处理配置(可选)
errorHandling:
  screenshot: true
  retry:
    enabled: true
    maxAttempts: 3
    delay: 2000

内置 Actions

navigate - 页面导航

用途:打开或跳转到指定页面

必需参数

  • url (string): 目标URL支持变量替换

可选参数

  • name (string): 步骤名称
  • options (object): 导航选项
    • waitUntil (string): 等待条件,默认 'networkidle2'
    • timeout (number): 超时时间(毫秒),默认 30000
  • verifyUrl (string): 验证URL是否包含此字符串
  • verifyElements (array): 验证这些元素存在
  • waitAfter (number): 导航后等待时间(毫秒)

示例

# 基本导航
- action: navigate
  url: "https://example.com/register"

# 带验证的导航
- action: navigate
  name: "打开注册页面"
  url: "https://example.com/register"
  verifyUrl: "/register"
  verifyElements:
    - '#username'
    - '#email'
    - 'button[type="submit"]'
  waitAfter: 2000

# 自定义选项
- action: navigate
  url: "{{config.baseUrl}}/login"
  options:
    waitUntil: 'domcontentloaded'
    timeout: 60000

fillForm - 表单填写

用途:填写表单字段

必需参数

  • fields (object): 字段配置对象,键为字段名

可选参数

  • name (string): 步骤名称
  • humanLike (boolean): 是否模拟人类输入,默认 true

字段配置

  • find (array): 选择器数组,按顺序尝试
    • css (string): CSS 选择器
    • xpath (string): XPath 选择器
    • text (string): 按文本查找
    • name (string): 按 name 属性查找
  • value (string): 字段值,支持变量替换
  • clear (boolean): 填写前是否清空,默认 true

示例

# 基本表单填写
- action: fillForm
  name: "填写注册信息"
  fields:
    username:
      find:
        - css: '#username'
      value: "{{account.username}}"
    
    email:
      find:
        - css: 'input[name="email"]'
        - css: '#email'
      value: "{{account.email}}"

# 模拟人类输入
- action: fillForm
  name: "填写个人信息"
  humanLike: true
  fields:
    firstName:
      find:
        - css: '#firstName'
      value: "{{account.firstName}}"
      clear: true
    
    lastName:
      find:
        - css: '#lastName'
      value: "{{account.lastName}}"

# 密码字段
- action: fillForm
  name: "设置密码"
  humanLike: false
  fields:
    password:
      find:
        - css: 'input[type="password"]'
      value: "{{account.password}}"
    
    passwordConfirm:
      find:
        - css: 'input[placeholder*="Confirm"]'
      value: "{{account.password}}"

click - 点击操作

用途:点击页面元素

必需参数

  • selector (array 或 object): 元素选择器

可选参数

  • name (string): 步骤名称
  • verifyAfter (object): 点击后验证
    • appears (array): 应该出现的元素
    • disappears (array): 应该消失的元素
    • timeout (number): 验证超时时间
  • waitForPageChange (boolean): 是否等待页面变化
  • checkSelector (object): 检查的选择器
  • waitAfter (number): 点击后等待时间(毫秒)
  • optional (boolean): 是否可选,默认 false

选择器格式

selector:
  - css: '#submit-btn'
  - xpath: '//button[@id="submit"]'
  - text: 'Continue'
  - name: 'submit'

示例

# 简单点击
- action: click
  selector:
    - css: 'button[type="submit"]'

# 按文本点击
- action: click
  name: "点击继续按钮"
  selector:
    - text: 'Continue'
    - text: '继续'
  waitAfter: 2000

# 带验证的点击
- action: click
  name: "提交表单"
  selector:
    - css: '#submit-btn'
  verifyAfter:
    appears:
      - '#success-message'
      - '.confirmation'
    disappears:
      - '.loading-spinner'
    timeout: 10000

# 可选点击(找不到元素不报错)
- action: click
  name: "关闭弹窗"
  selector:
    - css: '.modal-close'
  optional: true
  waitAfter: 500

wait - 等待

用途:等待特定条件

必需参数

  • type (string): 等待类型
    • delay: 固定时间延迟
    • element: 等待元素出现
    • navigation: 等待页面导航

可选参数

  • name (string): 步骤名称
  • duration (number): 延迟时长(毫秒),用于 delay 类型
  • find (array): 元素选择器,用于 element 类型
  • timeout (number): 超时时间(毫秒),默认 30000

示例

# 固定延迟
- action: wait
  name: "等待2秒"
  type: delay
  duration: 2000

# 等待元素出现
- action: wait
  name: "等待密码输入框"
  type: element
  find:
    - css: 'input[type="password"]'
  timeout: 15000

# 等待多个选择器之一
- action: wait
  name: "等待确认页面"
  type: element
  find:
    - css: '#confirmation'
    - text: 'Success'
  timeout: 30000

# 等待页面导航
- action: wait
  name: "等待页面跳转"
  type: navigation
  timeout: 10000

extract - 数据提取

用途:从页面提取数据并保存到上下文

必需参数

  • selector (string): CSS 选择器
  • contextKey (string): 保存到上下文的键名

可选参数

  • name (string): 步骤名称
  • extractType (string): 提取类型
    • text: 文本内容(默认)
    • html: HTML 内容
    • attribute: 属性值
    • value: 表单值
  • attribute (string): 属性名,用于 attribute 类型
  • regex (string): 正则表达式,用于提取特定内容
  • saveTo (object): 捕获组映射
  • filter (object): 元素过滤
    • contains (string): 包含文本
    • notContains (string): 不包含文本
  • multiple (boolean): 是否提取多个元素,默认 false
  • required (boolean): 是否必需,默认 true

示例

# 简单文本提取
- action: extract
  name: "提取页面标题"
  selector: "h1.title"
  extractType: "text"
  contextKey: "pageTitle"

# 提取属性
- action: extract
  name: "提取头像URL"
  selector: "img.avatar"
  extractType: "attribute"
  attribute: "src"
  contextKey: "avatarUrl"

# 正则提取 + 捕获组
- action: extract
  name: "提取配额信息"
  selector: "p.quota"
  extractType: "text"
  regex: "(\\d+)\\s*/\\s*(\\d+)"
  saveTo:
    used: "$1"
    total: "$2"
  contextKey: "quotaInfo"

# 过滤 + 提取
- action: extract
  name: "提取账单周期"
  selector: "p.info"
  filter:
    contains: "Next billing"
  regex: "(\\d+)\\s+days.*on\\s+([A-Za-z]+\\s+\\d+,\\s+\\d{4})"
  saveTo:
    days: "$1"
    date: "$2"
  contextKey: "billingInfo"

# 提取多个元素
- action: extract
  name: "提取所有列表项"
  selector: "li.item"
  extractType: "text"
  multiple: true
  contextKey: "items"

# 可选提取(找不到不报错)
- action: extract
  name: "提取错误消息"
  selector: ".error-message"
  contextKey: "errorMsg"
  required: false

verify - 结果验证

用途:验证操作结果(如支付成功/失败),支持轮询检测多种条件

必需参数

  • conditions (object): 验证条件
    • success (array): 成功条件列表(任一满足即成功)
    • failure (array): 失败条件列表(任一满足即失败)

可选参数

  • name (string): 步骤名称
  • timeout (number): 超时时间(毫秒),默认 10000
  • pollInterval (number): 轮询间隔(毫秒),默认 500
  • onSuccess (string): 成功时的行为
    • continue: 继续执行(默认)
    • return: 返回结果
  • onFailure (string): 失败时的行为
    • throw: 抛出异常(默认,触发 retryBlock 重试
    • continue: 继续执行(忽略失败)
    • return: 返回结果
  • onTimeout (string): 超时时的行为,默认 throw

onFailure 行为详解

行为 使用场景
throw 抛出异常 在 retryBlock 内使用,失败时触发重试
continue 继续执行 失败不影响流程,只记录结果
return 返回结果 由后续步骤处理失败情况

重要

  • retryBlock 内使用 onFailure: "throw" 可触发重试
  • 只有所有重试都失败,才会导致整个流程失败
  • 单次验证失败不会终止流程(会自动重试)

支持的条件类型

条件类型 说明 示例
urlContains URL 包含指定文本 urlContains: "success"
urlNotContains URL 不包含指定文本 urlNotContains: "stripe.com"
urlEquals URL 完全匹配 urlEquals: "https://app.com/dashboard"
elementExists 元素存在 elementExists: ".success-message"
elementNotExists 元素不存在 elementNotExists: ".loading"
elementVisible 元素可见 elementVisible: "#confirmation"
elementHidden 元素隐藏 elementHidden: ".modal"
textContains 页面包含文本 textContains: "Payment successful"
textNotContains 页面不包含文本 textNotContains: "Error"
elementTextContains 元素包含文本 {selector: ".status", text: "Active"}

示例

# 验证支付结果
- action: verify
  name: "验证支付结果"
  conditions:
    success:
      - urlNotContains: "checkout.stripe.com"
      - elementExists: ".payment-success"
    failure:
      - textContains: "card was declined"
      - textContains: "declined"
      - elementExists: ".error-message"
  timeout: 15000
  pollInterval: 500
  onFailure: "throw"

# 验证页面跳转
- action: verify
  name: "验证登录成功"
  conditions:
    success:
      - urlContains: "/dashboard"
      - elementExists: ".user-profile"
    failure:
      - textContains: "Invalid credentials"
      - elementExists: ".login-error"
  timeout: 10000
  onFailure: "throw"

# 验证元素状态
- action: verify
  name: "验证加载完成"
  conditions:
    success:
      - elementHidden: ".loading-spinner"
      - elementVisible: ".content"
  timeout: 30000
  onTimeout: "continue"

# 复杂验证
- action: verify
  name: "验证注册结果"
  conditions:
    success:
      - urlEquals: "https://app.com/welcome"
    failure:
      - textContains: "Email already exists"
      - textContains: "Username taken"
      - elementExists: ".validation-error"
  timeout: 10000
  pollInterval: 1000
  onSuccess: "return"
  onFailure: "throw"

配合 retryBlock 使用

- action: retryBlock
  name: "支付流程"
  maxRetries: 5
  onRetryBefore:
    - action: custom
      handler: "regenerateCard"
  steps:
    - action: fillForm
      fields:
        cardNumber:
          value: "{{card.number}}"
    
    - action: custom
      handler: "handleCaptcha"
    
    - action: click
      name: "提交支付"
      selector:
        - css: "#submit-payment"
    
    # verify 检测到失败会抛异常,触发 retryBlock 重试
    - action: verify
      name: "验证支付结果"
      conditions:
        success:
          - urlNotContains: "stripe.com"
        failure:
          - textContains: "declined"
          - textContains: "card was declined"
      timeout: 10000
      pollInterval: 500
      onFailure: "throw"

执行流程示例

第1次尝试
  ├─ 填写卡号: 4111111111111111
  ├─ 处理验证码
  ├─ 提交支付
  └─ verify 检测
      └─ 发现 "declined" ❌
          └─ throw Error ⚡
              └─ retryBlock 捕获 → 重试 1/5

第2次尝试
  ├─ regenerateCard() 生成新卡: 4242424242424242
  ├─ 填写新卡号: 4242424242424242
  ├─ 处理验证码
  ├─ 提交支付
  └─ verify 检测
      └─ URL 不包含 "stripe.com" ✅
          └─ 成功!继续下一步

总结尝试了2次第2次成功流程继续

日志输出示例

[Windsurf] [验证支付结果]
[windsurf] ✗ 验证失败: 页面包含文本: "card was declined"
[windsurf] ⚠ WARNING: 步骤失败,触发重试 (1/5)
[windsurf] 执行重试前钩子...
[windsurf] 重新生成银行卡...
[windsurf] ✓ 新卡号: 4242424242424242
[windsurf] 重新执行步骤...
[Windsurf] [填写银行卡信息]
[Windsurf] [验证支付结果]
[windsurf] ✓ 验证成功: URL 不包含 "stripe.com"
[windsurf] 支付流程完成!

retryBlock - 重试块

用途:将一组步骤作为整体进行重试

必需参数

  • steps (array): 要重试的步骤数组

可选参数

  • name (string): 重试块名称
  • maxRetries (number): 最大重试次数,默认 3
  • retryDelay (number): 重试间隔(毫秒),默认 2000
  • onRetryBefore (array): 重试前执行的步骤
  • onRetryAfter (array): 重试后执行的步骤

示例

# 基本重试块
- action: retryBlock
  name: "支付流程"
  maxRetries: 5
  retryDelay: 3000
  steps:
    - action: fillForm
      name: "填写银行卡"
      fields:
        cardNumber:
          find:
            - css: '#cardNumber'
          value: "{{card.number}}"
    
    - action: click
      name: "提交支付"
      selector:
        - css: '#submit-payment'

# 带重试钩子的重试块
- action: retryBlock
  name: "注册流程(含验证码重试)"
  maxRetries: 3
  onRetryBefore:
    # 重试前重新生成数据
    - action: custom
      handler: "regenerateAccount"
  onRetryAfter:
    # 重试后记录日志
    - action: custom
      handler: "logRetryAttempt"
  steps:
    - action: fillForm
      name: "填写注册信息"
      fields:
        email:
          find:
            - css: '#email'
          value: "{{account.email}}"
    
    - action: custom
      name: "处理验证码"
      handler: "handleCaptcha"

custom - 自定义逻辑

用途:执行站点适配器中的自定义方法

必需参数

  • handler (string): 适配器中的方法名

可选参数

  • name (string): 步骤名称
  • params (object): 传递给方法的参数
  • optional (boolean): 是否可选,默认 false

示例

# 简单自定义调用
- action: custom
  name: "处理验证码"
  handler: "handleCaptcha"

# 带参数的自定义调用
- action: custom
  name: "处理 Turnstile 验证"
  handler: "handleTurnstile"
  params:
    timeout: 30000
    maxRetries: 3

# 可选自定义调用
- action: custom
  name: "获取订阅信息"
  handler: "getSubscriptionInfo"
  optional: true

# 重新生成数据
- action: custom
  handler: "regenerateCard"
  params:
    country: "MO"

对应的适配器方法

class MySiteAdapter extends SiteAdapter {
  async handleCaptcha(params) {
    // 处理验证码逻辑
    return { success: true };
  }
  
  async handleTurnstile(params) {
    const { timeout, maxRetries } = params;
    // 处理 Turnstile 验证
    return { success: true };
  }
  
  async regenerateCard(params) {
    const { country } = params;
    // 重新生成银行卡
    this.context.data.card = this.cardGen.generate(country);
  }
}

变量替换

框架支持在 YAML 中使用变量,格式为 {{path.to.variable}}

可用变量源

1. context.data - 运行时数据

- action: fillForm
  fields:
    email:
      value: "{{account.email}}"      # context.data.account.email
    
    cardNumber:
      value: "{{card.number}}"         # context.data.card.number

2. config.site - 站点配置

- action: navigate
  url: "{{site.url}}"                  # config.site.url

在适配器中设置变量

async beforeWorkflow() {
  this.context.data = {
    account: {
      email: 'test@example.com',
      password: 'SecurePass123',
      firstName: 'John',
      lastName: 'Doe'
    },
    card: {
      number: '4111111111111111',
      month: '12',
      year: '25',
      cvv: '123'
    }
  };
}

站点适配器开发

基本结构

const SiteAdapter = require('../core/site-adapter');

class MySiteAdapter extends SiteAdapter {
  constructor(context) {
    super(context, 'mysite');  // 'mysite' 对应 mysite.yaml
  }
  
  /**
   * 工作流执行前 - 准备数据
   */
  async beforeWorkflow() {
    await super.beforeWorkflow();  // 清除浏览器状态
    
    // 生成测试数据
    this.context.data = {
      account: this.generateAccount(),
      card: this.generateCard()
    };
  }
  
  /**
   * 工作流执行后 - 清理或保存
   */
  async afterWorkflow() {
    await super.afterWorkflow();
    // 保存结果等
  }
  
  /**
   * 自定义方法 - 由 YAML 的 custom action 调用
   */
  async handleCaptcha(params) {
    // 实现验证码处理
    return { success: true };
  }
  
  /**
   * 重启钩子 - restart 策略调用
   */
  async onRestart(options) {
    // 返回需要重新执行的步骤名称
    return [
      '填写基本信息',
      '设置密码'
    ];
  }
}

module.exports = MySiteAdapter;

生命周期钩子

钩子 调用时机 用途
beforeWorkflow() 工作流开始前 准备数据、清理状态
afterWorkflow() 工作流完成后 保存结果、清理资源
onError(error) 发生错误时 错误处理、截图
onRestart(options) restart 重试时 返回需要重新执行的步骤

重试策略

框架提供三种重试策略(在 executeRetryStrategy 中实现):

1. refresh - 刷新页面保持状态

params:
  retryStrategy: 'refresh'
  • 适用于刷新后保持当前页面状态的网站
  • 只刷新页面,不重新填写

2. restart - 刷新后重新开始

params:
  retryStrategy: 'restart'
  • 适用于刷新后回到第一步的网站(如 Windsurf
  • 自动调用 onRestart() 获取需要重新执行的步骤

3. wait - 延长等待时间

params:
  retryStrategy: 'wait'
  waitTime: 10000
  • 不刷新页面,只等待更长时间
  • 适用于加载慢的情况

框架提供的工具方法

// 日志
this.log('info', '消息');
this.log('success', '✓ 成功消息');
this.log('warn', '⚠ 警告消息');
this.log('error', '✗ 错误消息');

// 重新执行 YAML 步骤
await this.rerunSteps(['步骤名称1', '步骤名称2']);
await this.rerunSteps([0, 1, 2]);  // 按索引

// 重试策略
await this.executeRetryStrategy('refresh', retryCount);
await this.executeRetryStrategy('restart', retryCount);
await this.executeRetryStrategy('wait', retryCount, { waitTime: 5000 });

最佳实践

1. 步骤命名清晰

# ❌ 不好
- action: click
  selector:
    - css: 'button'

# ✅ 好
- action: click
  name: "点击 Continue 按钮(基本信息页)"
  selector:
    - css: 'button[type="submit"]'

2. 使用多个选择器备选

fields:
  email:
    find:
      - css: '#email'           # 首选
      - css: 'input[name="email"]'  # 备选1
      - xpath: '//input[@type="email"]'  # 备选2

3. 验证关键步骤

# 导航后验证
- action: navigate
  url: "https://example.com/register"
  verifyElements:
    - '#username'
    - '#email'

# 点击后验证
- action: click
  name: "提交表单"
  selector:
    - css: '#submit'
  verifyAfter:
    appears:
      - '#success-message'

4. 合理使用 optional

# 可能不存在的弹窗
- action: click
  name: "关闭欢迎弹窗"
  selector:
    - css: '.welcome-modal .close'
  optional: true

# 不影响主流程的数据提取
- action: extract
  name: "提取备注信息"
  selector: ".notes"
  contextKey: "notes"
  required: false

5. 模块化配置

# 将重复逻辑抽取为 retryBlock
- action: retryBlock
  name: "支付流程"
  maxRetries: 5
  onRetryBefore:
    - action: custom
      handler: "regenerateCard"
  steps:
    # 复用的步骤组
    - action: fillForm
      ...
    - action: click
      ...

6. 适当使用 humanLike

# 重要表单使用人类行为模拟
- action: fillForm
  name: "填写个人信息"
  humanLike: true  # 随机延迟、打字速度
  fields:
    firstName:
      ...

# 支付信息快速填写
- action: fillForm
  name: "填写银行卡"
  humanLike: false  # 快速填写
  fields:
    cardNumber:
      ...

7. 使用 verify + retryBlock 实现智能重试

# ✅ 最佳实践:将需要重试的步骤放在 retryBlock 内
# hCaptcha 等验证码只处理一次(放在 retryBlock 外)
- action: custom
  handler: "handleCaptcha"

# 支付提交和验证放在 retryBlock 内
- action: retryBlock
  maxRetries: 5
  onRetryBefore:
    - action: custom
      handler: "regenerateCard"
  steps:
    - action: fillForm
      fields:
        cardNumber:
          value: "{{card.number}}"
    
    - action: click
      selector:
        - css: "#submit"
    
    # verify 失败会触发重试
    - action: verify
      conditions:
        success:
          - urlNotContains: "payment"
        failure:
          - textContains: "declined"
      onFailure: "throw"

# ❌ 避免:把验证码放在 retryBlock 内
# 会导致每次重试都要处理验证码

关键点

  • 只重试必要的步骤(填表 + 提交 + 验证)
  • 一次性步骤放在 retryBlock 外(验证码、页面导航)
  • verify 检测结果,onFailure: "throw" 触发重试
  • onRetryBefore 重新生成数据(如新卡号)

8. 代码vs配置的选择

场景 推荐方式 原因
点击、填表、等待 YAML 简单、可维护
数据提取 YAML (extract) + 处理(custom) 提取配置化,处理逻辑化
结果验证 YAML (verify) 轮询检测、触发重试
验证码、人机验证 custom 复杂逻辑
条件判断、循环 custom YAML 不支持
数据库操作 custom 需要导入模块

完整示例

查看 src/automation-framework/configs/sites/windsurf.yaml 了解完整的真实案例。


常见问题

Q: 如何调试 YAML 配置?

A: 查看日志输出,每个步骤都会打印执行信息:

[Windsurf] [1/14] 打开注册页面
[Windsurf] 导航到: https://windsurf.com/account/register
[Windsurf] ✓ 页面加载完成

Q: 元素找不到怎么办?

A:

  1. 使用 verifyElements 验证元素存在
  2. 增加 waitAfter 等待时间
  3. 使用多个选择器备选
  4. 设置 optional: true 跳过

Q: 如何处理动态内容?

A: 使用 wait action 等待元素出现:

- action: wait
  type: element
  find:
    - css: '.dynamic-content'
  timeout: 15000

Q: 变量替换不生效?

A: 检查:

  1. 变量路径是否正确(如 {{account.email}}
  2. 是否在 beforeWorkflow() 中设置了 this.context.data
  3. 日志中查看变量值

Q: verify 失败会终止整个流程吗?

A: 不会!

  • retryBlock 内使用 onFailure: "throw",失败会触发重试
  • 只有所有重试都失败,才会终止流程
  • 单次失败只是触发重试,不影响整体流程

Q: 如何避免重试时重复处理验证码?

A: 将验证码处理放在 retryBlock 外面:

# ✅ 正确:验证码只处理一次
- action: custom
  handler: "handleCaptcha"

- action: retryBlock
  steps:
    - 填写表单
    - 提交
    - 验证

# ❌ 错误:每次重试都处理验证码
- action: retryBlock
  steps:
    - action: custom
      handler: "handleCaptcha"
    - 填写表单
    - 提交

Q: verify 的 timeout 和 retryBlock 的 maxRetries 有什么区别?

A:

  • verify 的 timeout单次验证的轮询时间如检测支付结果15秒
  • retryBlock 的 maxRetries失败后重试的次数如支付失败重试5次
  • 总耗时 ≈ timeout × maxRetries(如 15秒 × 5次 = 75秒

更新日志

  • v1.0.0 - 基础框架
    • navigate, fillForm, click, wait, custom
  • v1.1.0 - 增强功能
    • retryBlock 重试块
    • 人类行为模拟
    • 点击验证
  • v1.2.0 - 数据提取
    • extract action
    • 正则提取
    • 多元素提取
  • v1.3.0 - 结果验证
    • verify action
    • 支持 10 种条件类型
    • 轮询检测机制
    • 配合 retryBlock 实现智能重试

框架持续演进中,欢迎贡献新功能! 🚀