新开源工具采用 CLI 而非 MCP 架构做浏览器自动化,适合 agent 开发者快速集成。对构建自动化工作流的程序员有直接应用价值。
为 AI agents 和人类构建的浏览器自动化工具,基于命令行。
pip install webctl
webctl navigate "https://example.com" # Auto-starts browser, returns page data
webctl click "Sign in" # Click by text description
webctl snapshot # See all elements with @refs
webctl stop # Closes browser and daemon
MCP 浏览器工具有一个根本性问题:服务器控制什么内容进入你的上下文。使用 Playwright MCP,每个响应都包含完整的无障碍树加上控制台消息。查询几个页面后,你的上下文窗口就满了。这导致性能下降、上下文丢失和成本上升。
CLI 反转了这个逻辑:你控制什么进入上下文。
# Filter before context
webctl snapshot --interactive-only --limit 30 # Only buttons, links, inputs
webctl snapshot --within "role=main" # Skip nav, footer, ads
# Pipe through Unix tools
webctl snapshot | grep -i "submit" # Find specific elements
webctl --format jsonl snapshot | jq '.data.role' # Extract with jq
除了过滤,CLI 还给你:
参见:MCP Considered Suboptimal —— 一个社区知识库,收集 CLI-over-MCP 的模式和替代方案。
webctl 与 agent-browser(Vercel 的浏览器 CLI)在 4 个真实场景的任务中的直接对标。两个工具都使用 Claude Opus 作为驱动 agent。
webctl 在所有 4 个任务上都以更低的成本达到更高的质量评分。以地标为基础的快照会收缩导航和侧边栏并优先显示内容,而自动降级方案(cookie 弹窗关闭、滚动查找、覆盖层重试)可以在不增加 agent 轮数的情况下处理复杂网站。
结构化数据优先:navigate 在涉及无障碍树之前会提取 JSON-LD / Open Graph 元数据(价格、评分、作者等)—— 通常足以回答问题而无需完整快照
基于地标的过滤:收缩 nav / footer / sidebar 地标,让 agents 看到内容而不是界面装饰
智能网络空闲检测:自定义加载检测,忽略媒体流和 websocket —— 有视频 / 分析的页面不会阻塞加载
在一个轮次中行动和观察:click / type 上的 --snapshot 标志返回更新后的页面状态,节省往返
设置:每个任务运行单个工具(webctl 或 agent-browser)的 Claude Opus,预算上限为 $1,无人工干预。质量由单独的 Claude 评估调用评分 0–10。
Amazon 产品查询:在 amazon.de 上为特定产品查找价格和运费
Spiegel.de 头条:从德国新闻网站提取前 5 条头条
Google Maps 餐厅:在柏林查找评分 >4 星的纯素中餐厅
DuckDuckGo 搜索:搜索企鹅爱好者网站并返回前 3 个结果
自己运行基准测试:bash benchmarks/bench_run.sh
npx skills add cosinusalpha/webctl
这会安装技能文件。你的 agent 会在第一次使用时自动安装 webctl 包。
pip install webctl
webctl setup # Downloads Chromium
webctl init # Generate skills/prompts for your agents
webctl init --global # Or install globally (works across all projects)
webctl init 为 Claude Code 和 Goose 创建按需技能,为 Gemini、Copilot 和 Codex 创建简化 prompt。
为什么用技能? 技能按需加载 —— 你的 agent 只在实际进行网页自动化时才读取 webctl 指令。这为其他任务保持上下文整洁。
选择特定 agent:
webctl init --agents claude,gemini # Only Claude and Gemini
webctl init --agents claude-noskill # Legacy CLAUDE.md format
如果你的 agent 没有自动检测生成的文件,把这个加到你的系统 prompt:
For web browsing, use webctl CLI. Run webctl agent-prompt for instructions.
注:如果已经配置了浏览器 MCP,禁用它以避免冲突。
webctl navigate "https://..." # Structured data + page summary
webctl navigate "https://..." --snapshot # Full a11y snapshot with @refs
webctl navigate "https://..." --read # Readable markdown content
webctl navigate "https://..." --search "query" # Find search box, type, submit
webctl navigate "https://..." --grep "price" # Filtered a11y snapshot
webctl back / forward / reload
webctl snapshot --interactive-only # Buttons, links, inputs only
webctl snapshot --within "role=main" # Scope to container
webctl query "role=button name~=Submit" # Debug query
webctl screenshot --path shot.png
webctl click "Submit" # By text description
webctl click @e3 # By @ref from snapshot
webctl click "Submit" --snapshot # Click + return updated page state
webctl type "Email" "user@example.com" # Smart targeting
webctl type "Country" "Germany" # Auto-detects dropdowns
webctl type "Search" "query" --submit # Type + press Enter
webctl press Enter
webctl do '[[...],[...]]' --snapshot # Batch multiple actions
webctl wait network-idle
webctl wait 'exists:role=button name~="Continue"'
webctl wait 'url-contains:"/dashboard"'
webctl status # Current state & error counts
webctl save # Persist cookies now
webctl console --count # Just counts by level (LLM-friendly)
webctl console --level error # Filter to errors only
浏览器在各个命令间保持打开。Cookie 持久化到磁盘。
webctl start # Visible browser
webctl start --mode unattended # Headless (invisible)
webctl -s work start # Named profile (separate cookies)
基于 ARIA 角色的语义化目标 —— 在 CSS 重构中保持稳定:
role=button # Any button
role=button name="Submit" # Exact match
role=button name~="Submit" # Contains text (preferred)
webctl snapshot # Human-readable
webctl --quiet navigate "..." # Suppress events
webctl --result-only --format jsonl navigate "..." # Pure JSON
┌─────────────┐ Unix Socket ┌─────────────┐
│ CLI │ ◄────────────► │ Daemon │
│ (webctl) │ JSON-RPC │ (browser) │
└─────────────┘ └─────────────┘
│ │
▼ ▼
Agent/User Chromium + Playwright
CLI:无状态,向 daemon 发送命令
Daemon:管理浏览器,首次命令时自动启动
Socket:$WEBCTL_SOCKET_DIR 或 OS 默认值(见下文)
Profiles:~/.local/share/webctl/profiles/
用 WEBCTL_SOCKET_DIR 环境变量覆盖目录。
webctl 验证 CLI 命令来自与 daemon 相同的用户:
所有平台都使用内核级凭据验证。这防止其他用户控制你的浏览器会话。
使用自定义 Chromium 二进制(跳过托管安装):
webctl config set browser_executable_path /path/to/chrome
# One-off override via environment:
WEBCTL_BROWSER_PATH=/path/to/chrome webctl start
允许全局 Playwright,即使版本不匹配(可选加入,谨慎使用):
webctl config set use_global_playwright true
重置为默认值:
webctl config set browser_executable_path null
webctl config set use_global_playwright false
为企业网络或 CI 环境配置 HTTP / HTTPS 代理。
通过环境变量(推荐用于 CI):
# Standard proxy env vars (auto-detected)
export HTTPS_PROXY=http://proxy.corp.com:8080
export NO_PROXY=localhost,*.internal.com
webctl start
# Or use webctl-specific var (highest priority)
export WEBCTL_PROXY_SERVER=http://proxy.corp.com:8080
通过配置文件(持久化):
webctl config set proxy_server http://proxy.corp.com:8080
webctl config set proxy_bypass localhost,*.internal.com
# For authenticated proxies
webctl config set proxy_username myuser
webctl config set proxy_password mypass
优先级顺序:WEBCTL_PROXY_SERVER > HTTPS_PROXY > HTTP_PROXY > 配置文件
检查和清除设置:
webctl config show # View all settings
webctl config set proxy_server null # Clear proxy
记录所有 webctl 命令及其输出为 shell-transcript 格式:
export WEBCTL_LOG=/tmp/webctl.log
webctl navigate "https://example.com"
webctl click "Submit"
cat /tmp/webctl.log # Review transcript
每个命令都被记录为 $ 前缀,后跟其输出,附加到文件。
限制浏览器可以导航到的域名。直接编辑配置文件(webctl config show 找到路径):
{
"domain_policy": {
"enabled": true,
"policy": {
"mode": "allow",
"allow": ["localhost", "*.mycompany.com", "github.com"],
"deny": []
}
}
}
域名模式支持 glob 通配符(如 *.example.com)。内置默认否决列表会阻止已知的恶意模式,无论模式如何。
设置 WEBCTL_SOCKET_DIR 在主机和容器之间(或容器之间)共享 Unix socket。
mkdir -p /tmp/webctl-ipc
docker run -d --name webctl-daemon \
-u $(id -u):$(id -g) \
-v /tmp/webctl-ipc:/ipc \
-e WEBCTL_SOCKET_DIR=/ipc \
my-webctl-image python -m webctl.daemon.server
export WEBCTL_SOCKET_DIR=/tmp/webctl-ipc
webctl start && webctl navigate "https://example.com"
-u $(id -u):$(id -g) 确保 socket 文件由你的主机用户拥有。
docker volume create webctl-ipc
docker run -d --name webctl-daemon \
-v webctl-ipc:/ipc \
-e WEBCTL_SOCKET_DIR=/ipc \
my-webctl-image python -m webctl.daemon.server
docker run --rm \
-v webctl-ipc:/ipc \
-e WEBCTL_SOCKET_DIR=/ipc \
my-webctl-image webctl navigate "https://example.com"
不需要 UID 匹配 —— 两个容器以相同用户身份运行。
uv tool install webctl
uv tool run webctl
playwright install-deps chromium
# Or manually install libraries listed in Playwright documentation