核心用法 / Core Usage
等待与断言
Agent 翻车,更多是败在乱等,而不是选错元素。
点完、填完之后,页面还在动——这时候该等什么、怎么确认动作真的生效,
决定了你的脚本是稳还是脆。这一页讲清楚 wait 怎么等、
expect 怎么断言、--observe 怎么看变化,
以及 --if-present 怎么让可选步骤保持幂等。
观察质量由 observed.status 的 complete、partial、unavailable 表示,动作 success 值不因观察失败而改写。证据不足时 changed 为 null,不会伪造空页面或 URL。基线失败但后置树可用时返回后置树。不完整观察会附错误和 retryAction:false,应检查当前状态,不要为了补观察重放动作。
选对等待条件 — wait
每次会改变页面的动作之后,都要挑一个具体的条件去等,
而不是拍脑袋 sleep 一个固定毫秒数。wait 支持这些形式:
$ chrome-use wait @e1 # 直到某个元素出现
$ chrome-use wait 2000 # 傻等,毫秒(最后手段)
$ chrome-use wait --text "Success" # 直到页面上出现这段文字
$ chrome-use wait --url "**/dashboard" # 直到 URL 匹配模式(glob)
$ chrome-use wait --load networkidle # 直到网络空闲(导航后收尾)
$ chrome-use wait --load domcontentloaded # 直到 DOMContentLoaded
$ chrome-use wait --fn "window.myApp.ready === true" # 直到 JS 条件成立
任何会改变页面的动作之后,从下面三种里挑一个:
- 等你预期会出现的具体元素:
wait @ref或wait --text "..."。 - 等 URL 变化:
wait --url "**/new-page"。 - 等网络空闲(SPA 导航的万能兜底):
wait --load networkidle。
wait 2000——它让脚本又慢又脆。
超时默认 25 秒,所以等一个真实条件不会白等太久,但会在条件满足的那一刻就继续。
读之前它自己会等 — settle
一次观察值多少,取决于它拍下的那一刻页面在做什么。所以
snapshot 和 --observe 会先等页面停下来再采集,
你不需要在前面自己塞一个 sleep:
- DOM 连续 100ms 没有变更,
- 没有还在跑的有限时长过渡/动画(无限循环的 loading 转圈会被忽略——它永远不结束),
- 你刚触发的动作发出的请求都已经回来。
以最慢的那个为准,上限 1 秒。静态页面大约只花 100ms; 而一次触发 XHR 的点击会等到响应回来,而不是把「响应前的树」当成结果返回。
两者有一处不同:单独的 snapshot 没有动作要反应,页面静止就是答案,安静了立刻返回;
而动作之后的 --observe 会先花上限的一半(默认 500ms)盯着「有没有第一个反应」,
才肯报 changed:false —— 否则一个 300ms 后才渲染的控件会被读成「什么都没发生」。
这份代价只由真的什么都没做的动作承担;只要页面有反应,窗口立刻结束。
$ chrome-use snapshot -i --settle-ms 3000 # 慢页面:把上限调高
$ chrome-use snapshot -i --no-settle # 就要中间态:不等,立刻采
Page had not settled after 1000ms (request in flight still active) — this capture
may be mid-transition. Re-read to confirm, or raise the ceiling with
AGENT_BROWSER_SETTLE_MS.——意思是这张树可能是中间态,请重读一次再信它。
中间态被当成最终态返回,比慢更糟,所以这条永远不会被吞掉。
既然已经等过一次,像素就可以搭这趟车:--with-screenshot <path>
让 snapshot 或带 --observe 的动作在同一个稳定时刻
同时留下结构和截图(各等各的会得到两个时刻的东西,那比不合并还糟)。结构照旧走 stdout,
图片落盘并在输出里报路径 —— 截图在这里是输出,不是 agent 读页面的方式。
全局可用 AGENT_BROWSER_SETTLE_MS(设 0 关闭等待)和
AGENT_BROWSER_SETTLE_QUIET_MS 调。等某个具体条件
仍然是 wait 的活:settle 只知道页面停了,不知道你要的东西出现了没有。
确认动作生效 — expect
动作做完之后,用断言去确认结果,而不是拉一张快照用眼睛看。
expect 是一个带退出码的 pass/fail 动词
(0 通过 / 1 为假 / 2 无法判断),所以它能和 &&、
chrome-use batch 组合,而且只花 ~1 行、不用你去读一整张快照。
$ chrome-use click @e8 && chrome-use expect "#toast" visible # toast 弹出来了吗?
$ chrome-use expect count ".result" ">=" 1 # 结果加载出来了吗?
$ chrome-use expect text @e3 contains "Saved" # 成功提示?
$ chrome-use expect url contains /dashboard # 导航落地了吗?
$ chrome-use expect "#spinner" gone # 加载完成了?
$ chrome-use requests --clear && chrome-use click @save \
&& chrome-use expect request /api/save --status 2xx # POST 发出且 2xx?
$ chrome-use expect no-errors # 没有 console 报错?
expect 自带等待
expect 会在超时时间内轮询、等条件成立,
所以你常常不需要再单独写一个 wait。支持的条件有:
- 元素状态:
visible|hidden|gone|present; - 数量:
count <css> <op> <n>; - 文本/值/属性:
text|value|attr … equals|contains|matches; - URL:
url …; - 网络请求:
request <substr> [--status 2xx]; - 控制台:
no-errors。
--not 反转判断,--no-wait 只检查一次不轮询。
expect request 只能看到开始跟踪之后捕获的请求——
先跑一次 requests --clear;no-errors 需要控制台捕获——
先跑一次 console。详见 排查问题。
看清动作改了什么 — --observe
请求最多显示 20 条摘要,每条最多 256 个 UTF-8 字节;data URL 只显示媒体头和编码后载荷大小。JSON 同时返回 requestsTotal、requestsOmitted、requestsShortened。完整记录用 network requests --json 查看。changed:false 只表示树与 URL 没变,有请求时仍显示摘要。
给一个会改变页面的动作(click / fill / type /
select / check / press / eval)
加上 --observe,就不用你手动跑「动作 → wait → snapshot → diff」那一套了:
返回结果里会带一个 observed 增量——新增/移除的可交互行
(新的 toast、校验提示也会通过 alert 面通道带上)、URL 变化、发出的请求;
什么都没动就返回 {changed:false}。
$ chrome-use click @e8 --observe # 读取动作后的变化和有界请求摘要
--observe 不再给「旧树全删 + 新树全增」的 diff,
而是在 observed snapshot: 下直接给新页面的树,前面一行说明旧页面有多少行已不在。
判定条件是两棵树都有页面规模(≥20 行)且各自 ≥80% 的行换掉;树里的 ref 是活的,直接用。
&&、批处理)用
expect;想看清到底发生了什么、拿到结构化的变化用 --observe。
一次填完整张表单 — form fill --map
与其写 N 步 fill / select / check,
不如传一个 {标签或选择器: 值} 的映射:它按 <label>、
aria-label、placeholder、name、CSS 逐个解析字段,自动派发到对应的控件类型
(字符串 → 文本/下拉/单选,true/false → 复选框),
还能顺手提交(--submit "<文本|选择器>"),返回
{filled, submitted, errors}——errors 就是行内校验消息,
所以一次提交被拒会在同一次调用里告诉你为什么。
$ chrome-use form fill --map \
'{"Email":"a@b.com","Country":"US","Subscribe":true}' \
--submit "Sign up"
fill 单独填——它能处理;
form fill 覆盖的是标准控件。更多输入细节见 交互操作。
可选步骤 — --if-present
给任意基于选择器的动作加上 --if-present(别名 --optional),
当目标不存在时它就变成一个空操作但成功(↷ skipped,退出码 0),
而不是报错——不用事先读一遍页面判断,流程也能反复重跑。
$ chrome-use click ".cookie-accept" --if-present # 关掉可能不存在的 cookie 横幅
$ chrome-use check "#opt-in" --if-present
--if-present 只对「目标缺失」放行;真正的失败(比如元素在但点不动)
仍然会报错,不会被悄悄吞掉。