chatgpt-browser-ask
用 CDP(Chrome DevTools Protocol)+ Playwright 遥控本机正在运行、且已登录的 Google Chrome,在 ChatGPT 标签页里发问、上传附件、切换模型/思考强度、等生成、抓回答。
它不发任何 HTTP、不碰 token —— 用的就是用户本人的登录态,等价于"帮你在自己浏览器里点鼠标、拖文件、读屏幕"。
核心是
scripts/chatgpt.cjs(Node CLI)。仓库里另有scripts/legacy-applescript/是纯 AppleScript 文字版兜底(不需调试端口,但不支持附件与选模型)——见文末。
前置条件(务必先确认)
- macOS + Google Chrome + Node ≥ 18。
- 安装 Playwright:在 skill 目录
npm i(或全局npm i -g playwright)。 - Chrome 必须以调试端口启动,并带上你平时的登录态:
本质是# 先完全退出 Chrome(Cmd+Q),再运行: scripts/launch_chrome.sh # 默认端口 9222,复用你日常 profile(含登录态)--remote-debugging-port=9222 --user-data-dir="<你平时的 Chrome profile>"。 启动后确认已登录 https://chatgpt.com 。 - 脚本默认连
http://127.0.0.1:9222,可用--cdp URL或环境变量CHATGPT_CDP改。
快速用法
# 同步:问一个问题,等它答完,答案打到 stdout
node scripts/chatgpt.cjs ask --new "你的困难问题" # 开新会话
node scripts/chatgpt.cjs ask "追问:再展开第2点" # 接着同一会话追问
# 带附件(可多次 --attach)+ 指定思考强度
node scripts/chatgpt.cjs ask --new --attach ./a.pdf --attach ./b.png --effort instant "总结这两个文件"
# 选模型 / 思考强度(也可单独设置:model 子命令)
node scripts/chatgpt.cjs ask --new --effort pro "需要深度推理的问题"
node scripts/chatgpt.cjs model --effort instant # 只切强度,不发问
# 异步:发完立即返回,后台监听器替你等结果(适合长推理 / 你要去干别的)
node scripts/chatgpt.cjs send --new "很难的问题"
nohup node scripts/chatgpt.cjs watch --notify --out ~/Downloads/ans.md >/tmp/w.log 2>&1 &
# ↑ 答完弹 macOS 通知 + 写文件;--exec 'CMD' 触发后续处理
# 多 Agent:各带 --session,互不干扰(详见"并发/多 Agent 隔离")
node scripts/chatgpt.cjs ask --session A --new "A 的问题"
node scripts/chatgpt.cjs ask --session B --new "B 的问题"
也可用同名瘦包装:
scripts/chatgpt_ask.sh/chatgpt_watch.sh/chatgpt_shot.sh(转发到上面的 CLI)。
子命令与选项
| 子命令 | 作用 |
|---|---|
ask "问题" |
发送并等待,回答打到 stdout |
send "问题" |
只发送(异步),记录 pending 后立即退出 |
watch |
等待 pending 的结果(--out/--notify/--exec) |
adopt |
把当前 Chrome 里已打开的 /c/ 会话认作本 session 的会话 |
model |
仅设置模型/思考强度 |
shot |
截图当前会话标签(视觉兜底) |
通用选项:--session NAME、--new、--attach PATH(可重复)、--effort LABEL、
--model NAME、--timeout SEC、--interval SEC、--raw、--cdp URL。
- 思考强度
--effort:instant/fast(极速) ·balanced(均衡) ·advanced(高级) ·ultra(超高) ·pro(Pro 扩展)。也可直接给中文标签(按子串匹配)。 - 模型
--model:模型家族子菜单里的名字,如"GPT-5.5"(按子串匹配,best-effort)。 - ⚠️ 强度/模型菜单文案区域相关(示例是简中界面);换语言需按你界面里的文案传。
保持"前后问题在同一会话"(核心设计)
- 第一次发问后,ChatGPT 会把 URL 变成
chatgpt.com/c/<会话id>。CLI 把它存到~/.config/chatgpt-browser-ask/<session>/conversation_url。 - 之后不带
--new的每次调用都按/c/<id>定位到该标签追问 → 始终同一上下文。 - 想另起炉灶:
--new(覆盖该 session 记录的会话)。 - 想沿用网页里手动选好模型的某对话:
adopt认领它。
并发 / 多 Agent 隔离(重要)
多个 Agent 交叉共用同一浏览器会冲突:共享状态文件互相覆盖、可能撞进同一会话标签。 解决办法是每个 Agent 用独立 session:
node scripts/chatgpt.cjs ask --session A --new "A 的问题" # Agent A
node scripts/chatgpt.cjs ask --session B --new "B 的问题" # Agent B(独立会话标签 + 独立状态目录)
# 也可用环境变量:export CHATGPT_SESSION=A
- 不同 session → 不同
/c/会话标签 + 不同状态目录。 - 异步监听要带上同一个 session:
watch --session A ...。 - ⚠️ 同一个 session 不要让两个进程同时跑;一个 session 一条串行链。
已处理的边界情况(都是实战踩过的坑)
- 「当前激活标签页」会漂移:等待期间用户切了标签/App 会读错页面。→ 一律按
/c/<id>会话 URL 在所有 context/page 里定位目标标签,绝不用 "active tab"。 - 附件"卡片出现 ≠ 上传完成":上传中发送按钮是禁用的。→ 上传后轮询等发送按钮真正可用
(
!disabled && aria-disabled!=='true')再点,附件默认给到 120s。这是关键修复。 - 模型/强度菜单是 pointer-only 的 Radix 菜单:合成
.click()打不开。→ 用 Playwright 的click({force:true})(真实指针事件);且空白新页面顶部没有模型切换器,需先聚焦组合框、 等工具栏 hydrate 出现再点。 - 推理/Pro 模型会长时间思考:仍是生成中、正文很短。→ 用足够长 timeout(同步默认 15min / 监听 30min→可调,watch 默认 2h),耐心轮询。
- 完成判据:
无 stop 按钮且助手条数 > 发问前 PREV_N且最新回合已带评价按钮 (good-response,g>=n)且正文长度连续两次稳定。good-response 按钮只在真正生成完才出现, 能避免把中途停顿误判为完成。 - 追问别抓成旧答案:发问前记下
PREV_N,只认条数 > PREV_N的新回合。 - 会话标签被关:监听/追问时若
/c/<id>标签不在了,自动新开标签导航回该会话 URL。 - 未登录 / 页面没加载出输入框:等
#prompt-textarea出现,超时明确报错。 - 连不上 CDP:明确提示用
--remote-debugging-port启动 Chrome(见前置条件)。
Playwright 通过 CDP 传值天然处理 Unicode/引号/换行,无需再走 base64。
DOM 依赖(ChatGPT 前端若改版,改这里)
chatgpt.cjs 里的选择器:输入框 #prompt-textarea、发送 [data-testid="send-button"]、
停止 [data-testid="stop-button"]、助手消息 [data-message-author-role="assistant"]、
完成信号 [data-testid="good-response-turn-action-button"]、附件卡片 button[aria-label*="移除文件"]、
文件输入 input[type=file]、强度/模型下拉 button[aria-haspopup="menu"] + [role="menuitemradio"]。
已知限制
- 抓的是
innerText:代码块、表格、KaTeX 公式会被压平成纯文本(语义在、排版丢)。 - 模型家族切换是 best-effort(子菜单文案区域相关);思考强度切换已实测稳定。
- 仅 macOS + Chrome,且需以调试端口启动 Chrome。
兜底:纯 AppleScript 文字版(不需调试端口)
scripts/legacy-applescript/ 是最初的实现,用 AppleScript 让 Chrome 执行 JS,无需用调试端口
重启 Chrome,但不支持附件、不支持选模型,只能收发文字。需在 Chrome 开启
「视图→开发者→允许 Apple 事件中的 JavaScript」。用法见该目录内脚本头部注释。
文件结构
scripts/
chatgpt.cjs CDP 核心 CLI:ask/send/watch/adopt/model/shot(主用)
launch_chrome.sh 带调试端口 + 你的 profile 启动 Chrome
chatgpt_ask.sh 瘦包装 → chatgpt.cjs ask(--send-only → send)
chatgpt_watch.sh 瘦包装 → chatgpt.cjs watch
chatgpt_shot.sh 瘦包装 → chatgpt.cjs shot
legacy-applescript/ 纯 AppleScript 文字版兜底(不需调试端口,无附件/模型)
package.json 声明 playwright 依赖