让 Claude 操控 Chrome:打开网页、点击填表、截图、抓数据。
帮我用 https://github.com/vercel-labs/agent-browser 安装 agent-browser skill,然后打开我本地的网站把注册流程走一遍并截图
一行指令在 Docker 里拉起带网页远程桌面和 CDP 接口的持久化 Chrome:人可远程看画面、手动登录和过验证码,Agent 同步操作并复用同一套 Cookie。
帮我安装人机共享容器浏览器 skill https://prompt.free2gpt.com/s/shared-chrome.md,然后帮我在当前目录部署一个 Chrome 容器
它会下载 https://prompt.free2gpt.com/s/shared-chrome.md 并把 skill 装到 ~/.claude/skills/shared-chrome/,然后直接开始干活。
curl -fsSL https://prompt.free2gpt.com/s/shared-chrome.md --create-dirs -o ~/.claude/skills/shared-chrome/SKILL.md
docker-compose.yml、官方 Google Chrome(x86_64)或 linuxserver/chromium(arm64)镜像配置、独立 Profile 自启保活脚本与 CDP 端口转发服务:3001 控制 / :#shared 多人只读围观),Agent 通过本机 127.0.0.1:9222 用 agent-browser 或 Playwright 操作同一浏览器./config,容器重启不丢登录状态;遇到登录、扫码、2FA 或验证码时,人工接管完成后 Agent 直接在同一页面继续network_mode: host 冲突、Chrome 136+ 默认目录限制、GUI 模式 CDP 仅监听 127.0.0.1、共享视口裁切与多 Profile 串台等常见坑./browser 部署一个带远程桌面和 CDP 的持久化 Chrome 容器,端口用 3010 和 9225x86_64 架构默认构建官方 Google Chrome(arm64 自动改用基础镜像自带的 Chromium)127.0.0.1:9222(无鉴权,切勿暴露到 0.0.0.0),网页远程桌面通过 .env 中的 Basic Auth 账号密码保护在 Docker 中部署一个带完整 Wayland 桌面(Selkies HTML5 远程桌面)与 CDP 调试接口的持久化 Chrome 实例:
:3001 / HTTP :3000),实时看到画面并操作键鼠、登录账号、处理验证码或 2FAhttp://127.0.0.1:9222(CDP)用 agent-browser / Playwright / Puppeteer 操作同一浏览器会话、共享全部 Cookie 与登录态./config,容器重建后登录态不丢失动手前先快速检查以下信息,缺失或冲突时向用户确认:
uname -m
x86_64(amd64):可构建官方 Google Chrome 镜像(支持 Google 账号同步、风控与兼容性更好)aarch64(arm64):Google 官方无 Linux ARM64 .deb 包,跳过构建,直接用 linuxserver/chromium:latest 自带的 chromium./browser(若用户指定了路径则用用户路径)127.0.0.1:3000(HTTP,供反代)+ 3001:3001(HTTPS 自签证书,局域网/直连),CDP 127.0.0.1:9222ss -tln 或 lsof 检查 3000、3001、9222 是否被占用,冲突则递增端口BROWSER_USER / BROWSER_PASSWORD),未指定时生成强随机密码写入 .envgoogle-chrome.deb 需要代理,询问或读取代理地址(供构建下载及 CHROME_CLI --proxy-server=... 使用)PUID/PGID 默认 1000:1000(若当前非 root 用户则用 id -u / id -g)按下面结构在目标目录(如 ./browser)生成文件:
browser/
├── .env # Basic Auth 账号密码 (chmod 600)
├── docker-compose.yml # 容器编排(bridge 网络 + shm_size 2gb)
├── chrome/ # [仅 x86_64 官方 Chrome]
│ ├── Dockerfile
│ └── google-chrome.deb
├── services/
│ └── cdp-forward # [必须 +x] 0.0.0.0:9223 -> 127.0.0.1:9222 转发
└── config/.config/labwc/
└── autostart # [必须 +x] 独立 profile + 崩溃/关闭 3s 自动重启
x86_64)与 chrome/Dockerfile若 Docker Hub 拉取慢可改用镜像前缀(如 docker.1panel.live/linuxserver/chromium:latest),避免用经常超时的 lscr.io。
mkdir -p chrome services config/.config/labwc
curl -fSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o chrome/google-chrome.deb
chrome/Dockerfile:
FROM linuxserver/chromium:latest
COPY google-chrome.deb /tmp/
RUN rm -f /etc/apt/sources.list.d/* \
&& sed -i "s#deb.debian.org#mirrors.aliyun.com#g" /etc/apt/sources.list \
&& sed -i "/^deb-src/d; /security/d" /etc/apt/sources.list \
&& apt-get update \
&& apt-get install -y --no-install-recommends /tmp/google-chrome.deb \
&& rm -rf /tmp/google-chrome.deb /var/lib/apt/lists/* /etc/apt/sources.list.d/google-chrome.*
若服务器在海外无需阿里云源,可去掉两行
sed。rm -f /etc/apt/sources.list.d/*是为了清理基础镜像里可能卡住apt-get update的第三方源。若为arm64,跳过此步。
services/cdp-forward(必须 chmod +x)关键机制:Chrome 有界面模式下 CDP 固定只监听容器内 127.0.0.1:9222,Docker 端口映射无法直接转出。利用基础镜像自带的 /lsiopy/bin/python3 起一个 s6 自定义常驻服务,将 0.0.0.0:9223 转发到 127.0.0.1:9222:
#!/lsiopy/bin/python3
import asyncio
async def pipe(r, w):
try:
while data := await r.read(65536):
w.write(data)
await w.drain()
finally:
w.close()
async def handle(cr, cw):
try:
ur, uw = await asyncio.open_connection("127.0.0.1", 9222)
except OSError:
cw.close()
return
await asyncio.gather(pipe(cr, uw), pipe(ur, cw), return_exceptions=True)
async def main():
server = await asyncio.start_server(handle, "0.0.0.0", 9223)
await server.serve_forever()
asyncio.run(main())
config/.config/labwc/autostart(必须 chmod +x)关键机制:
--remote-debugging-port,必须显式指定独立 --user-data-dir=$HOME/.config/chrome-profile。while true 循环在退出 3 秒后自动重开并清理残留 Singleton* 锁。#!/bin/bash
PROFILE=$HOME/.config/chrome-profile
BIN=google-chrome # 若 arm64 直接使用基础镜像,改为 chromium
while true; do
pgrep -x chrome >/dev/null || pgrep -x chromium >/dev/null || rm -f "$PROFILE"/Singleton*
"$BIN" \
--no-sandbox \
--test-type \
--password-store=basic \
--start-maximized \
--ozone-platform=wayland \
--user-data-dir="$PROFILE" \
${CHROME_CLI} > /dev/null 2>&1
sleep 3
done &
.env(chmod 600)与 docker-compose.yml.env:
BROWSER_USER=admin
BROWSER_PASSWORD=<生成强随机密码>
docker-compose.yml(x86_64 用 build: ./chrome + image: shared-chrome:latest;arm64 直接 image: linuxserver/chromium:latest):
services:
chromium:
build: ./chrome
image: shared-chrome:latest
container_name: shared-chrome
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
- LC_ALL=zh_CN.UTF-8
- CUSTOM_USER=${BROWSER_USER}
- PASSWORD=${BROWSER_PASSWORD}
- CHROME_CLI=--remote-debugging-port=9222 --remote-allow-origins=* --lang=zh-CN
# 若需浏览器走代理,追加:
# --proxy-server=http://<proxy-host>:<port> --proxy-bypass-list=<local>;127.*;10.*;172.16.*;192.168.*
volumes:
- ./config:/config
- ./services:/custom-services.d:ro
ports:
- 127.0.0.1:3000:3000
- 3001:3001
- 127.0.0.1:9222:9223
shm_size: "2gb"
restart: unless-stopped
安全与架构红线:
network_mode: host:容器内 Wayland/X :1 抽象 unix socket 会与宿主机桌面环境冲突,导致 PulseAudio/Selkies 卡死。0.0.0.0:必须绑定 127.0.0.1:9222:9223(CDP 无鉴权,可读写 Cookie、执行任意 JS)。shm_size: "2gb" 不可省:Docker 默认 64MB /dev/shm 会导致 Chrome 标签页频繁崩溃。chmod +x services/cdp-forward config/.config/labwc/autostart
chmod 600 .env
# 确保挂载目录属主与 PUID:PGID 一致,否则容器内写 profile 会报权限错误
chown -R 1000:1000 config
docker compose up -d --build
等待约 5~10 秒后验收:
# 1. 验证 CDP 就绪
curl -fsS http://127.0.0.1:9222/json/version
# 2. 验证远程桌面端口监听
curl -skI https://127.0.0.1:3001 | head -n 3
验收成功后向用户输出:
https://<服务器IP>:3001(及只读观看地址 https://<服务器IP>:3001/#shared).env)http://127.0.0.1:9222URL/#shared,可无限多人同时观看,输入事件会被丢弃,不抢控制权~/.agent-browser/config.json 写入 {"cdp": "9222"}(或每次传 --cdp 9222);结束会话用 agent-browser close 只断开连接,不会关闭 Chromeconst browser = await chromium.connectOverCDP("http://127.0.0.1:9222");
const context = browser.contexts()[0]; // 必须取 contexts()[0] 才能复用持久化登录态!
agent-browser set viewport 或 setViewportSize,否则页面尺寸与远程桌面窗口不一致会导致底部/右侧按钮被裁切;保持随窗口自适应。若误设,执行 agent-browser close 断开该会话即可清除模拟,无需重启容器