文档中心

BAL 语言

浏览器自动化语言 BAL 的完整语法与命令参考。

简介

BAL(Browser Automation Language)是一门面向浏览器自动化的领域特定语言。它把「找元素」和「做什么」彻底解耦:语言本身只描述意图,由执行器翻译成 Playwright 调用。

核心目标

  • 站点无关:语言不内置任何站点逻辑,站点差异放在 .page 配置中。
  • 输入优先兼容:所有输入默认走多策略降级 + 验证,不假设 fill 有效。
  • 上传全覆盖:图片、视频、附件、目录、拖拽、粘贴、分片,七种路径。
  • 标签独立抽象:把「输入 + 联想 + 选择 + 去重 + 验证」封装成一条命令。
  • 可扩展:命令、选择器策略、上传策略均通过注册表扩展,不改语言核心。

参数声明

声明输入参数:key / 名称 / 类型 / 必填标记,运行时按 {key} 替换并自动校验。

@input · 输入参数

# @input prompt 提示词 text 必填

声明输入参数:key / 名称 / 类型 / 必填标记,运行时按 {key} 替换并自动校验。

@output · 输出参数

# @output images 图片列表 text

声明输出参数:key / 名称 / 类型,运行结果写入工作日志并可被下一节点引用。

设计原则

原则说明
站点无关语言不内置任何站点逻辑,差异放 .page 配置
输入优先兼容所有输入默认走多策略降级 + 验证,不假设 fill 有效
显式等待不靠 sleep,用 wait_until 等待真实状态
可验证每个写操作都可 verify:true,失败降级而非静默
可扩展命令、选择器策略、上传策略均通过注册表扩展
可读可 diff纯文本行式语法,支持注释与模块化

目录

1. 词法规范

基本单位

  • 一行一条命令,# 开头为注释
  • 命令名小写蛇形:wait_until、set_input_files
  • 字符串双引号,支持 \" \\ \n \t 转义
  • 参数形式:位置参数 "值"、键值参数 key:value、选项 [opt=val]
  • 变量 $name,常量 UPPER_CASE 约定为全局

注释与空行

# 整行注释
goto "https://example.com"   # 行尾注释

续行

# 长命令用 \ 续行
upload css:"input[type=file]" \
    files:"a.jpg","b.png" \
    mode:auto \
    verify:true

字符串插值

set $name = "世界"
echo "你好,${name}"          # 你好,世界
echo "你好,$name"            # 同上,简单变量可省花括号

2. 选择器语法

统一形式:<策略>:<值>[修饰符]

策略表

策略示例对应 Playwright
texttext:"登录"get_by_text
rolerole:button["提交"]get_by_role
labellabel:"邮箱"get_by_label
placeholderplaceholder:"搜索"get_by_placeholder
testidtestid:"submit-btn"get_by_test_id
titletitle:"关闭"get_by_title
altalt:"封面"get_by_alt_text
csscss:".btn.primary"locator
xpathxpath:"//button[@type='submit']"locator
nthnth:3当前上下文第 4 个
refref:$saved引用之前保存的元素句柄

修饰符

click text:"删除" [nth=2]        # 第 3 个匹配
click text:"删除" [last]
click text:"删除" [first]
click text:"删除" [visible=true]  # 只匹配可见元素
click css:".item" [filter="含关键词"]
click role:button["提交"] [exact=true]

链式定位

# 在某个容器内查找
click css:".modal" >> text:"确认"
# 父子、兄弟关系
click css:".form" > placeholder:"用户名"
click text:"用户名" + css:".error"

元素句柄保存

find placeholder:"标题" -> $title_input
input $title_input value:"测试"

3. 变量与表达式

赋值

set $count = 0
set $url = $BASE + "/page/" + $count
set $pwd = env("APP_PASSWORD")
set $user = input("请输入用户名")
set $now = now()
set $id = uuid()
set $n = random(1, 100)

内置函数

函数说明
now([format])当前时间
uuid()UUID v4
random(min, max)随机整数
env(name)环境变量
input(prompt)运行时输入
file(path)读取文件内容
glob(pattern)文件通配
trim(s) / lower(s) / upper(s)字符串处理
split(s, sep) / join(list, sep)列表处理
len(list) / index(list, i)列表操作
json(str) / to_json(obj)JSON 处理
base64_encode(s) / base64_decode(s)编码
sleep(ms)暂停(表达式内用)

表达式

