CF浏览器
阅读任何网站的最快方式 克劳德代码.
提供Claude代码的开源工具 15个MCP工具+6个现成技能 用于JavaScript渲染的网页——内容提取、屏幕截图、PDF、可访问性快照、人工智能驱动的数据提取、多页爬行和 浏览器交互 (点击、键入、表单提交、JS eval、动作链)。由...驱动 Cloudflare浏览器渲染 零成本免费套餐。支持 直接模式 (无需工人)和 工人模式 (具有缓存、速率限制和交互)。
   
为什么选择CF浏览器?
Claude Code的内置 WebFetch 只返回原始HTML。单页应用程序、动态内容和JS渲染的页面都是空的。CF浏览器解决了这个问题:
- JS执行 --完全无头Chrome在提取之前渲染页面
- 15个专用工具 --markdown、截图、PDF、可访问性快照、AI提取、爬行,以及点击/键入/评估/交互/表单提交
- 浏览器交互 --点击按钮、填写表单、执行JS、链接多步操作(Worker模式)
- 经过身份验证的抓取 --为登录页面注入Cookie和自定义标头
- 零成本 --只读工具在Cloudflare的免费层上运行;交互工具需要工人付费($5/mo)
- 基于边缘 --来自300多个Cloudflare位置的全球低延迟
快速开始
使用CF浏览器的两种方法——选择适合的一种:
| 直接模式 | 工人模式 | |
|---|---|---|
| 设置 | pip install +2个环境变量 | 部署Worker+ pip install |
| 开始的时候 | 2分钟 | 10分钟 |
| 需求 | CF账号ID+API代币 | 工人+KV+R2 |
| 可用工具 | 10个只读工具 | 全部15个工具 |
| 缓存 | 无 | KV+R2(节省约70%的API配额) |
| 速率限制 | 无 | 每键需要60次/分钟 |
| 多用户 | 否(共享CF凭据) | 是(每个用户都有自己的API密钥) |
| 最佳 | 个人使用,快速启动 | 团队,生产,大批量 |
选项A:直接模式(无工人)
直接调用Cloudflare浏览器渲染API-无需部署Worker。
pip install cf-browser cf-browser-mcp添加到您的 .mcp.json:
{
"mcpServers": {
"cf-browser": {
"type": "stdio",
"command": "python3",
"args": ["-m", "cf_browser_mcp.server"],
"env": {
"CF_ACCOUNT_ID": "",
"CF_API_TOKEN": ""
}
}
}
}获取您的凭据:
- 账户ID:
wrangler whoami或 Cloudflare 控制面板 → 任何域名→ 概述→ 右侧边栏 - API代币: dash.cloudflare.com/profile/api-tokes → 创建令牌→ 使用“编辑Cloudflare Workers”模板
重新启动克劳德代码。10个只读工具立即工作;5个交互工具需要Worker模式。
选项B:工作模式(带缓存和速率限制)
部署Cloudflare Worker作为具有内置缓存和身份验证的边缘代理。
一个命令设置:
git clone https://github.com/claude-world/cf-browser.git
cd cf-browser
bash setup.sh安装脚本创建所有Cloudflare资源,部署Worker,安装Python包,并输出可粘贴的 .mcp.json 配置。
Click to expand manual Worker setup
先决条件
- Node.js 18+,Python 3.10+
- Cloudflare帐户 浏览器渲染 启用
wranglerCLI已通过身份验证(npm i -g wrangler && wrangler login)
步骤1:部署Worker
cd worker
cp wrangler.toml.example wrangler.toml
npm install创建资源并将命名空间ID粘贴到 wrangler.toml:
wrangler kv namespace create CACHE
wrangler kv namespace create RATE_LIMIT
wrangler r2 bucket create cf-browser-storage设置秘密:
wrangler secret put CF_ACCOUNT_ID # from: wrangler whoami
wrangler secret put CF_API_TOKEN # from: https://dash.cloudflare.com/profile/api-tokens
echo "$(openssl rand -hex 32)" | wrangler secret put API_KEYS部署:
wrangler deploy
# → https://cf-browser..workers.dev第二步:安装SDK+MCP服务器
pip install cf-browser cf-browser-mcp或者从源代码安装:
cd sdk && pip install -e .
cd ../mcp-server && pip install -e .步骤3:在Claude Code中注册MCP
添加到您的项目 .mcp.json:
{
"mcpServers": {
"cf-browser": {
"type": "stdio",
"command": "python3",
"args": ["-m", "cf_browser_mcp.server"],
"env": {
"CF_BROWSER_URL": "https://cf-browser..workers.dev",
"CF_BROWSER_API_KEY": ""
}
}
}
}重新启动克劳德代码。你会看到15 browser_* 工具可用。
建筑
┌─────────────────────┐
│ Claude Code │
└──────────┬───────────┘
│
┌──────────▼───────────┐
│ MCP Server (15 tools)│
└──────────┬───────────┘
│
┌────────────────┴────────────────┐
│ │
Direct Mode Worker Mode
(CF_ACCOUNT_ID (CF_BROWSER_URL
+ CF_API_TOKEN) + CF_BROWSER_API_KEY)
│ │
│ ┌─────────────▼──────────────┐
│ │ Cloudflare Worker │
│ │ ├── Auth (timing-safe) │
│ │ ├── Rate limit (KV) │
│ │ └── Cache (KV + R2) │
│ └─────────────┬──────────────┘
│ │
└────────────────┬─────────────────┘
│
┌──────────▼───────────┐
│ CF Browser Rendering │
│ API (Chrome) │
└──────────────────────┘三个独立的包:
| 包装 | 语言 | 用途 |
|---|---|---|
worker/ | TypeScript(Hono+Puppeter) | 带身份验证、缓存、速率限制、浏览器交互的边缘代理 |
sdk/ (cf-browser 在PyPI上) | Python(httpx) | 异步客户端库 |
mcp-server/ (cf-browser-mcp PyPI上) | Python(FastMCP) | 用于Claude代码的15个MCP工具 |
MCP工具
只读工具(直接+工作模式)
| 工具 | 输入 | 输出 | 用例 |
|---|---|---|---|
browser_markdown | url | Markdown字符串 | 将任何网页读取为纯文本 |
browser_content | url | HTML字符串 | 获取完全渲染的HTML(JS执行) |
browser_screenshot | url、宽度、高度 | PNG文件路径 | 视觉验证、多设备测试 |
browser_pdf | url,格式 | PDF文件路径 | 生成报告,存档页面 |
browser_scrape | url,选择器\[\] | {"elements":[...]} | 提取与规范化元数据匹配的选择器 |
browser_json | url,prompt | JSON | 人工智能驱动的结构化数据提取 |
browser_links | url | [{href, text}] | 发现页面上的所有超链接 |
browser_a11y | url | JSON | 面向可访问性的快照,去掉了屏幕截图 |
browser_crawl | url,限制 | {"job_id","status"} | 启动异步多页爬网 |
browser_crawl_status | job_id,等待 | JSON | 轮询或等待爬网结果 |
交互工具(仅限Worker模式——需要BROWSER绑定)
| 工具 | 输入 | 输出 | 用例 |
|---|---|---|---|
browser_click | url,选择器 | JSON | 单击按钮/链接并获取结果页面 |
browser_type | url、选择器、文本 | JSON | 在输入字段中键入 |
browser_evaluate | url,script | JSON | 执行JavaScript并获取返回值 |
browser_interact | url,actions\[\] | JSON | 链接多个动作(点击、键入、等待、截图等) |
browser_submit_form | url,字段 | JSON | 在一次调用中填写和提交表单 |
所有工具均接受可选 cookies, headers, wait_for, wait_until,以及 user_agent 参数。使用 wait_until="networkidle0" 用于SPA网站(React、Next.js、X/Twitter)。
克劳德代码中的示例
"Read the React 19 migration guide"
→ browser_markdown("https://react.dev/blog/2024/12/05/react-19")
"Show me what our homepage looks like on mobile"
→ browser_screenshot("https://example.com", width=375, height=667)
"Extract the top 5 products with name, price, and rating"
→ browser_json("https://example.com/products", prompt="Extract top 5 products...")
"Get the page structure for accessibility analysis"
→ browser_a11y("https://example.com")
"Scrape our dashboard (requires login)"
→ browser_markdown("https://app.example.com/dashboard", cookies='[{"name":"session","value":"abc"}]')
"Find all broken links on our site"
→ browser_crawl("https://example.com", limit=50) → browser_crawl_status(job_id, wait=True)
"Log into our staging site and check the dashboard"
→ browser_interact("https://staging.example.com/login", actions=[
{"action":"type", "selector":"#email", "text":"admin@example.com"},
{"action":"type", "selector":"#password", "text":"secret"},
{"action":"click", "selector":"button[type=submit]"},
{"action":"wait", "selector":".dashboard"},
{"action":"screenshot"}
])
"Fill out the contact form"
→ browser_submit_form("https://example.com/contact",
fields={"#name":"Claude", "#email":"claude@example.com", "#message":"Hello!"},
submit_selector="button.submit")工人API参考
所有路线(除 /health)要求 Authorization: Bearer 头球
端点
| 路由 | 方法 | 正文 | 缓存 | 响应 |
|---|---|---|---|---|
/health | 获取 | -- | -- | {"status":"ok","version":"2.0.1","capabilities":{"interact":...}} |
/content | 职位 | {url, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 1小时 | HTML |
/markdown | 职位 | {url, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 1小时 | Markdown |
/screenshot | 职位 | {url, width?, height?, full_page?, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | R2 24小时 | 巴布亚新几内亚 |
/pdf | 职位 | {url, format?, landscape?, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | R2 24小时 | |
/snapshot | 职位 | {url, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 30分钟 | JSON |
/scrape | 职位 | {url, elements[], wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 30分钟 | {"elements":[...]} |
/json | 职位 | {url, prompt, schema?, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | 无 | JSON |
/links | 职位 | {url, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 1小时 | [{href, text}] |
/a11y | 职位 | {url, wait_for?, wait_until?, user_agent?, cookies?, headers?, no_cache?} | KV 5分钟 | {"type":"accessibility_snapshot", ...} |
/crawl | 职位 | {url, limit?, user_agent?, cookies?, headers?, no_cache?} | — | {"job_id":"..."} |
/crawl/:id | 获取 | -- | R2 | JSON |
/crawl/:id | 删除 | -- | -- | 204无内容 |
/click | 职位 | {url, selector, wait_for?, ...} | 无 | JSON |
/type | 职位 | {url, selector, text, clear?, wait_for?, ...} | 无 | JSON |
/evaluate | 职位 | {url, script, wait_for?, ...} | 无 | JSON |
/interact | 职位 | {url, actions[], wait_for?, ...} | 无 | JSON |
/submit-form | 职位 | {url, fields, submit_selector?, wait_for?, ...} | 无 | JSON |
互动路线(/click, /type, /evaluate, /interact, /submit-form)要求 BROWSER 结合。如果未配置绑定,则返回501。如果这些路由返回404,则Worker部署已过时;重新部署和验证 /health 报告 version: "2.0.1".
响应形状在Worker、SDK和MCP之间进行了标准化:
/scrape回报{"elements":[{"selector":"...", "results":[...]}]}即使上游API返回原始列表。/links返回一个数组{href, text}物体;裸URL字符串被提升为{href, text: null}./a11y源自于/snapshot,剥离base64屏幕截图有效载荷,并添加type: "accessibility_snapshot".
经过身份验证的请求
所有端点都接受可选 cookies 和 headers 用于访问经过身份验证的页面的字段:
curl -X POST https://cf-browser.example.workers.dev/markdown \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/dashboard",
"cookies": [{"name": "session_id", "value": "abc123", "domain": ".example.com"}],
"headers": {"X-Custom-Auth": "token"}
}'请求示例
# Get markdown
curl -X POST https://cf-browser.example.workers.dev/markdown \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://react.dev"}'
# Screenshot with viewport
curl -X POST https://cf-browser.example.workers.dev/screenshot \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "width": 1280, "height": 720}' \
-o screenshot.png
# Accessibility snapshot
curl -X POST https://cf-browser.example.workers.dev/a11y \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
# AI extraction
curl -X POST https://cf-browser.example.workers.dev/json \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://news.ycombinator.com", "prompt": "Extract top 5 stories with title and score"}'缓存行为
- 集
"no_cache": true在请求正文中绕过缓存 - 缓存的响应包括
X-Cache: HIT头球 - 文本内容(HTML、Markdown、JSON)存储在KV中
- 二进制内容(PNG、PDF)存储在R2中
- 已完成的爬网结果将持久化到R2
速率限制
- 默认值:每个API密钥每分钟60个请求
- 响应标头:
X-RateLimit-Limit,X-RateLimit-Remaining - 超过:HTTP 429
Retry-After头球
开发包
pip install cf-browser# Direct mode — no Worker needed
from cf_browser import CFBrowserDirect
async with CFBrowserDirect(
account_id="your-cf-account-id",
api_token="your-cf-api-token",
) as browser:
md = await browser.markdown("https://example.com")
# Worker mode — via deployed Worker
from cf_browser import CFBrowser
async with CFBrowser(
base_url="https://cf-browser.example.workers.dev",
api_key="your-key",
) as browser:
# Read a page
markdown = await browser.markdown("https://react.dev")
# Take a screenshot
png_bytes = await browser.screenshot("https://example.com", width=1280, height=720)
# AI-powered extraction
data = await browser.json_extract(
"https://news.ycombinator.com",
prompt="Extract the top 5 stories with title and score",
)
# Accessibility snapshot (LLM-friendly, screenshot stripped)
tree = await browser.a11y("https://example.com")
# Scrape by CSS selectors
elements = await browser.scrape("https://example.com", selectors=["h1", ".price"])
# Authenticated scraping with cookies
md = await browser.markdown(
"https://app.example.com/dashboard",
cookies=[{"name": "session", "value": "abc", "domain": ".example.com"}],
)
# Async crawl
job_id = await browser.crawl("https://example.com", limit=10)
result = await browser.crawl_wait(job_id, timeout=120)SDK方法
只读(直接+工作模式):
| 方法 | 返回 | 描述 |
|---|---|---|
content(url, **opts) | str | 渲染HTML |
markdown(url, **opts) | str | 清除Markdown |
screenshot(url, **opts) | bytes | PNG图像 |
pdf(url, **opts) | bytes | PDF文档 |
snapshot(url, **opts) | dict | HTML+元数据 |
scrape(url, selectors, **opts) | dict | 标准化为 {"elements": [...]} |
json_extract(url, prompt, **opts) | dict | AI提取数据 |
links(url, **opts) | list[dict] | 标准化列表 {href, text} 物体 |
a11y(url, **opts) | dict | 以可访问性为导向的快照,去掉了屏幕截图 |
crawl(url, **opts) | str | 作业ID |
crawl_status(job_id) | dict | 作业状态 |
crawl_wait(job_id, timeout, poll_interval) | dict | 等待完成 |
交互(仅限Worker模式):
| 方法 | 返回 | 描述 |
|---|---|---|
click(url, selector, **opts) | dict | 点击元素,返回页面状态 |
type_text(url, selector, text, clear?, **opts) | dict | 在输入框中键入 |
evaluate(url, script, **opts) | dict | 执行JS,返回结果 |
interact(url, actions, **opts) | dict | 链接多个动作 |
submit_form(url, fields, submit_selector?, **opts) | dict | 填写并提交表格 |
delete_crawl(job_id) | None | 删除缓存的爬网结果 |
所有方法均接受 no_cache=True 为了绕过缓存, cookies/headers 对于经过身份验证的访问, wait_for 等待CSS选择器, wait_until 用于导航策略(networkidle0 对于SPA),以及 user_agent 用于自定义用户代理。互动方式提高 NotImplementedError 在直接模式下。在Worker模式下, 404 Not Found 在交互方法上,通常意味着您指向的是过时的Worker部署,应该重新部署。
安全
- 认证:使用SHA-256进行定时安全承载令牌比较(防止定时攻击)
- 速率限制:按密钥跟踪,使用KV中的哈希密钥材料(不存储原始密钥)
- SSRF预防:只有
http://和https://允许URL;阻止了localhost、私有IP文字和DNS解析为私有IP的主机名 - 秘密:通过存储的所有凭据
wrangler secret put,从不在代码中 - Cookie隔离:Cookie根据请求注入,从不持久化
技能(奖金)
CF浏览器包括6个即用型 Claude代码技能 在 skills/ 目录。将技能文件夹复制到项目的 .claude/skills/ 激活。
| 技能 | 命令 | 它的作用 |
|---|---|---|
| 内容提取器 | /content-extractor | 读取页面、提取结构化数据、抓取元素、发现链接 |
| 现场审计员 | /site-auditor | 抓取网站并生成SEO/链接/可访问性审计报告 |
| 法医 | /doc-fetcher | 将整个文档网站抓取到RAG的本地Markdown |
| 视觉质量保证 | /visual-qa | 多设备视口截图(移动设备/平板电脑/笔记本电脑/台式机)+视觉检查 |
| 变更日志监视器 | /changelog-monitor | 跟踪任何项目的版本更新和重大更改 |
| 竞争对手手表 | /competitor-watch | 提取并比较竞争对手的定价/功能 |
# Copy a single skill
cp -r skills/content-extractor .claude/skills/
# Or copy all
cp -r skills/* .claude/skills/成本
| 组件 | 免费层 | 付费(每月5美元工人) |
|---|---|---|
| 浏览器渲染 | 10分钟/天,5个爬网作业 | 更高的限制 |
| KV | 100K读取/天 | 10M读取/月 |
| R2 | 10GB存储空间 | 包括10GB |
| 工人 | 每天10万次请求 | 每月1000万次请求 |
对于大多数Claude Code的使用,免费层就足够了。交互工具(点击、键入、评估、交互、提交表单)需要为BROWSER绑定提供Workers Paid计划(每月5美元)。
故障排除
browser_click/browser_type/browser_evaluate/browser_interact/browser_submit_form返回501:Worker部署时没有[browser] binding = "BROWSER".- 同样的工具回来了
404:Worker部署比当前仓库旧。重新部署和验证/health回报version: "2.0.1". browser_scrape或browser_links环境之间看起来不同:当前的SDK和MCP规范了传统的上游形状,但最干净的解决方案仍然是重新部署Worker。
发展
工人
cd worker
npm install
npm run dev # Local dev server at :8787
npm run type-check # TypeScript checks
npm test # Run tests软件开发工具包
cd sdk
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -vMCP服务器
cd mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -e ../sdk # Install SDK first
pip install -e ".[dev]"
pytest tests/ -v项目结构
cf-browser/
├── worker/ Cloudflare Worker (TypeScript)
│ ├── src/
│ │ ├── index.ts Hono app entry point
│ │ ├── types.ts Env bindings & request types
│ │ ├── middleware/
│ │ │ ├── auth.ts Bearer token validation
│ │ │ ├── cache.ts KV/R2 cache layer
│ │ │ └── rate-limit.ts Per-key rate limiting
│ │ ├── routes/
│ │ │ ├── content.ts POST /content → HTML
│ │ │ ├── markdown.ts POST /markdown → Markdown
│ │ │ ├── screenshot.ts POST /screenshot → PNG
│ │ │ ├── pdf.ts POST /pdf → PDF
│ │ │ ├── snapshot.ts POST /snapshot → JSON
│ │ │ ├── scrape.ts POST /scrape → JSON
│ │ │ ├── json.ts POST /json → JSON (AI)
│ │ │ ├── links.ts POST /links → JSON
│ │ │ ├── a11y.ts POST /a11y → JSON (accessibility snapshot)
│ │ │ ├── crawl.ts POST/GET/DELETE /crawl
│ │ │ ├── click.ts POST /click (interaction)
│ │ │ ├── type.ts POST /type (interaction)
│ │ │ ├── evaluate.ts POST /evaluate (interaction)
│ │ │ ├── interact.ts POST /interact (action chains)
│ │ │ └── submit-form.ts POST /submit-form (interaction)
│ │ └── lib/
│ │ ├── cf-api.ts CF Browser Rendering client
│ │ ├── puppeteer.ts Puppeteer lifecycle helper (interaction)
│ │ ├── param-map.ts snake_case → CF API camelCase mapping
│ │ ├── response-normalizers.ts scrape/links response normalization
│ │ ├── cache-key.ts SHA-256 cache keys
│ │ └── validate-url.ts SSRF prevention
│ ├── tests/
│ ├── wrangler.toml.example
│ └── package.json
├── sdk/ Python SDK (cf-browser on PyPI)
│ ├── src/cf_browser/
│ │ ├── client.py CFBrowser client (Worker mode)
│ │ ├── direct.py CFBrowserDirect client (Direct mode)
│ │ ├── _normalizers.py Response-shape normalization helpers
│ │ ├── _shared.py Shared helpers (crawl polling)
│ │ ├── models.py Pydantic response models
│ │ └── exceptions.py Typed error hierarchy
│ ├── tests/
│ └── pyproject.toml
├── mcp-server/ MCP Server (cf-browser-mcp on PyPI)
│ ├── src/cf_browser_mcp/
│ │ └── server.py 15 MCP tool definitions
│ └── pyproject.toml
├── examples/ Usage examples
├── setup.sh One-command setup script
├── CHANGELOG.md
├── LICENSE
└── README.md贡献
- 分叉存储库
- 创建要素分支
- 通过测试进行更改
- 跑
npm test(工人)和pytest(SDK+MCP服务器)验证 - 提交拉取请求
