# Headed Browser Open V3

> 使用有头浏览器(headed browser)打开网页，通过CDP协议进行元素点击和自动化操作。V3优化版：简化架构，保留核心功能（协议拦截、元素操作、截图），适用于小红书、抖音等需要绕过App唤起提示的网站。

- Skill: `18816132863/headed-browser-open-v3` (Agent Skill, multi-file: 13 files)
- Install (CLI): `npx skillmds@latest add 18816132863/headed-browser-open-v3`
- Raw SKILL.md: https://api.skillmd.com/api/skills/18816132863/headed-browser-open-v3/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: 18816132863 (https://skillmd.com/u/18816132863)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/18816132863/headed-browser-open-v3

---


# Headed Browser Open Skill V3

## 概述

本 Skill 提供通过 CDP (Chrome DevTools Protocol) 控制有头浏览器的能力，适用于需要模拟真实用户环境、绕过反爬虫检测、处理 App 唤起弹窗的场景。

**核心特性：**
- 真实 Chrome 浏览器（非 headless），更难被检测
- CDP 协议控制，支持元素查找、点击、输入、截图
- 自动拦截外部协议弹窗（weixin://, taobao:// 等）
- Xvfb 虚拟显示支持，无需物理显示器

## 何时使用本 Skill

| 场景 | 是否适用 | 说明 |
|------|---------|------|
| 需要绕过反爬虫检测 | ✅ | 有头浏览器更接近真实用户 |
| 网站触发 App 唤起弹窗 | ✅ | 自动拦截外部协议 |
| 小红书、抖音等国内平台 | ✅ | 已验证兼容 |
| 简单的页面抓取 | ❌ | 优先使用 browser skill |
| 需要多标签页并行 | ⚠️ | 支持但需手动管理 |

### 优先级规则

**当用户请求涉及以下关键词时，优先使用本 skill：**

| 关键词类型 | 示例 | 说明 |
|-----------|------|------|
| 浏览器操作 | "打开浏览器"、"用浏览器访问"、"浏览器打开" | 用户明确要求使用浏览器 |
| 网站名称 | "小红书"、"抖音"、"xiaohongshu"、"douyin" | 已验证兼容的网站 |
| 协议拦截 | "阻止弹窗"、"拦截 App 唤起"、"去掉打开 App 提示" | 需要协议拦截功能 |
| 反爬需求 | "绕过检测"、"模拟真人"、"有头浏览器" | 需要真实浏览器环境 |
| 自动化操作 | "点击"、"输入"、"登录"、"截图" | 需要 CDP 控制页面 |

**触发示例：**
- "用浏览器打开小红书" → 使用本 skill
- "帮我截图抖音页面" → 使用本 skill
- "打开浏览器访问 example.com" → 使用本 skill
- "阻止淘宝的 App 唤起弹窗" → 使用本 skill

**不触发的情况（使用其他 skill）：**
- "抓取网页内容" → 使用 web-access skill
- "搜索信息" → 使用 web_search 工具
- "简单的页面截图" → 使用 browser skill

## 前置要求

```bash
# Ubuntu/Debian
apt-get update
apt-get install -y xvfb google-chrome-stable python3-pip
pip3 install websocket-client
```

## Skill 路径定位

本 skill 的脚本和场景文件存储在相对于 SKILL.md 的目录下。使用时需先定位当前 skill 的根目录：

```
1. 当前文件路径 = 本 SKILL.md 文件的路径
2. Skill 根目录 = 当前文件路径的父目录
3. 脚本目录 = Skill 根目录 + /scripts/
4. 场景目录 = Skill 根目录 + /scenarios/
```

**示例路径：**
- 当前文件: `~/.openclaw/workspace/skills/headed-browser-open-v3/SKILL.md`
- Skill 根目录: `~/.openclaw/workspace/skills/headed-browser-open-v3/`
- 脚本目录: `~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/`
- 场景目录: `~/.openclaw/workspace/skills/headed-browser-open-v3/scenarios/`

## 核心工作流程（强制）

**⚠️ 重要：使用本 skill 时必须严格遵守以下工作流程**

### 强制步骤：使用站点场景文件

**在每次操作任何网站之前，必须执行以下步骤：**

1. **确定 Skill 根目录**：本 SKILL.md 文件所在目录即为 skill 根目录 `{SKILL_ROOT}`
2. **提取目标域名**：从目标 URL 中提取主域名（如 `https://www.xiaohongshu.com/search_result?keyword=xxx` → `xiaohongshu.com`）
3. **构建场景文件路径**：`{SKILL_ROOT}/scenarios/{domain}.md`（注意：场景文件使用域名格式，如 `xiaohongshu.com.md`）
4. **检查并读取场景文件**：如果文件存在，使用 `read` 工具读取，根据平台特征、有效模式、已知陷阱调整操作策略