set $total = $price * $qty
set $ok = $count > 3 and $name != ""
set $msg = "共 " + str($count) + " 条"

支持:+ - * / %、== != > < >= <=、and or not、括号。

4. 指令总览

【配置与会话】 config  session  context  page  viewport  user_agent  locale  timezone
【导航】       goto  back  forward  reload  open  switch_tab  close_tab  wait_for_load
【查找】       find  find_all  exists  count
【输入】       input  fill  type  type_slow  paste  clear  press  press_seq  ime_input
【点击】       click  dblclick  right_click  hover  focus  blur  tap
【表单】       check  uncheck  select  select_multi  set_date  set_time  set_range
【上传】       upload  upload_dir  upload_drag  upload_paste  upload_chunked  cancel_upload
【标签】       tag_add  tag_remove  tag_select  tag_clear  tag_list
【鼠标】       drag  drag_to  scroll_to  scroll_by  scroll_into_view
【键盘】       keyboard_press  keyboard_type  keyboard_down  keyboard_up
【等待】       wait  wait_until  wait_for_url  wait_for_response  wait_for_download
【断言】       assert  assert_exists  assert_text  assert_url  assert_count
【提取】       get_text  get_attr  get_value  get_count  get_url  get_title  get_html
【流程】       if/elif/else/endif  loop/endloop  foreach/endforeach  while/endwhile
               break  continue  return
【函数】       func/endfunc  call  import
【错误】       try/catch/finally  on_error  retry
【弹窗】       dialog_accept  dialog_dismiss  dialog_handle
【框架】       frame  frame_exit  frame_main
【窗口】       new_window  switch_window  close_window
【网络】       intercept  mock  block  unblock  route  unroute
【存储】       storage_save  storage_load  cookie_set  cookie_get  cookie_clear
【调试】       screenshot  echo  log  pause  trace_start  trace_stop  dump

5. 配置与会话

config(全局配置)

config timeout=30000
config screenshot_on_error=true
config input_mode=auto            # auto | fast | compat | human
config input_delay=30
config input_verify=true
config input_max_retry=2
config upload_timeout=180000
config headless=false
config slow_mo=0

session(会话)

session new
session load "account.json"
session save "account.json"
session close

context / page

context new [viewport=1920x1080] [locale=zh-CN] [timezone=Asia/Shanghai]
context close
page new
page close
page switch 0
page list -> $pages

viewport / user_agent / locale

viewport 1440 900
user_agent "Mozilla/5.0 ..."
locale "zh-CN"
timezone "Asia/Shanghai"
geolocation 31.23 121.47
permissions ["geolocation", "notifications"]

7. 查找与存在性

find <selector> -> $var
find_all <selector> -> $list
exists <selector> -> $bool
count <selector> -> $n
find placeholder:"标题" -> $title
find_all css:".item" -> $items
exists text:"加载更多" -> $has_more
count css:".comment" -> $n

8. 输入命令族核心

设计要点:所有输入默认走多策略降级 + 验证。不假设 fill() 有效,因为 React/Vue 受控组件、contenteditable 富文本、有输入联动的输入框经常不响应直接赋值。

统一入口 input

input <selector> value:"..." 
    mode:auto|fast|type|type_slow|keyboard|native|richtext|ime
    delay:30
    clear:true
    verify:true
    on_fail:abort|continue|retry(3,1000)

模式说明

mode行为适用
fast直接 fill静态表单、非受控
typepress_sequentially(delay)普通 React 组件
type_slow逐字符,delay≥100有联想的搜索框
keyboardclick + Ctrl+A + Delete + keyboard.type强风控、IME
nativenative setter + 派发 input/changeReact/Vue 受控
richtextcontenteditable 专用链富文本编辑器
ime派发 composition 事件中日韩输入法
auto检测类型 → 策略链降级 → 验证默认推荐

自动降级流程

input mode:auto
  ├─ 检测元素类型
  │   ├─ input/textarea  → 表单策略链
  │   ├─ contenteditable → 富文本策略链
  │   └─ 未知            → 先试表单,再试富文本
  ├─ 表单策略链:fill → press_sequentially → keyboard.type → native_setter
  ├─ 富文本链:press_seq → insert_text → execCommand → innerText
  ├─ 每步验证:input_value() 或 inner_text()
  ├─ 失败降级,全部失败 → 截图 + trace + on_fail
  └─ 返回实际生效策略名(写入日志)

专用命令

