jo-inc/camofox-browser
GitHub: jo-inc/camofox-browser
一个基于 Camoufox 引擎的免检测浏览器自动化服务,为 AI 代理提供绕过反爬的稳定 REST API。
Stars: 2132 | Forks: 203
```
git clone https://github.com/jo-inc/camofox-browser && cd camofox-browser
npm install && npm start
# → http://localhost:9377
```
## 为什么
AI 代理需要浏览真实网络。Playwright 会被屏蔽。无头 Chrome 会被指纹识别。隐身插件本身会成为指纹。
Camoufox 在 **C++ 实现层**修补 Firefox — `navigator.hardwareConcurrency`、WebGL 渲染器、AudioContext、屏幕几何、WebRTC 等 — 在 JavaScript 触及它们之前全部伪造。没有 shims,没有包装器,没有泄露。
该项目将这一引擎封装为面向代理的 REST API:使用可访问性快照替代臃肿的 HTML,用稳定的元素引用实现可靠点击,并为常用网站提供搜索宏。
## 功能
- **C++ 反检测** — 绕过 Google、Cloudflare 及大多数机器人检测
- **元素引用** — 稳定的 `e1`、`e2`、`e3` 标识符,用于可靠交互
- **令牌高效** — 可访问性快照体积约为原始 HTML 的 10%
- **随处运行** — 懒加载浏览器启动 + 空闲自动关闭,闲置时内存约 40MB。设计用于与你的其他栈共享一台机器:树莓派、5 美元 VPS、共享 Railway 基础设施
- **会话隔离** — 每个用户独立的 Cookie 与存储
- **Cookie 导入** — 注入 Netscape 格式的 Cookie 文件以实现免登录浏览
- **代理 + 地理定位** — 通过内置 GeoIP 将流量路由至住宅代理,并自动设置区域/时区
- **结构化日志** — 每行 JSON 日志含请求 ID,便于生产环境观测
- **YouTube 文本** — 无需 API 键即可通过 yt-dlp 提取任意 YouTube 视频字幕
- **搜索宏** — `@google_search`、`@youtube_search`、`@amazon_search`、`@reddit_subreddit` 等 10+ 种
- **快照截图** — 在可访问性快照中附带 base64 PNG 截图
- **大页处理** — 自动截断并支持基于偏移的分页
- **下载捕获** — 捕获浏览器下载并通过 API 获取(可选内联 base64)
- **DOM 图像提取** — 列出 `
![]()
` 的 src/alt,并可选择返回内联 data URL
- **任意部署** — 支持 Docker、Fly.io、Railway
## 可选依赖
| 依赖 | 用途 | 安装 |
|-----------|---------|---------|
| [yt-dlp](https://github.com/yt-dlp/yt-dlp) | YouTube 字幕提取(快速路径) | `pip install yt-dlp` 或 `brew install yt-dlp` |
Docker 镜像已包含 yt-dlp。本地开发请安装该依赖以启用 `/youtube/transcript` 端点;未安装时将回退到较慢的浏览器方式。
## 快速开始
### OpenClaw 插件
```
openclaw plugins install @askjo/camofox-browser
```
**工具:** `camofox_create_tab` · `camofox_snapshot` · `camofox_click` · `camofox_type` · `camofox_navigate` · `camofox_scroll` · `camofox_screenshot` · `camofox_close_tab` · `camofox_list_tabs` · `camofox_import_cookies`
### 独立运行
```
git clone https://github.com/jo-inc/camofox-browser
cd camofox-browser
npm install
npm start # downloads Camoufox on first run (~300MB)
```
默认端口为 `9377`。请参阅 [环境变量](#environment-variables) 获取全部选项。
### Docker
包含的 `Makefile` 能自动识别 CPU 架构并在 Docker 构建**之外**预先下载 Camoufox 与 yt-dlp 二进制文件,因此重建速度很快(约 30 秒,而非约 3 分钟)。
```
# 构建并启动(自动检测架构:在 M1/M2 上为 aarch64,在 Intel 上为 x86_64)
make up
# 停止并移除容器
make down
# 强制干净重建(例如在升级 VERSION/RELEASE 后)
make reset
# 仅下载二进制文件(不构建)
make fetch
# 显式覆盖架构或版本
make up ARCH=x86_64
make up VERSION=135.0.1 RELEASE=beta.24
```
注意:必须先运行 `make fetch`(或 `make build`)——Dockerfile 期望预下载的二进制文件位于 `dist/` 目录。
### Fly.io / Railway
已包含 `fly.toml` 与 `railway.toml`。使用 `fly deploy` 部署或连接仓库到 Railway。
## 用法
### Cookie 导入
从浏览器导入 Cookie 到 Camoufox,以跳过 LinkedIn、Amazon 等网站的交互式登录。
#### 设置
**1. 生成密钥:**
```
# macOS / Linux
openssl rand -hex 32
```
**2. 启动 OpenClaw 前设置环境变量:**
```
export CAMOFOX_API_KEY="your-generated-key"
openclaw start
```
插件与服务器均使用同一密钥进行身份验证。请只需设置一次。
**3. 从浏览器导出 Cookie:**
安装支持导出 Netscape 格式 Cookie 文件的浏览器扩展(例如 Chrome/Firefox 的 “cookies.txt”)。导出目标网站的 Cookie。
**4. 放置 Cookie 文件:**
```
mkdir -p ~/.camofox/cookies
cp ~/Downloads/linkedin_cookies.txt ~/.camofox/cookies/linkedin.txt
```
默认目录为 `~/.camofox/cookies/`。可通过 `CAMOFOX_COOKIES_DIR` 覆盖。
**5. 请求代理导入:**
代理调用 `camofox_import_cookies` → 读取文件 → 使用 Bearer 令牌 POST 到服务器 → Cookie 注入浏览器会话。后续对 linkedin.com 的 `camofox_create_tab` 调用将已认证。
#### 工作原理
```
~/.camofox/cookies/linkedin.txt (Netscape format, on disk)
│
▼
camofox_import_cookies tool (parses file, filters by domain)
│
▼ POST /sessions/:userId/cookies
│ Authorization: Bearer
│ Body: { cookies: [Playwright cookie objects] }
▼
camofox server (validates, sanitizes, injects)
│
▼ context.addCookies(...)
│
Camoufox browser session (authenticated browsing)
```
- `cookiesPath` 相对于 Cookie 目录解析,禁止路径遍历到外部
- 每个请求最多 500 个 Cookie,文件大小限制 5MB
- Cookie 对象被清理为 Playwright 字段的允许列表
#### 独立服务器使用
```
curl -X POST http://localhost:9377/sessions/agent1/cookies \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_CAMOFOX_API_KEY' \
-d '{"cookies":[{"name":"foo","value":"bar","domain":"example.com","path":"/","expires":-1,"httpOnly":false,"secure":false}]}'
```
#### Docker / Fly.io
```
docker run -p 9377:9377 \
-e CAMOFOX_API_KEY="your-generated-key" \
-v ~/.camofox/cookies:/home/node/.camofox/cookies:ro \
camofox-browser
```
对于 Fly.io:
```
fly secrets set CAMOFOX_API_KEY="your-generated-key"
```
### 代理 + 地理定位
将所有浏览器流量通过代理路由,并自动派生区域、时区与地理位置(基于代理出口 IP 的内置 GeoIP)。
**简单代理(单端点):**
```
export PROXY_HOST=166.88.179.132
export PROXY_PORT=46040
export PROXY_USERNAME=myuser
export PROXY_PASSWORD=mypass
npm start
```
**回连代理(旋转粘性会话):**
适用于 Decodo、Bright Data 或 Oxylabs 等提供单网关端点并带基于会话的粘性 IP 的服务:
```
export PROXY_STRATEGY=backconnect
export PROXY_BACKCONNECT_HOST=gate.provider.com
export PROXY_BACKCONNECT_PORT=7000
export PROXY_USERNAME=myuser
export PROXY_PASSWORD=mypass
npm start
```
每个浏览器上下文拥有独立的粘性会话,因此不同用户获得不同 IP。会话在代理错误或 Google 屏蔽时自动轮换。
或在 Docker 中:
```
docker run -p 9377:9377 \
-e PROXY_HOST=166.88.179.132 \
-e PROXY_PORT=46040 \
-e PROXY_USERNAME=myuser \
-e PROXY_PASSWORD=mypass \
camofox-browser
```
配置代理后:
- 所有流量经代理路由
- Camoufox 的 GeoIP 自动设置 `locale`、`timezone` 与 `geolocation`,匹配代理出口 IP
- 浏览器指纹(语言、时区、坐标)与代理位置一致
- 无代理时默认使用 `en-US`、`America/Los_Angeles` 及旧金山坐标
### 结构化日志
所有日志输出为 JSON(每行一个对象),便于日志聚合器解析:
```
{"ts":"2026-02-11T23:45:01.234Z","level":"info","msg":"req","reqId":"a1b2c3d4","method":"POST","path":"/tabs","userId":"agent1"}
{"ts":"2026-02-11T23:45:01.567Z","level":"info","msg":"res","reqId":"a1b2c3d4","status":200,"ms":333}
```
健康检查请求(`/health`)不计入请求日志以降低噪音。
### 基础浏览
```
# 创建标签页
curl -X POST http://localhost:9377/tabs \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "sessionKey": "task1", "url": "https://example.com"}'
# 使用元素引用获取可访问性快照
curl "http://localhost:9377/tabs/TAB_ID/snapshot?userId=agent1"
# → { "snapshot": "[button e1] Submit [link e2] Learn more", ... }
# 通过引用点击
curl -X POST http://localhost:9377/tabs/TAB_ID/click \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "ref": "e1"}'
# 向元素输入内容
curl -X POST http://localhost:9377/tabs/TAB_ID/type \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "ref": "e2", "text": "hello", "pressEnter": true}'
# 使用搜索宏导航
curl -X POST http://localhost:9377/tabs/TAB_ID/navigate \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "macro": "@google_search", "query": "best coffee beans"}'
```
## API
### 标签页生命周期
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| `POST` | `/tabs` | 创建标签页并设置初始 URL |
| `GET` | `/tabs?userId=X` | 列出打开的标签页 |
| `GET` | `/tabs/:id/stats` | 标签页统计(工具调用、访问 URL) |
| `DELETE` | `/tabs/:id` | 关闭标签页 |
| `DELETE` | `/tabs/group/:groupId` | 关闭标签页组 |
| `DELETE` | `/sessions/:userId` | 关闭用户所有标签页 |
### 页面交互
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| `GET` | `/tabs/:id/snapshot` | 可访问性快照(含元素引用)。查询参数:`includeScreenshot=true`(附加 base64 PNG)、`offset=N`(分页大快照) |
| `POST` | `/tabs/:id/click` | 点击元素(引用或 CSS 选择器) |
| `POST` | `/tabs/:id/type` | 向元素输入文本 |
| `POST` | `/tabs/:id/press` | 按下键盘按键 |
| `POST` | `/tabs/:id/scroll` | 滚动页面(上下左右) |
| `POST` | `/tabs/:id/navigate` | 导航至 URL 或搜索宏 |
| `POST` | `/tabs/:id/wait` |等待选择器或超时 |
| `GET` | `/tabs/:id/links` | 提取页面所有链接 |
| `GET` | `/tabs/:id/images` | 列出 `
` 元素。查询参数:`includeData=true`(返回内联 data URL)、`maxBytes=N`、`limit=N` |
| `GET` | `/tabs/:id/downloads` | 列出捕获的下载。查询参数:`includeData=true`(base64 文件数据)、`consume=true`(读取后清除)、`maxBytes=N` |
| `GET` | `/tabs/:id/screenshot` | 截取屏幕 |
| `POST` | `/tabs/:id/back` | 后退 |
| `POST` | `/tabs/:id/forward` | 前进 |
| `POST` | `/tabs/:id/refresh` | 刷新 |
### YouTube 文本
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| `POST` | `/youtube/transcript` | 从 YouTube 视频提取字幕 |
```
curl -X POST http://localhost:9377/youtube/transcript \
-H 'Content-Type: application/json' \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "languages": ["en"]}'
# → { "status": "ok", "transcript": "[00:18] ♪ We're no strangers to love ♪\n...", "video_title": "...", "total_words": 548 }
```
使用可用的 [yt-dlp](https://github.com/yt-dlp/yt-dlp)(快速路径,无需浏览器)。若未安装则回退到浏览器拦截方式,速度较慢且受 YouTube 广告前贴片影响。
### 服务器
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| `GET` | `/health` | 健康检查 |
| `POST` | `/start` | 启动浏览器引擎 |
| `POST` | `/stop` | 停止浏览器引擎 |
### 会话
| 方法 | 端点 | 描述 |
|--------|----------|-------------|
| `POST` | `/sessions/:userId/cookies` | 向用户会话添加 Cookie(Playwright 格式对象) |
## 搜索宏
`@google_search` · `@youtube_search` · `@amazon_search` · `@reddit_search` · `@reddit_subreddit` · `@wikipedia_search` · `@twitter_search` · `@yelp_search` · `@spotify_search` · `@netflix_search` · `@linkedin_search` · `@instagram_search` · `@tiktok_search` · `@twitch_search`
Reddit 宏直接返回 JSON(无需 HTML 解析):
- `@reddit_search` — 搜索全站 Reddit,返回含 25 条结果的 JSON
- `@reddit_subreddit` — 浏览子版块(例:查询 `"programming"` → `/r/programming.json`)
## 环境变量
| 变量 | 描述 | 默认 |
|----------|-------------|---------|
| `CAMOFOX_PORT` | 服务器端口 | `9377` |
| `PORT` | 服务器端口(备用,用于 Fly.io 等平台) | `9377` |
| `CAMOFOX_API_KEY` | 启用 Cookie 导入端点(未设置则禁用) | — |
| `CAMOFOX_ADMIN_KEY` | 启用 `POST /stop` 所需 | — |
| `CAMOFOX_COOKIES_DIR` | Cookie 文件目录 | `~/.camofox/cookies` |
| `MAX_SESSIONS` | 最大并发浏览器会话 | `50` |
| `MAX_TABS_PER_SESSION` | 每会话最大标签页数 | `10` |
| `SESSION_TIMEOUT_MS` | 会话空闲超时 | `1800000`(30 分钟) |
| `BROWSER_IDLE_TIMEOUT_MS` | 浏览器空闲后关闭(0 = 永不) | `300000`(5 分钟) |
| `HANDLER_TIMEOUT_MS` | 单个请求最大处理时间 | `30000`(30 秒) |
| `MAX_CONCURRENT_PER_USER` | 每用户并发请求上限 | `3` |
| `MAX_OLD_SPACE_SIZE` | Node.js V8 堆限制(MB) | `128` |
| `PROXY_STRATEGY` | 代理模式:`backconnect`(旋转粘性会话)或空(单端点) | — |
| `PROXY_PROVIDER` | 会话格式提供者(如 `decodo`) | `decodo` |
| `PROXY_HOST` | 代理主机或 IP(简单模式) | — |
| `PROXY_PORT` | 代理端口(简单模式) | — |
| `PROXY_USERNAME` | 代理认证用户名 | — |
| `PROXY_PASSWORD` | 代理认证密码 | — |
| `PROXY_BACKCONNECT_HOST` | 回连网关主机名 | — |
| `PROXY_BACKCONNECT_PORT` | 回连网关端口 | `7000` |
| `PROXY_COUNTRY` | 代理地理目标国家 | — |
| `PROXY_STATE` | 代理地理目标州/区域 | — |
| `TAB_INACTIVITY_MS` | 超过此时间关闭标签页 | `300000`(5 分钟) |
## 架构
```
Browser Instance (Camoufox)
└── User Session (BrowserContext) - isolated cookies/storage
├── Tab Group (sessionKey: "conv1")
│ ├── Tab (google.com)
│ └── Tab (github.com)
└── Tab Group (sessionKey: "conv2")
└── Tab (amazon.com)
```
会话在 30 分钟无活动后自动过期。浏览器在无活跃会话 5 分钟后自动关闭,并在下次请求时重新启动。
当会话达到标签页上限时,自动回收最旧/最少使用的标签页,而非返回错误 —— 因此长时间运行的代理会话不会遇到死胡同。
## 测试
```
npm test # all tests
npm run test:e2e # e2e tests only
npm run test:live # live site tests (Google, macros)
npm run test:debug # with server output
```
## npm
```
npm install @askjo/camofox-browser
```
## 加密货币诈骗警告
一些不法分子正在利用本项目的关注度,用名为 “Camofox” 的加密货币代币做手脚。**Camofox 并非加密项目,也永远不会成为加密项目。** 任何使用 Camofox 名称的代币、币或 NFT 都与我们无关。
## 许可证
MIT 标签:AI代理, AI浏览, AudioContext, Camoufox, Chrome无头指纹, C++级补丁, Docker, Firefox Fork, MITM代理, Playwright绕过, REST API, SEO, Telegram, WebGL渲染器, WebRTC, WhatsApp, 云部署, 反机器人检测, 反检测, 头部浏览器, 安全防御评估, 屏幕几何, 搜索宏, 无头浏览器, 浏览器指纹混淆, 硬件并发, 稳定元素引用, 网站访问, 自动化服务器, 自定义脚本, 访问性快照, 请求拦截, 阻止绕过, 隐身插件