**示例：**
```
用户要求访问：https://www.xiaohongshu.com/search_result?keyword=xxx

必须执行的步骤：
1. 确定本 skill 根目录：当前 SKILL.md 所在目录
2. 提取域名：xiaohongshu.com
3. 构建路径：{SKILL_ROOT}/scenarios/xiaohongshu.md
4. 检查文件是否存在 → 如存在则 read 读取 → 根据经验操作
5. 如不存在 → 读取 `scenarios/generic.md` 按通用模式操作，成功后记录经验到上述路径
```

### 完整工作流程

```
1. 确定目标网站
        ↓
2. 【强制】读取场景文件
   ├── 存在 scenarios/{domain}.md → 读取该文件
   └── 不存在 → 读取 scenarios/generic.md（默认场景）
        ↓
3. 按场景经验执行操作
        ↓
4. 遇到问题 → 记录到场景文件（陷阱/经验）
        ↓
5. 截图确认结果
```

**场景文件读取优先级：**
1. **第一优先**：`scenarios/{domain}.md`（如 `xiaohongshu.com.md`）
2. ** fallback**：`scenarios/generic.md`（通用默认场景）

**示例：**
```
访问 https://www.xiaohongshu.com
├── 读取 scenarios/xiaohongshu.com.md（存在）→ 使用小红书特定经验
└── 如不存在 → 读取 scenarios/generic.md → 使用通用经验

访问 https://www.newsite.com（新网站，无场景文件）
└── 读取 scenarios/generic.md → 使用通用经验操作
    └── 操作成功后 → 创建 scenarios/newsite.com.md 记录经验
```

### 经验记录原则（强制）

**操作中发现新问题 → 立即更新场景文件：**

1. **失败经验** → 添加到"已知陷阱"章节
2. **成功经验** → 添加到"有效模式"章节  
3. **坐标/参数调整** → 更新对应表格
4. **新发现** → 添加"更新记录"

**为什么必须记录经验？**
- 每个网站有独特的行为模式（反爬策略、元素查找方式等）
- 场景文件记录了已知陷阱和解决方案
- 避免重复踩坑，持续积累
- 便于后续自动化操作

**示例：**
```bash
# 操作抖音时发现 --find 找不到元素
# → 更新 scenarios/douyin.com.md
# → 添加陷阱："抖音使用 Canvas 渲染，元素查找失效"
# → 添加模式："以截图为主，坐标点击为辅"
```

### 场景文件索引

| 文件 | 何时加载 | 说明 |
|------|---------|------|
| `scenarios/xiaohongshu.com.md` | 访问小红书相关页面 | 小红书平台特征、登录流程、坐标参考 |
| `scenarios/douyin.com.md` | 访问抖音相关页面 | 抖音平台特征、Canvas渲染处理 |
| `scenarios/zhihu.com.md` | 访问知乎相关页面 | 知乎平台特征、登录流程 |
| `scenarios/bilibili.com.md` | 访问B站相关页面 | B站平台特征、登录点击经验 |
| `scenarios/generic.md` | 通用参考 | 通用原则和最佳实践 |

## 脚本参考

### browser.sh - 浏览器管理

| 命令 | 说明 | 示例 |
|------|------|------|
| `start [URL]` | 启动浏览器，可选打开URL | `browser.sh start "https://xiaohongshu.com"` |
| `status` | 检查运行状态 | `browser.sh status` |
| `stop` | 停止浏览器 | `browser.sh stop` |

**环境变量：**
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `CDP_PORT` | 18800 | CDP 调试端口 |
| `DISPLAY_NUM` | 99 | Xvfb 显示号 |
| `SCREEN_WIDTH` | 1920 | 屏幕宽度 |
| `SCREEN_HEIGHT` | 1080 | 屏幕高度 |

### element.py - 元素操作

| 参数 | 说明 | 示例 |
|------|------|------|
| `--find TEXT` | 查找包含指定文本的元素 | `--find "登录,手机号"` |
| `--click X Y` | 点击指定坐标 | `--click 1077 586` |
| `--click-text TEXT` | 点击包含指定文本的元素 | `--click-text "获取验证码"` |
| `--js-click` | 使用JavaScript点击（绕过反爬） | `--click-text "登录" --js-click` |
| `--type TEXT` | 在当前焦点元素输入文本 | `--type "13800138000"` |
| `--screenshot PATH` | 截图保存 | `--screenshot /tmp/page.png` |
| `--port PORT` | CDP端口 | `--port 18800` |
| `--display NUM` | Xvfb显示号 | `--display 99` |