fill placeholder:"标题" value:"测试"
type placeholder:"标题" value:"测试" delay:50
type_slow placeholder:"搜索" value:"Playwright" delay:150
paste css:".editor" value:"很长的正文..."
clear placeholder:"标题"
press css:".editor" key:"Enter"
press css:".editor" key:"Control+A"
press_seq css:".editor" value:"逐字符输入" delay:30
ime_input css:".editor" value:"中文输入法内容"

只读 / 禁用自动解锁

# mode:auto 检测到 readOnly/disabled 时自动执行:
el.readOnly = false; el.disabled = false;
unlock placeholder:"只读字段"
lock placeholder:"字段"

输入验证

input placeholder:"标题" value:"测试" verify:true
assert_value placeholder:"标题" equals "测试"
assert_value placeholder:"标题" contains "测"

9. 文件上传核心

统一入口 upload

upload <selector> 
    files:"a.jpg","b.png"
    mode:auto|input|drag|paste|chunked|dir
    cover:"a.jpg"
    verify:true
    timeout:180000
    on_fail:abort|continue|retry(3,1000)

模式说明

mode行为适用
input直接 set_input_files标准 input[type=file]
drag模拟拖拽到目标区域无 input、纯拖拽上传
paste模拟粘贴文件支持粘贴上传的编辑器
chunked分片上传大文件视频、大附件
dir上传整个目录webkitdirectory
auto检测 → 策略链降级默认推荐

策略链

upload mode:auto
  ├─ 查找 input[type=file]
  │   ├─ 存在且 visible/attached → set_input_files
  │   └─ 隐藏 → 直接 set_input_files(无需可见)
  ├─ 无 input → 点击上传触发区 → 等待 input 出现 → set_input_files
  ├─ 仍无 input → 尝试 drag 策略
  ├─ 仍失败 → 尝试 paste 策略
  ├─ 大文件(>50MB)→ 自动切 chunked
  ├─ 等待上传完成:缩略图数量 / 进度条消失 / 网络空闲
  └─ 校验:文件数量、封面、缩略图存在

图片上传

upload css:"input[type=file]" files:"cover.jpg","detail1.png","detail2.png"
upload css:"input[type=file]" files:glob("assets/*.jpg")
upload css:".upload-area" files:"cover.jpg" mode:drag
upload css:".editor" files:"screenshot.png" mode:paste
upload css:"input[type=file]" files:"a.jpg" cover:"a.jpg" verify:true

视频上传

upload css:"input[type=file]" files:"video.mp4" mode:auto timeout:600000
upload css:"input[type=file]" files:"video.mp4" mode:chunked chunk_size:5242880
assert_uploaded css:".video-item" count:1
wait_until text:"视频上传完成" timeout:600000

附件上传

upload css:"input[type=file]" files:"doc.pdf","sheet.xlsx"
upload css:"input[type=file]" files:"archive.zip" verify:true

目录上传

upload_dir css:"input[type=file]" dir:"assets/images"

拖拽 / 粘贴 / 分片

upload_drag css:".drop-zone" files:"cover.jpg"
drag_file css:".drop-zone" path:"cover.jpg"
upload_paste css:".editor" path:"screenshot.png"
upload_chunked css:"input[type=file]" path:"big-video.mp4" chunk_size:5242880

上传控制

cancel_upload                    # 取消当前上传
pause_upload                     # 暂停(若页面支持)
resume_upload
assert_uploaded <selector> count:<n>
wait_upload_complete timeout:180000

10. 标签与话题核心

设计要点:标签交互是「输入 + 联想 + 选择」的组合。单独抽象成命令族,把「输入关键词 → 等待联想 → 选择候选 → 去重 → 验证」封装成一条命令。

tag_add

tag_add <selector> 
    value:"Playwright"
    mode:auto|type|select|enter|comma
    wait_suggest:true
    select:nth(0)|first|exact|contains
    verify:true
    dedup:true

交互流程

