基于 skill-template 脚手架开发,包含: - payroll_config(费率配置,可编辑)+ payslip_snapshots(解析历史,只读)2 张业务表 - 全国默认 + 北上广 4 套费率(社保/公积金/个税起征点/7 级税率表) - 5 个业务 Action:calculate-payslip-simple / calculate-payslip-full / explain-term / view-config / edit-config - 个税累计预扣法计算,支持多月历史累加 - 20 个薪资名词库(社保/公积金/个税/全勤/加班费等) - 完整市场文档(README/TUTORIAL/DEMO/CHANGELOG) - 296 测试全部通过
124 lines
4.7 KiB
Markdown
124 lines
4.7 KiB
Markdown
# 浏览器 RPA 元素拾取与定位标准
|
||
|
||
> 先读 [`RPA_ELEMENT_LOCATING.md`](RPA_ELEMENT_LOCATING.md)。本文只定义浏览器端的拾取、定位、验证和常见陷阱;账号、Profile、HITL 和录屏仍以 [`RPA.md`](RPA.md) 为准。
|
||
|
||
## 目录
|
||
|
||
1. 拾取工具
|
||
2. 拾取步骤
|
||
3. 定位优先级
|
||
4. 特殊上下文
|
||
5. 验证标准
|
||
6. 禁止模式
|
||
7. example 路由
|
||
|
||
## 1. 拾取工具
|
||
|
||
优先使用 Playwright Inspector / Codegen 的 **Pick Locator**,辅以 Chrome/Edge DevTools:
|
||
|
||
- Pick Locator:点选页面元素,获取 role/label/text/testid 等候选定位器。
|
||
- DevTools Elements:确认真实 DOM、属性、父容器、iframe 和 Shadow DOM。
|
||
- Playwright trace/screenshot:复核动作发生时的页面状态。
|
||
|
||
检查器只负责给出候选。复制到生产代码前必须人工确认作用域、唯一性和稳定性。
|
||
|
||
## 2. 拾取步骤
|
||
|
||
1. 使用真实 `profile_dir` 和有头浏览器打开目标页面。
|
||
2. 手工进入发生动作的准确页面、标签页和弹窗状态。
|
||
3. 用 Pick Locator 点选元素,先记录建议 locator。
|
||
4. 在 DevTools 中确认:
|
||
- accessible role/name
|
||
- label、placeholder、可见文本
|
||
- 稳定 id/name
|
||
- `data-testid`(仅目标系统已提供或自有系统可维护时)
|
||
- 所在 iframe、dialog、表格行或卡片
|
||
5. 先定位业务容器,再在容器内定位动作元素。
|
||
6. 运行 `count()`;关键动作期望 `1`。
|
||
7. 验证 `visible`、`enabled`、必要时 `editable/checked`。
|
||
8. 执行动作并断言 URL、业务容器、成功提示、单号或状态变化。
|
||
9. 刷新页面、关闭重开浏览器后复测。
|
||
|
||
## 3. 定位优先级
|
||
|
||
从高到低:
|
||
|
||
1. `get_by_role(role, name=...)`
|
||
2. `get_by_label(...)`
|
||
3. 自有系统的稳定 `get_by_test_id(...)`
|
||
4. `get_by_placeholder(...)`、`get_by_alt_text(...)`、`get_by_title(...)`
|
||
5. 稳定业务文本,优先用于非交互元素或父容器
|
||
6. 稳定 `id` / `name` / 短 CSS
|
||
7. 容器 + `filter(has_text=...)` / `has=...`
|
||
8. 短 XPath
|
||
9. 已验证的顺序定位
|
||
|
||
示例:
|
||
|
||
```python
|
||
dialog = page.get_by_role("dialog", name="订单确认")
|
||
submit = dialog.get_by_role("button", name="确认提交")
|
||
if await submit.count() != 1:
|
||
raise RuntimeError("ERROR:ELEMENT_AMBIGUOUS submit_button")
|
||
await submit.wait_for(state="visible")
|
||
await submit.click()
|
||
await page.get_by_text("提交成功", exact=True).wait_for(state="visible")
|
||
```
|
||
|
||
### 列表与重复按钮
|
||
|
||
不要直接选择全页第一个“添加”:
|
||
|
||
```python
|
||
row = page.get_by_role("row").filter(has_text="客户A")
|
||
button = row.get_by_role("button", name="添加")
|
||
```
|
||
|
||
如果业务键不唯一,先停止并要求补充输入,不要用 `.first` 猜。
|
||
|
||
## 4. 特殊上下文
|
||
|
||
### iframe
|
||
|
||
先确认元素属于哪个 iframe,再使用 `frame_locator`。不得因为主页面找不到就改用坐标。
|
||
|
||
### 新标签页和弹窗
|
||
|
||
点击前注册 popup/new page 等待;取得新 Page 后再定位。关闭弹窗不等于业务成功。
|
||
|
||
### Shadow DOM
|
||
|
||
Playwright CSS locator 默认可穿透 open Shadow DOM;XPath 不穿透。closed Shadow DOM 无法正常读取时,评估目标应用是否提供可访问性属性,不能注入破解。
|
||
|
||
### 动态列表
|
||
|
||
等待列表完成加载后再读取;`locator.all()` 不会等待动态列表稳定。滚动或刷新后重新获取 locator。
|
||
|
||
### Canvas
|
||
|
||
先确认是否存在可访问性节点或外层业务控件。完全无 DOM 时才进入局部图像方案,并记录分辨率、缩放和识别区域。
|
||
|
||
## 5. 验证标准
|
||
|
||
- locator 在真实目标页面匹配数量符合元素清单。
|
||
- 不因语言、窗口宽度、列表顺序或一次刷新就指向不同业务对象。
|
||
- 动作前检查可见、可用;动作后等待真实业务状态。
|
||
- 登录态至少结合两个证据:例如稳定用户菜单 + 登录按钮不存在,不能只看单个哈希 class。
|
||
- 真实和仿真站明确区分:仿真可以使用 `fill()` 加速测试;真实生产输入遵守项目拟人节奏。
|
||
|
||
## 6. 禁止模式
|
||
|
||
- 用全页所有 `input` 的尺寸和位置猜搜索框。
|
||
- 用 `.first` 绕过严格模式。
|
||
- 从 DevTools 复制深层 `nth-child` 或绝对 XPath。
|
||
- 只等 URL 含 `search` 就判定结果成功。
|
||
- 页面结构变化后动态生成 selector 并继续提交。
|
||
- 为方便测试给第三方网站注入 testid。
|
||
|
||
## 7. example 路由
|
||
|
||
- 真实网站、登录/HITL/滚动:[`../examples/real_browser_rpa/README.md`](../examples/real_browser_rpa/README.md)
|
||
- 自有 sandbox、表单和 adapter:[`../examples/simulator_browser_rpa/README.md`](../examples/simulator_browser_rpa/README.md)
|
||
|
||
复制 example 前先完成目标站元素清单;example 中的任何 URL、selector 和业务字段都不得跨平台照抄。
|