**点击失败时的处理：**

如果 `--click-text` 点击没有反应：

1. **告知用户"点击失败，尝试使用JavaScript点击..."**

2. **使用 `--js-click` 参数重试**（推荐）
   ```bash
   element.py --click-text "登录" --js-click
   ```

3. **如果仍然失败：**
   - 告知用户"JavaScript点击也失败了，尝试其他方法..."
   - 可以尝试其他方法（如动态查找元素位置后点击）
   - 截图反馈当前页面状态
   - 如果所有方法都失败，告知用户"操作失败，请稍后重试"
   - 记录失败经验到场景文件

**为什么需要 `--js-click`？**
- 部分网站有反自动化检测，CDP鼠标事件被拦截
- JavaScript点击直接触发元素点击事件，更难被检测
- 小红书、B站等平台建议使用 `--js-click`

## 标准操作流程

### 流程 1：打开网页并截图

```bash
# 1. 启动浏览器打开目标网站（后台运行）
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/browser.sh start "https://www.xiaohongshu.com" &

# 2. 等待页面加载（根据网络情况调整）
sleep 3

# 3. 截图确认页面状态
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --screenshot /tmp/page.png
```

**注意：** 启动浏览器时使用 `&` 后台运行，避免阻塞当前终端。

### 流程 2：查找并点击元素

```bash
# 1. 查找页面元素（获取位置和文本信息）
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --find "登录,手机号,同意"

# 2. 根据查找结果点击指定坐标
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --click 1077 586

# 3. 或通过文本点击
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --click-text "获取验证码"

# 4. 截图确认
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --screenshot /tmp/after_click.png
```

### 流程 3：输入文本

```bash
# 1. 点击输入框获取焦点（或通过坐标）
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --click 960 438

# 2. 输入文本
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --type "13800138000"

# 3. 截图确认
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --screenshot /tmp/after_type.png
```

## 具体场景

本 skill 提供针对特定网站的详细操作场景，每个场景文件包含：

- **快速开始** - 最简操作流程
- **平台特征** - 网站技术特点
- **有效模式** - 已验证成功的操作模式
- **已知陷阱** - 失败经验和解决方案
- **常见问题** - Q&A

| 网站 | 场景文件 | 特征 | 状态 |
|------|----------|------|------|
| 小红书 | [scenarios/xiaohongshu.com.md](scenarios/xiaohongshu.com.md) | DOM+Canvas混合，支持元素查找 | ✅ 已验证 |
| 抖音 | [scenarios/douyin.com.md](scenarios/douyin.com.md) | 纯Canvas渲染，需截图+坐标 | ✅ 已验证 |
| 知乎 | [scenarios/zhihu.com.md](scenarios/zhihu.com.md) | 标准DOM渲染，支持动态查找 | ✅ 已验证 |
| B站 | [scenarios/bilibili.com.md](scenarios/bilibili.com.md) | 标准DOM，建议使用JS点击 | ✅ 已验证 |
| 通用 | [scenarios/generic.md](scenarios/generic.md) | 通用原则和最佳实践 | 📋 参考 |

**场景文件格式（YAML Frontmatter）：**
```yaml
---
domain: example.com
aliases: [别名1, 别名2]
updated: 2026-04-13
---
```

**使用场景文件的步骤（强制）：**
1. **【必须】读取场景**：`read scenarios/{domain}.md`
2. **理解特征**：查看"平台特征"和"已知陷阱"
3. **执行操作**：按"有效模式"或"快速开始"执行
4. **记录经验**：遇到问题更新场景文件
5. **截图确认**：每次操作后截图验证

## 重要提示

### 手机号登录流程（通用）

**必须先勾选"我已阅读并同意"，再点击"获取验证码"！**

| 顺序 | 操作 | 说明 |
|------|------|------|
| 1 | 输入手机号 | 在手机号输入框输入 |
| 2 | **勾选同意协议** | ⚠️ 必须先勾选，否则验证码按钮无响应 |
| 3 | 点击获取验证码 | 此时按钮才可点击 |

### 坐标定位技巧

**为什么需要坐标？**
- 某些网站（如小红书）的元素难以通过文本精确点击
- 坐标点击更可靠，但需要根据分辨率调整

**获取坐标的方法：**
1. 先截图查看当前页面状态
2. 使用图像编辑工具测量目标位置
3. 或使用 `--find` 查看元素大致位置

**常用分辨率坐标参考：**