tag_add mode:auto
  ├─ 点击标签输入入口(或 # 触发)
  ├─ 输入关键词(走 input mode:auto)
  ├─ 等待联想候选出现
  ├─ 选择候选:
  │   ├─ select:first       → 第一个
  │   ├─ select:nth(2)      → 第三个
  │   ├─ select:exact       → 文本完全匹配
  │   └─ select:contains    → 文本包含
  ├─ 或按 Enter/逗号 直接创建
  ├─ 验证标签 chip 出现
  └─ 去重(已存在则跳过)

示例

# 小红书话题
tag_add placeholder:"搜索话题" value:"Playwright" select:exact
tag_add placeholder:"搜索话题" value:"自动化测试" select:first
tag_add placeholder:"搜索话题" value:"小红书运营" select:contains

# 批量
foreach $t in ["Playwright", "自动化", "测试"]
    tag_add placeholder:"搜索话题" value:$t select:first
endforeach

其他标签命令

tag_remove placeholder:"搜索话题" value:"Playwright"
tag_clear placeholder:"搜索话题"
tag_list -> $tags                      # 提取当前所有标签
tag_select css:".tag-list" value:"已有标签"   # 从已有列表中选择
assert_tag placeholder:"搜索话题" contains "Playwright"
assert_tag_count placeholder:"搜索话题" equals 3

标签触发方式

# 通过 # 触发
tag_add css:".editor" value:"Playwright" trigger:"#"

# 通过按钮触发
tag_add css:".editor" value:"Playwright" trigger:click

# 直接输入 + 回车
tag_add css:".tag-input" value:"Playwright" mode:enter

11. 表单控件

复选框 / 单选

check css:"#agree"
uncheck css:"#subscribe"
check css:".radio-option" [value="A"]
is_checked css:"#agree" -> $checked

下拉选择

select css:"#city" value:"上海"
select css:"#city" label:"上海市"
select css:"#city" index:2
select_multi css:"#tags" values:"A","B","C"
deselect css:"#city" value:"上海"
select_native css:"#city" value:"上海"     # 原生 select
select_custom css:".dropdown" value:"上海" # 自定义下拉

日期 / 时间 / 范围

set_date css:"#date" value:"2026-09-29"
set_time css:"#time" value:"14:30"
set_range css:"#price" value:500
set_color css:"#color" value:"#ff0000"

滑块 / 评分

set_slider css:".slider" value:75
set_rating css:".rating" value:5

12. 点击与鼠标

click <selector> [button=left|right|middle] [click_count=1] [force=false]
dblclick <selector>
right_click <selector>
hover <selector>
focus <selector>
blur <selector>
tap <selector>                     # 触摸
click_at x:100 y:200
click_position <selector> x:10 y:10
drag <from> to <to>
drag_to <selector> target:<selector>
scroll_to <selector>
scroll_by x:0 y:500
scroll_into_view <selector>
scroll_top / scroll_bottom

13. 键盘

keyboard_press "Enter"
keyboard_press "Control+A"
keyboard_type "Hello" delay:50
keyboard_down "Shift"
keyboard_up "Shift"
keyboard_insert_text "中文文本"

14. 等待与同步

wait 1000
wait_until <selector> [state=visible|hidden|attached|detached] [timeout=30000]
wait_until url contains "/dashboard"
wait_until url equals "https://..."
wait_until text:"加载完成"
wait_until title contains "首页"
wait_until count css:".item" >= 10
wait_for_url "**/dashboard"
wait_for_response url contains "/api/user"
wait_for_request url contains "/api/submit"
wait_for_download to:"file.pdf"
wait_for_popup -> $new_page
wait_for_function "() => window.ready === true"
wait_for_load state:networkidle
wait_for_timeout 3000

15. 断言

assert exists <selector>
assert not_exists <selector>
assert visible <selector>
assert hidden <selector>
assert enabled <selector>
assert disabled <selector>
assert text <selector> equals "预期"
assert text <selector> contains "包含"
assert text <selector> matches "/正则/"
assert value <selector> equals "值"
assert attr <selector> name:"href" contains "/home"
assert url contains "/dashboard"
assert title equals "首页"
assert count <selector> equals 5
assert count <selector> >= 3
assert checked css:"#agree"
assert uploaded <selector> count:3
assert tag <selector> contains "Playwright"
assert no_console_error
assert no_network_error
# 失败策略
assert exists css:".ad" on_fail:continue
assert exists css:".required" on_fail:abort
assert exists css:".optional" on_fail:retry(3, 1000)

16. 数据提取

get_text <selector> -> $var
get_text_all <selector> -> $list
get_attr <selector> name:"href" -> $url
get_value <selector> -> $val
get_html <selector> -> $html
get_inner_html <selector> -> $html
get_count <selector> -> $n
get_url -> $url
get_title -> $title
get_cookie name:"session" -> $cookie
get_local_storage key:"token" -> $token
get_all_text -> $page_text
get_screenshot <selector> to:"el.png"
# 批量提取
get_all css:".item" -> $items {
    text: "get_text(css:'.title')",
    link: "get_attr(css:'a', 'href')",
    price: "get_text(css:'.price')"
}

17. 流程控制

条件

if $count > 3
    echo "超过阈值"
elif $count == 0
    echo "零"
else
    echo "正常"
endif

计数循环

loop 5 times
    click text:"下一页"
    wait 1000
endloop

遍历

foreach $item in ["a", "b", "c"]
    echo $item
endforeach

foreach $file in glob("assets/*.jpg")
    upload css:"input[type=file]" files:$file
endforeach

条件循环

while exists text:"加载更多"
    click text:"加载更多"
    wait 1000
endwhile

循环控制

loop 10 times
    if exists text:"结束"
        break
    endif
    if not_exists text:"继续"
        continue
    endif
endloop

返回

func check()
    if not_exists css:".ok"
        return false
    endif
    return true
endfunc

18. 函数与模块

定义与调用

func login(user, pass)
    goto $BASE + "/login"
    input placeholder:"用户名" value:$user
    input placeholder:"密码" value:$pass mode:keyboard
    click role:button["登录"]
    wait_until url contains "/home"
endfunc

call login("admin", env("APP_PASSWORD"))

默认参数

func publish(title, body, tags = [])
    input placeholder:"标题" value:$title
    input role:textbox[first] value:$body mode:richtext
    foreach $t in $tags
        tag_add placeholder:"搜索话题" value:$t select:first
    endforeach
    click text:"发布"
endfunc

模块导入

import "lib/xhs.bal"
import "lib/common.bal"

call xhs_publish("标题", "正文", ["标签1", "标签2"])

模块导出

# lib/xhs.bal
export func xhs_login(session_file)
    ...
endfunc

export func xhs_publish(title, body, tags)
    ...
endfunc

19. 错误处理

try / catch / finally

try
    click text:"提交"
    wait_until text:"成功"
catch e
    echo "失败: " + $e.message
    screenshot "error.png"
finally
    echo "清理"
endtry

on_error 修饰

click text:"提交" on_error:retry(3, 1000)
click text:"可选广告" on_error:continue
upload css:"input[type=file]" files:"a.jpg" on_error:abort

全局错误策略

config on_error=abort            # abort | continue | retry
config screenshot_on_error=true
config trace_on_error=true

20. 弹窗 · 框架 · 窗口

原生弹窗

dialog_accept
dialog_dismiss
dialog_handle accept
dialog_handle dismiss
dialog_prompt "输入内容"
on_dialog accept

iframe

frame css:"iframe#login"
    input placeholder:"用户名" value:"admin"
    click text:"登录"
frame_exit
frame_main

多窗口

new_window "https://example.com" -> $page
switch_window 1
switch_window title contains "新窗口"
close_window

21. 网络与存储

拦截与模拟

intercept url contains "/api/user" -> $response
mock url contains "/api/user" body:{"name": "test"} status:200
block url contains ".png"
unblock url contains ".png"
route url contains "/api/**" handler:"mock_handler"
unroute
wait_for_response url contains "/api/submit"

存储

storage_save "state.json"
storage_load "state.json"
cookie_set name:"token" value:"xxx" domain:".example.com"
cookie_get name:"token" -> $token
cookie_clear
local_storage_set key:"token" value:"xxx"
local_storage_get key:"token" -> $val

22. 调试

screenshot "step1.png"
screenshot <selector> to:"element.png"
echo "当前 URL: " + get_url()
log info "步骤完成"
pause                              # 打开 Inspector
trace_start "trace.zip"
trace_stop
dump html -> "page.html"
dump text -> "page.txt"
dump console -> "console.log"
dump network -> "network.har"
highlight <selector>

23. 扩展机制

注册自定义命令

# Python 侧
@executor.register("xhs_publish_note")
async def publish_note(ctx, title, body, tags):
    ...

# BAL 侧
xhs_publish_note title:"标题" body:"正文" tags:["a","b"]

注册选择器策略

STRATEGIES["data"] = lambda p, v: p.locator(f'[data-{v}]')

click data:action="submit"

注册上传策略

UPLOAD_STRATEGIES["websocket"] = upload_via_ws

upload css:"#file" files:"a.jpg" mode:websocket

站点配置 .page

site: xiaohongshu
base_url: "https://www.xiaohongshu.com"
selectors:
  creator_button:  'text:"创作中心"'
  title_input:     'placeholder:"添加标题"'
  body_editor:
    selector: 'role:textbox[first]'
    input_mode: richtext
  upload_input:    'css:input[type="file"]'
  hashtag_entry:   'text:"#添加话题"'
  hashtag_search:  'placeholder:"搜索话题"'
input_defaults:
  mode: auto
  verify: true
upload_defaults:
  mode: auto
  timeout: 180000

load_page "xiaohongshu.page"
goto creator
input $title_input value:"标题"

24. 完整示例

小红书图文发布

# xhs_publish.bal
config input_mode=auto
config input_verify=true
config screenshot_on_error=true

load_page "xiaohongshu.page"
session load "account.json"

goto creator

# 上传图片(第一张为封面)
upload $upload_input \
    files:"cover.jpg","detail1.png","detail2.png" \
    mode:auto \
    cover:"cover.jpg" \
    verify:true
wait_upload_complete timeout:120000

# 标题(React 受控 input)
input $title_input value:"Playwright 自动化发布测试" mode:auto verify:true

# 正文(contenteditable 富文本)
input $body_editor value:"这是正文内容,测试富文本输入。" mode:richtext delay:30

# 标签
foreach $t in ["Playwright", "自动化测试", "小红书运营"]
    tag_add $hashtag_search value:$t select:first verify:true
endforeach

assert_tag_count $hashtag_search equals 3

# 发布
click text:"发布"
wait_until url contains "/publish/success" timeout:60000
screenshot "publish_result.png"

session save "account.json"

视频上传 + 附件

config upload_timeout=600000

upload css:"input[type=file]" files:"video.mp4" mode:chunked chunk_size:5242880
wait_until text:"视频上传完成" timeout:600000
assert_uploaded css:".video-item" count:1

upload css:"input[type=file]" files:"cover.jpg" mode:auto
upload css:"input[type=file]" files:"doc.pdf","sheet.xlsx"

带错误恢复的批量操作

foreach $item in $items
    try
        input placeholder:"搜索" value:$item mode:type_slow delay:150
        wait_until css:".result-item" state:visible
        click css:".result-item" [first]
        click text:"收藏"
        wait_until text:"已收藏"
    catch e
        log error "处理失败: " + $item + " - " + $e.message
        screenshot "error_" + $item + ".png"
        continue
    endtry
endforeach

25. 附录速查

选择器策略速查

text · role · label · placeholder · testid · title · alt · css · xpath · nth · ref

输入模式速查

fast · type · type_slow · keyboard · native · richtext · ime · auto

上传模式速查

input · drag · paste · chunked · dir · auto

错误码

错误码含义
E_SELECTOR_NOT_FOUND选择器无匹配
E_TIMEOUT等待超时
E_INPUT_FAILED所有输入策略失败
E_UPLOAD_FAILED上传失败
E_ASSERT_FAILED断言失败
E_DIALOG_UNHANDLED弹窗未处理
E_FRAME_NOT_FOUNDiframe 未找到
E_NETWORK_ERROR网络错误
E_PERMISSION_DENIED权限不足

覆盖度清单

类别覆盖
导航goto/back/forward/reload/多标签/多窗口
元素查找/点击/悬停/拖拽/滚动/焦点
输入表单/富文本/只读/IME/受控组件/验证
上传图片/视频/附件/目录/拖拽/粘贴/分片
标签输入/联想/选择/删除/去重/批量
表单复选/单选/下拉/日期/时间/范围/滑块
等待元素/URL/文本/网络/下载/弹窗/函数
断言存在/可见/文本/属性/数量/上传/标签
提取文本/属性/HTML/Cookie/Storage
流程条件/循环/遍历/break/continue/return
函数定义/调用/默认参/导入/导出
错误try/catch/finally/retry/on_error
弹窗alert/confirm/prompt
框架iframe 进出
网络拦截/模拟/屏蔽/等待
存储session/cookie/localStorage
调试截图/日志/暂停/trace/dump

结语

三大核心设计
  • 输入不假设:input mode:auto 把兼容性做到最高,任何输入框都有降级路径。
  • 上传不假设:upload mode:auto 覆盖 input、拖拽、粘贴、分片、目录五种路径。
  • 标签单独抽象:tag_add 把「输入 + 联想 + 选择 + 去重 + 验证」封装成一条命令。

配合 .page 站点配置和命令注册表,这套 DSL 可以在不改语言核心的前提下,适配任意站点、任意控件,覆盖从导航到上传到提取的完整网页操作链路。