172 lines
8.4 KiB
Markdown
172 lines
8.4 KiB
Markdown
# Real Browser RPA Example
|
||
|
||
这是一个真实网站浏览器 RPA skill 的可复制参考实现,适用于需要登录、人工验证、搜索、滚动加载、采集和入库的场景。
|
||
|
||
**说明:**
|
||
|
||
- 本示例是通用模板,不绑定具体平台。
|
||
- 示例抽象自已跑通的真实浏览器 RPA skill(抖音视频链接采集),但代码已改成中性示例命名。
|
||
- 新 skill 开发时可以复制本目录,再替换目标站点、选择器、解析逻辑和业务字段。
|
||
|
||
## 适用场景
|
||
|
||
- 真实网站操作(非 sandbox / mock)
|
||
- 需要登录态与 persistent Chrome/Edge profile
|
||
- 需要通过 account-manager 管理账号和 `profile_dir`
|
||
- 需要处理人工登录、滑块验证码、短信验证码
|
||
- 需要关键词搜索、滚动加载、采集可见条目
|
||
- 需要结构化日志、用户友好的停止原因、失败留痕(截图/视频)
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
real_browser_rpa/
|
||
├── README.md
|
||
├── scripts/
|
||
│ ├── service/
|
||
│ │ ├── account_client.py # subprocess 调用 account-manager
|
||
│ │ ├── browser_session.py # 系统 Chrome + persistent context
|
||
│ │ ├── human_verification.py # 滑块/短信/保存登录弹窗检测(不依赖 task_rpa 错误类型)
|
||
│ │ ├── task_rpa.py # RPA 主流程
|
||
│ │ └── task_service.py # 轻量编排(示例无 DB)
|
||
│ └── util/
|
||
│ ├── constants.py # 平台常量、selector 占位
|
||
│ └── logging.py # 结构化日志与脱敏
|
||
└── tests/
|
||
├── test_human_verification.py # 验证码误判防护
|
||
└── test_stop_reason.py # 停止原因文案
|
||
```
|
||
|
||
## 核心流程
|
||
|
||
1. **pick account** — 通过 `account_client.pick_web_account()` 获取 `profile_dir` 与租约
|
||
2. **启动浏览器** — `launch_persistent_context` + `new_page()` + `page.goto(start_url)`
|
||
3. **人工验证(启动后)** — 检测滑块/短信,等待用户完成
|
||
4. **等待登录** — 检测登录按钮消失 / 登录态 marker 出现
|
||
5. **保存登录弹窗** — 等待“是否保存登录信息”倒计时消失
|
||
6. **人工验证(登录后)** — 再次检测
|
||
7. **搜索** — 定位搜索框 → 输入关键词 → 点击搜索
|
||
8. **等待结果容器** — `#search-result-container`(示例 selector)
|
||
9. **滚动采集循环** — 采集可见条目 → 判断 stop_reason → 滚动加载
|
||
10. **返回结果** — `ScrapeRunResult` + `format_stop_reason_for_user()`
|
||
11. **释放租约** — `finally` 中 `release_lease()`
|
||
|
||
## 开发新 skill 时如何复制
|
||
|
||
1. **先阅读** `examples/real_browser_rpa/README.md`(本节及下方「复制边界」)
|
||
2. 复制整个 `examples/real_browser_rpa/` 到新 skill 的 `scripts/` 结构(或作为起点合并)
|
||
3. 修改 `util/constants.py` 中的 `TARGET_PLATFORM`、`DEFAULT_START_URL`、selector 常量
|
||
4. 替换 `task_rpa.py` 中的登录态 marker、搜索框/结果解析逻辑(**必须 F12 实测**)
|
||
5. 替换 `human_verification.py` 中的验证码 selector(若目标站点 DOM 不同)
|
||
6. 在 `task_service.py` 中接入真实 DB、任务日志、RpaVideoSession
|
||
7. 添加 CLI 入口(`scripts/main.py`),并补齐 `SKILL.md` 的 LLM/运行契约说明与根 `README.md` 的用户市场说明
|
||
|
||
## 复制边界:哪些能复制,哪些必须替换
|
||
|
||
### 可以直接参考/复制的
|
||
|
||
- `browser_session.py` 的启动结构:**persistent context → new_page → goto**
|
||
- `human_verification.py` 的人工验证等待模式(容器级检测 + 等待人工,不自动破解)
|
||
- `task_rpa.py` 的流程分层、结构化日志点、`stop_reason` 设计
|
||
- `account_client.py` 的 account-manager CLI **集中封装**方式(subprocess 仅限此文件)
|
||
- `tests/test_human_verification.py` 的误判防护测试思路
|
||
|
||
### 必须替换的
|
||
|
||
- `SKILL_SLUG`
|
||
- `TARGET_PLATFORM`
|
||
- `LEASE_HOLDER`
|
||
- `DEFAULT_START_URL`
|
||
- `SEARCH_INPUT_SELECTORS` / `SEARCH_BUTTON_SELECTOR`
|
||
- `RESULT_CONTAINER_SELECTOR` / `RESULT_ITEM_SELECTOR`
|
||
- `SCROLL_CONTAINER_SELECTORS`
|
||
- `RESULT_END_TEXT`
|
||
- `LOGGED_IN_SELECTORS` / `LOGGED_OUT_SELECTOR`(见下方说明)
|
||
- `_parse_item_locator()` 业务字段解析
|
||
- 用户可见中文文案
|
||
- 数据库写入逻辑
|
||
- 任务日志逻辑
|
||
- 录屏/截图业务标题
|
||
|
||
### 禁止照抄的
|
||
|
||
- 不要照抄目标站点 selector(示例 selector 不等于真实 DOM)
|
||
- 不要照抄平台名、slug、logger 名
|
||
- 不要依赖 `D:\OpenClaw\client-commons\account-manager\scripts\main.py` 等开发机绝对路径作为生产依赖
|
||
- 不要把示例里的 result selector 当成真实站点 selector
|
||
- 不要把示例代码原样发布为业务 skill
|
||
- 不要把真实账号、手机号、cookie、token 写入代码或 README
|
||
|
||
### 登录 selector 说明
|
||
|
||
`task_rpa.py` 中的 `LOGGED_IN_SELECTORS` 与 `LOGGED_OUT_SELECTOR` **只是示例**,偏中文「登录」按钮和常见站点结构。复制到新 skill 后:
|
||
|
||
- **必须**用目标站点 F12 / DOM 实测后替换
|
||
- **不允许**凭经验猜 selector
|
||
- **不允许**因为示例在本机曾跑通就直接照搬到其他平台
|
||
|
||
### account-manager 路径解析说明
|
||
|
||
`account_client.py` 末尾的 `D:\OpenClaw\client-commons\account-manager\scripts\main.py` 是**开发环境兜底路径**,仅用于模板/本机调试。复制到真实 skill 后:
|
||
|
||
- **优先**通过 `ACCOUNT_MANAGER_ROOT`、`CLAW_SKILLS_ROOT`、`JIANGCHANG_SKILLS_ROOT` 或宿主运行环境解析 account-manager
|
||
- **不要**把个人机器路径作为生产依赖
|
||
|
||
## 必须保留的安全原则
|
||
|
||
- **不 import account-manager 内部模块** — 只通过 CLI/subprocess 调用
|
||
- **不自动破解验证码** — 滑块/短信只检测 + 等待人工完成
|
||
- **日志脱敏** — 不输出完整手机号/账号
|
||
- **租约释放** — `pick-web --lease` 后必须在 `finally` 释放
|
||
- **失败留痕** — 真实 skill 应在关键失败点截图(示例中已留注释位)
|
||
|
||
## 常见坑
|
||
|
||
| 坑 | 正确做法 |
|
||
|---|---|
|
||
| 直接 `import account_manager.service...` | 通过 `subprocess` 调用 `account-manager/scripts/main.py` |
|
||
| 把 URL 放进 `launch_persistent_context(args=[url])` | `args` 只放 Chrome 参数;URL 用 `page.goto(start_url)` |
|
||
| 启动后直接操作 DOM | 先 `context.new_page()` 再 `page.goto()` |
|
||
| 用整页 `body.inner_text()` 判断验证码 | 限定在 `[role='dialog']`、`.vc-captcha-verify` 等容器 |
|
||
| 搜索结果含“验证码教程”文字就误判 | 单元测试覆盖:无验证 DOM 时不应 `present=True` |
|
||
| 无结构化日志 | 关键节点打 `rpa_start` / `browser_ready` / `collect_round` 等 |
|
||
| 把 CLI 参数暴露给普通用户 | 用户说明放根 `README.md`;运行契约与触发规则放 `SKILL.md`(LLM/平台入口) |
|
||
|
||
## 需要替换的内容清单
|
||
|
||
| 文件 | 替换项 |
|
||
|---|---|
|
||
| `util/constants.py` | `SKILL_SLUG`、`TARGET_PLATFORM`、`DEFAULT_START_URL`、所有 selector |
|
||
| `browser_session.py` | `get_start_url()` 配置来源、stealth 脚本(可选) |
|
||
| `human_verification.py` | `SLIDER_SELECTORS`、`SMS_SELECTORS`、`DIALOG_TEXT_CONTAINERS` |
|
||
| `task_rpa.py` | `LOGGED_IN_SELECTORS`、`LOGGED_OUT_SELECTOR`、`_parse_item_locator()` |
|
||
| `account_client.py` | `PLACEHOLDER_PLATFORM`、`LEASE_HOLDER`、账号 setup 文案 |
|
||
| `task_service.py` | 接入 DB、任务日志、entitlement、视频留痕 |
|
||
|
||
## 依赖说明
|
||
|
||
本目录是 **示例**,不影响 skill-template 根目录运行。真实 skill 需要:
|
||
|
||
- Python 3.10+
|
||
- Python 包 `playwright`:属于**宿主共享 runtime** 的通用能力;技能侧**不要**在 `requirements.txt` 中重复声明,也**不要**在代码或脚本中执行 `pip install playwright`
|
||
- 真实 skill **默认使用系统 Chrome/Edge**,**不使用** Playwright 下载的内置 Chromium
|
||
- 技能侧**不要**执行 `playwright install`、`playwright install chromium` 或类似命令
|
||
- 若本地独立开发环境缺少 Playwright Python 包,只能作为开发机临时环境补装;**生产/宿主运行**由共享 runtime 解决
|
||
- `jiangchang_skill_core`(如 `find_chrome_executable` 等,由 platform-kit 提供)
|
||
- 兄弟 skill `account-manager`
|
||
|
||
## 运行测试
|
||
|
||
```bash
|
||
cd examples/real_browser_rpa
|
||
python -m pytest tests/ -v
|
||
```
|
||
|
||
测试为纯函数/Mock DOM,**不需要启动真实浏览器**。
|
||
|
||
## 当前状态
|
||
|
||
- 示例代码已就绪,可直接作为新 skill 复制起点。
|
||
- 未绑定具体平台业务字段;selector 为占位示例。
|
||
- 未接入真实数据库与 CLI 入口。
|