关于 using-webctl
用于在 Claude.ai 容器中通过 webctl 命令行进行浏览器自动化的技能,说明 Chromium 的认证代理解决方案,以及网页导航、检查和交互命令。
主要功能
- 01认证代理转发配置
- 02webctl 会话与导航命令
- 03网页快照与截图
- 04基于 ARIA 的查询和交互
- 05代理故障排查说明
适用场景
- 01在 Claude.ai 容器中自动操作浏览器
- 02通过快照检查网页
- 03与表单和页面控件交互
- 04排查 Chromium 代理隧道故障
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oaustegard/ claude-skills --skill using-webctl安装后在 Claude Code 中输入/using-webctl确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdREADME.mdscripts/auth_proxy.pysetup_webctl.py详细介绍
在 Claude.ai 容器中使用 webctl
通过 webctl CLI 进行浏览器自动化,并在 Claude.ai 的出口流量受控环境中自动处理代理身份验证。
适用场景
- 用户请求浏览器自动化、网页抓取或页面交互
- webctl 命令因
ERR_TUNNEL_CONNECTION_FAILED失败 - Playwright/Chromium 需要通过经过身份验证的 HTTP 代理工作
核心问题
Claude.ai 容器通过经过身份验证的出口代理(带有 JWT 凭据的 HTTP_PROXY 环境变量)路由流量。Chromium 无法妥善处理 HTTPS CONNECT 隧道的代理身份验证,导致所有 HTTPS 导航失败,尽管 curl 可以正常工作。
解决方案
本地转发代理(端口 18080)会拦截 Chromium 连接,并在转发到实际出口代理前注入 Proxy-Authorization 标头。
设置步骤
1. 安装 webctl
pip install webctl --break-system-packages
webctl setup # Downloads Chromium if needed
2. 部署身份验证代理模块
将 scripts/auth_proxy.py 复制到 webctl 的守护进程目录:
cp /mnt/skills/user/using-webctl/scripts/auth_proxy.py \
/usr/local/lib/python3.12/dist-packages/webctl/daemon/
3. 修补会话管理器
对 /usr/local/lib/python3.12/dist-packages/webctl/daemon/session_manager.py 应用此补丁。
较新的 webctl 版本将上下文创建拆分为两个分支(移动设备模拟与桌面)。两个分支都必须接收代理配置。找到相应代码块(搜索 cfg = WebctlConfig.load(),后面跟着 if mode == "unattended" and cfg.mobile_emulation: 分支——大约在第 190 行):
cfg = WebctlConfig.load()
if mode == "unattended" and cfg.mobile_emulation:
# Mobile emulation: cleaner pages, fewer ads, simpler layouts
device = self._playwright.devices["Pixel 7"]
context = await browser.new_context(
storage_state=storage_state,
**device,
)
else:
context = await browser.new_context(
storage_state=storage_state, viewport={"width": 1280, "height": 720}
)
替换为:
cfg = WebctlConfig.load()
from .auth_proxy import get_local_proxy_url
proxy_url = get_local_proxy_url()
proxy_config = {"server": proxy_url} if proxy_url else None
if mode == "unattended" and cfg.mobile_emulation:
# Mobile emulation: cleaner pages, fewer ads, simpler layouts
device = self._playwright.devices["Pixel 7"]
context = await browser.new_context(
storage_state=storage_state,
proxy=proxy_config,
**device,
)
else:
context = await browser.new_context(
storage_state=storage_state, viewport={"width": 1280, "height": 720},
proxy=proxy_config
)
如果文件中只有一个 new_context 调用(较旧的 webctl 版本),就在该调用中注入 proxy=proxy_config,并将三行 proxy_url 放在它上方。
4. 验证
webctl start --mode unattended
webctl --quiet navigate "https://github.com"
webctl snapshot --interactive-only --limit 10
webctl stop
快速参考
会话管理
webctl start --mode unattended # Headless browser
webctl stop # Full shutdown (use --keep-daemon to leave daemon running)
webctl status # Current state + console error counts
导航
webctl navigate "https://..."
webctl back / webctl forward / webctl reload
观察
webctl snapshot --interactive-only --limit 30 # Buttons, links, inputs
webctl snapshot --within "role=main" # Scope to container
webctl query "role=button name~=Submit" # Debug queries
webctl screenshot --path shot.png
交互
webctl click 'role=button name~="Submit"'
webctl type 'role=textbox name~="Email"' "[email protected]"
webctl type 'role=textbox name~="Search"' "query" --submit
webctl select 'role=combobox name~="Country"' --label "Germany"
查询语法
role=button— 按 ARIA 角色查询name~="partial"— 包含匹配(推荐,更稳健)name="exact"— 精确匹配nth=0— 有多个匹配项时选择第一个
等待条件
webctl wait network-idle
webctl wait 'exists:role=button name~="Continue"'
webctl wait 'url-contains:"/dashboard"'
故障排除
ERR_TUNNEL_CONNECTION_FAILED
身份验证代理未加载。请确认:
auth_proxy.py存在于 webctl 守护进程目录中- 会话管理器已修补
- 重启守护进程:
webctl stop && webctl start --mode unattended
多个匹配项错误
添加更具体的条件或使用 nth=0:
webctl click 'role=link name="Sign in" nth=0'
验证代理是否正在运行
netstat -tlnp | grep 18080
限制
- 补丁仅对当前会话有效(容器重置后会清除)
- 只能访问网络配置中允许的域名
- 不支持 Firefox(出口策略禁止下载)
域名限制
在系统提示词的 <network_configuration> 中查看允许的域名。常见的允许域名包括:*.github.com、*.bsky.app 和允许的 API 端点。
输出过滤
减少上下文消耗:
webctl snapshot --interactive-only --limit 30 # Cap elements
webctl snapshot | grep -i "submit" # Unix filtering
webctl --quiet navigate "..." # Suppress events