核心用法 / Core Usage

定位元素

大多数时候 snapshot 拿到的 @ref 就够用了。但有时 ref 会失效、目标藏在隐藏状态里、或者你干脆不想先截一次 snapshot。 这一页讲另一套锁定目标的手段——find 语义定位器、原始 CSS、坐标点击——以及从结构化定位一路 升级到 eval 的阶梯。

什么时候不用 @ref

@ref 是最快的路径,但它建立在每次 snapshot 之上,页面一变就会过期。 当你遇到下面这些情况,直接用语义定位器或 CSS 更省事:


find 语义定位器

find 按语义而不是 ref 来锁定元素:角色 + 名字、可见文本、表单 label、placeholder、data-testid,或者「第一个 / 第 N 个」匹配。命中后直接跟一个动作动词 (click / fill / type / hover …)。 find label 不止匹配 <label> 元素——也会匹配 aria-label 和 aria-labelledby,所以只靠 ARIA 标注、没有 <label> 标签的图标按钮和自定义控件也能被找到。 如果还不知道 locator 类型,直接传一段自然语言描述;chrome-use 会按名称、文本、祖先上下文和 role 排序返回候选,并附上 cursor 与精简 selector 锚点,不会自动点击。

find — 语义定位器
$ chrome-use find role button click --name "Submit"
$ chrome-use find "编辑 Web服务规则 设置按钮"       # 只返回排序候选
$ chrome-use find query "edit settings button"       # 显式自然语言语法
$ chrome-use find text "Sign In" click
$ chrome-use find text "Sign In" click --exact     # 仅精确匹配
$ chrome-use find label "Email" fill "user@test.com"
$ chrome-use find label "Close" click            # 命中只有 aria-label="Close" 的图标按钮
$ chrome-use find placeholder "Search" type "query"
$ chrome-use find testid "submit-btn" click
$ chrome-use find first ".card" click
$ chrome-use find nth 2 ".card" hover
✅ 先核对真实的标签文字
翻译会坑你。真实案例:LinkedIn 的「Save」按钮标签是 收藏 而不是 保存, 所以 find text "保存" 什么都找不到,而 snapshot -i 一直显示 button "收藏" [ref=eN]——直接 click @eN 就行。下结论「元素不存在」之前,先确认它的确切标签。

原始 CSS 选择器

任何动作动词都能直接吃一个 CSS 选择器,无需先 find:

CSS 选择器
$ chrome-use click "#submit"
$ chrome-use fill "input[name=email]" "user@test.com"
$ chrome-use click "button.primary"
$ chrome-use click "//button[@type='submit']"   # 以 //、/、(、./ 或 .. 开头即视为 XPath,无需 xpath= 前缀
ℹ️ XPath 的 text() 只看第一个直接文本节点
//button[text()='Save'] 在文本被拆成多个节点(React 的 {a} - {b})或嵌在子元素里时永远匹配不到。 改用 contains(normalize-space(.), '…'),或者 find "<label>" / text=<label> / snapshot -i + @ref。带 text() 的 XPath 匹配为空时,报错会直接解释这个坑; 「Element not found」也会保留原选择器和解析器的具体诊断,不再一律归咎于 closed shadow root / 跨源 iframe。

升级阶梯

定位一个元素有一条从便宜到万能的阶梯。按顺序往下走,别在某一档上死磕:

① snapshot + @eN

结构清晰的页面最快。拿到 ref 就 click @eN。

② find role/text/label

不想先截 snapshot 时,按语义直接命中。

③ 原始 CSS

已有稳定选择器时直接传给动作动词。

④ eval

上面任何一档一旦跟你较劲(ref 失效、隐藏状态、点击被遮挡),立刻落到 eval 直接操作 DOM。

⚠️ 别把一个不稳的定位器重试三遍
遇到 ref 失效、隐藏状态、被遮挡的点击时,不要反复重试同一个结构化定位器——直接 eval 对 DOM 下手,这是查清「为什么失败」最快的路子。更多用法见 提取数据。

click 的自动滚动与 DOM 回退

click 会先把元素滚动进视口;如果坐标点击被遮挡,它会自动回退到 DOM 的 .click()。如果一次 click 报告成功却什么都没发生——典型的是 自动补全 / 菜单里那种一失焦就关掉的 <li>——用 DOM 点击模式重试那一下,或者干脆 eval:

点击报成功却没反应
# 用 DOM 点击模式重试这一下
$ AGENT_BROWSER_CLICK_MODE=dom chrome-use click @e3

# 或者直接用 JS 选中并点击那个条目
$ chrome-use eval "document.querySelector('#stubborn').click()"

按坐标点击

当你手上唯一的把手就是一个坐标时——canvas、来自截图的标记、没有稳定选择器的目标——直接点像素点:

坐标点击
$ chrome-use click 449 320            # 点视口坐标 (x y)
$ chrome-use click 449,320            # 同上,逗号写法
$ chrome-use click --coords 449,320   # 同上,显式 flag
ℹ️ 纯数字永远是坐标
一个纯数字参数永远被当作坐标,绝不会被当成选择器。坐标点击是 canvas / WebGL 场景的正确工具; 表单字段和按钮请优先走 snapshot + @ref,别拿截图去定位。

find 触不到的地方

find 和 CSS 选择器都基于页面 DOM(querySelectorAll),所以对两类元素会报 「Element not found」——即使 snapshot -i 明明列出了它们(快照走的是 CDP 无障碍树,能穿透两者), get text 也能读到它们:

⚠️ 这两类元素改用 snapshot 的 @ref
对闭合 shadow root 或跨源 iframe 里的元素,用它在 snapshot 里的 @ref 来定位, 而不是 find。需要坐标回退时,box @ref 会给出元素的坐标盒子。 参见 交互操作 里对跨源 iframe 的说明。

下一步

语义 find role/text/label/placeholder/alt/title/testid 要求恰好一个可见匹配,只定位不操作时也一样。多个匹配会返回最多八个候选及可见状态、选择器和上下文提示,不派发动作,也不输出输入框的值。用 --name/--exact 消歧,或用 --within <CSS|@ref> 限定到唯一容器。范围必须属于当前标签页的主文档,跨 iframe 的 ref 和已选中的 iframe 上下文会被拒绝;可用 iframe 内的直接 ref 动作,或先 `frame main`。find first/last/nth 保留显式按序选择;普通 CSS 动作行为不变。role 和 label 名称来自 Chrome 无障碍数据,包含 aria-labelledby;每次语义调用重新定位。派发前目标已脱离时安全失败,结果不确定的动作不会重放。

先从页面发现范围:find query "Beta account" 返回候选的选择器锚点;选出对应标题的 article/容器,再执行 find role button click --name Save --exact --within "<返回的选择器>"。范围有歧义时用 snapshot -s "<选择器>" 查看并缩小范围,不取第一个。未知语义 find 参数和重复 --within 会被拒绝;输入像参数的文字可写 find label Email fill -- --name。--exact false 使用子串匹配。

现有 mcp --tools all 的 chrome_use_find 工具接受 within,使用相同的唯一范围规则,工具数量不变。fill/type 的 text 按文字原样传入,--name --observe 不会被当作 CLI 参数。

语义 find 的 --observe 仍按已有行为提示不支持;已知范围和回执时可在同一个 batch 中执行范围内 find 动作及任务专属的 get text 核验。MCP find 工具不声明 observe 字段。