| 网站 | 元素 | 1920x1080 | 1366x768 |
|------|------|-----------|----------|
| 小红书 | 同意协议复选框 | (1077, 586) | (768, 420) |
| 小红书 | 获取验证码按钮 | (1256, 438) | (896, 315) |

### 每次操作后截图

**强制要求：每次操作后必须截图确认**

原因：
- 验证操作是否成功
- 便于调试和问题排查
- 记录操作历史

```bash
# 操作前截图
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --screenshot /tmp/before.png

# 执行操作
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --click 100 200

# 操作后截图
~/.openclaw/workspace/skills/headed-browser-open-v3/scripts/element.py --screenshot /tmp/after.png
```

## 技术原理

### 协议拦截实现

通过 Chrome 启动参数 `--inject-js` 在页面加载前注入 `blocker.js`：

```javascript
// 劫持 window.location
Object.defineProperty(window, 'location', {
    set: function(url) {
        if (url && !url.match(/^https?:\/\//i)) {
            console.log('[Blocker] Blocked:', url);
            return; // 阻止非 HTTP 协议
        }
        window.location.href = url;
    }
});
```

**拦截范围：**
- `window.location` setter
- `window.open()`
- `<a>` 标签点击事件

### 截图机制

```
--screenshot 执行流程：
1. 尝试 CDP 截图 (Page.captureScreenshot)
2. 成功 → 保存退出
3. 失败 → 回退到 Xvfb 截图 (import -window root)
4. 都失败 → 报错退出
```

### CDP 连接

```
element.py → WebSocket → Chrome CDP (port 18800)
                ↓
         执行浏览器操作
```

## 故障排查

| 问题 | 可能原因 | 解决方案 |
|------|---------|---------|
| 浏览器启动失败 | Xvfb 未安装 | `apt-get install xvfb` |
| CDP 连接失败 | 浏览器未启动或端口冲突 | 检查 `browser.sh status`，更换 `CDP_PORT` |
| 元素找不到 | 页面未加载完成 | 增加 `sleep` 等待时间 |
| 点击无反应 | 坐标不正确 | 先截图确认元素位置，调整坐标 |
| 输入文本失败 | 输入框未获得焦点 | 先点击输入框再输入 |
| 截图失败 | CDP 和 Xvfb 都不可用 | 检查 `DISPLAY` 环境变量 |
| Chrome CPU 占用高 | 页面卡死或内存泄漏 | `pkill -9 chrome` 强制终止 |

### Chrome 进程 CPU 占用过高处理

```bash
# 强制终止所有 Chrome 进程
pkill -9 chrome

# 同时终止 Xvfb
pkill -9 Xvfb

# 检查是否还有残留进程
ps aux | grep -E "chrome|Xvfb" | grep -v grep
```

## 文件结构

```
headed-browser-open-v3/
├── SKILL.md                  # 本文件
├── scripts/
│   ├── browser.sh            # 浏览器启动/停止脚本
│   ├── element.py            # 元素操作脚本（CDP 控制）
│   └── blocker.js            # 协议拦截 JavaScript
└── scenarios/
    ├── xiaohongshu.md        # 小红书操作场景
    └── douyin.md             # 抖音操作场景
```

## 最佳实践

### 1. 操作前规划
- 明确目标：需要打开什么页面？执行什么操作？
- 检查是否有对应场景文件
- 预估操作步骤和等待时间

### 2. 稳健的操作节奏
```bash
# 好：每步操作后等待并截图
browser.sh start URL
sleep 3
element.py --screenshot step1.png
element.py --click 100 200
sleep 1
element.py --screenshot step2.png

# 不好：连续操作不等待
browser.sh start URL
element.py --click 100 200
element.py --type "text"  # 可能页面还没加载完
```

### 3. 错误处理
- 操作失败后先截图查看当前状态
- 检查浏览器是否仍在运行
- 必要时重启浏览器

### 4. 资源清理
- 任务完成后执行 `browser.sh stop` 清理资源
- 长时间运行的任务定期检查 Chrome 进程状态

## 版本对比

| 特性 | V2 | V3 |
|------|-----|-----|
| 核心功能 | ✅ | ✅ |
| 代码复杂度 | 较高 | **简化** |
| 场景文件 | 强制使用 | 参考使用 |
| 架构 | 复杂 | **精简** |
| 维护性 | 一般 | **更好** |

## 相关

- [headed-browser-open-v2](../headed-browser-open-v2/SKILL.md) - V2版本（功能更完整，场景强制化）
- [browser](../browser/SKILL.md) - 原生 browser skill（无头浏览器，更轻量）

