# RPA 示例（仅格式与模式）

**说明**：下文 URL、选择器、会话 ID 均为**占位符**，不是任何真实站点结构。真实值必须来自 Phase 1 工具输出或用户任务，禁止照抄示例当业务真值。

---

## 示例 1：四阶段长什么样

### Phase 1 — CLI 记录（示意）

```
ziniao list-stores
ziniao open-store "<会话ID>"
ziniao navigate "<入口URL>"
ziniao wait "<页面就绪锚点>" --timeout 60
ziniao snapshot --interactive
ziniao click "<动作A选择器>"
ziniao wait "<下一屏锚点>"
ziniao screenshot step-a.png
# … 按任务继续，直到闭环可复现
```

### Phase 2 — 步骤表（示意）

| # | 动作 | 选择器/参数 | 等待条件 | 预期结果 |
|---|------|------------|----------|----------|
| 1 | navigate | `<入口URL>` | `<就绪锚点>` | 可操作 |
| 2 | click | `<A>` | `<B>` | 进入下一状态 |

### Phase 3 — 脚本骨架（与 CLI 语义对齐）

```python
"""RPA: [任务名] — 依赖: pip install nodriver ziniao"""

import asyncio
import logging

import nodriver
from ziniao_webdriver import ZiniaoClient

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s")
logger = logging.getLogger(__name__)

ZINIAO_CONFIG = { ... }  # 与运行环境一致
SESSION_ID = "<会话ID>"


async def do_task(tab):
    await tab.get("<入口URL>")
    anchor = await tab.select("<就绪锚点>", timeout=60)
    if not anchor:
        raise RuntimeError("页面未就绪")
    el = await tab.select("<A>", timeout=30)
    if not el:
        raise RuntimeError("未找到 <A>")
    await el.click()
    nxt = await tab.select("<B>", timeout=30)
    if not nxt:
        raise RuntimeError("未进入预期状态")


async def run():
    client = ZiniaoClient(**ZINIAO_CONFIG)
    if not client.heartbeat():
        client.start_browser()
    r = client.open_store(SESSION_ID)
    if not r or not r.get("debuggingPort"):
        raise RuntimeError("无 CDP 端口")
    browser = await nodriver.Browser.create(host="127.0.0.1", port=r["debuggingPort"])
    try:
        await do_task(browser.main_tab)
    finally:
        browser.stop()


if __name__ == "__main__":
    asyncio.run(run())
```

### Phase 4

按 [doc-template.md](doc-template.md) 填写；第 3 节粘贴**真实**命令与输出摘要。

---

## 示例 2：列表数据提取（`evaluate` 模式）

Phase 1 用 `ziniao eval 'JSON.stringify(...)'` 试通后，脚本侧：

```python
rows = await tab.evaluate("""
    Array.from(document.querySelectorAll('<行选择器>')).map(row => ({
        c0: row.querySelector('<单元选择器>')?.textContent?.trim(),
    }))
""")
```

写入 `Path("out.json").write_text(json.dumps(rows, ensure_ascii=False, indent=2))`。

---

## 示例 3：定时轮询（监控类）

```python
CHECK_INTERVAL = 300
TARGET_URL = "https://example.com/dashboard"

async def run():
    # … 连接浏览器同示例 1 …
    tab = browser.main_tab
    await tab.get(TARGET_URL)
    while True:
        await tab.evaluate("location.reload()")
        await tab.sleep(5)
        v = await tab.evaluate(
            "document.querySelector('.metric')?.textContent?.trim() || ''"
        )
        logger.info("metric=%s", v)
        await asyncio.sleep(CHECK_INTERVAL)
```

---

## 模式总结

| 目标 | 工具链要点 | 脚本要点 |
|------|------------|----------|
| 流程自动化 | `navigate` → `wait` → `snapshot` → 交互命令链 | `get` / `select` / `click` 与之一致 |
| 批量参数 | CLI 验证一条路径；数据用 CSV/JSON | 循环 + 单条 try/except |
| 抓接口 | `network list` / HAR | 评估是否改 HTTP 客户端直连 |
| 多会话 | `ziniao --store` 或 `session switch` | `for` + 每次 `open_store` 或等价 |
