# Chatgpt Browser Ask

> 通过 CDP(Chrome DevTools Protocol)+ Playwright 遥控本机已登录的 Chrome，向 ChatGPT 网页版自动提问并抓取回答，支持上传附件、选择模型/思考强度、多轮保持在同一会话、以及"发完就走、后台监听拿结果"的异步模式。当用户想用浏览器里已登录的 ChatGPT/GPT 账号自动提问(可带附件)、指定模型、拿结果、保持同一对话上下文，或让某个模型(如 GPT-5.5 Pro)在后台跑长推理时使用。仅限 macOS + Google Chrome。

- Skill: `juneqqq/chatgpt-browser-ask` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add juneqqq/chatgpt-browser-ask`
- Raw SKILL.md: https://api.skillmd.com/api/skills/juneqqq/chatgpt-browser-ask/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: juneqqq (https://skillmd.com/u/juneqqq)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/juneqqq/chatgpt-browser-ask

---


# chatgpt-browser-ask

用 **CDP(Chrome DevTools Protocol)+ Playwright** 遥控**本机正在运行、且已登录**的 Google Chrome，在 ChatGPT 标签页里发问、上传附件、切换模型/思考强度、等生成、抓回答。

**它不发任何 HTTP、不碰 token** —— 用的就是用户本人的登录态，等价于"帮你在自己浏览器里点鼠标、拖文件、读屏幕"。

> 核心是 `scripts/chatgpt.cjs`(Node CLI)。仓库里另有 `scripts/legacy-applescript/` 是**纯 AppleScript 文字版兜底**(不需调试端口，但**不支持附件与选模型**)——见文末。

## 前置条件（务必先确认）
1. macOS + Google Chrome + Node ≥ 18。
2. 安装 Playwright：在 skill 目录 `npm i`（或全局 `npm i -g playwright`）。
3. **Chrome 必须以调试端口启动，并带上你平时的登录态**：
   ```bash
   # 先完全退出 Chrome(Cmd+Q)，再运行：
   scripts/launch_chrome.sh          # 默认端口 9222，复用你日常 profile(含登录态)
   ```
   本质是 `--remote-debugging-port=9222 --user-data-dir="<你平时的 Chrome profile>"`。
   启动后确认已登录 https://chatgpt.com 。
4. 脚本默认连 `http://127.0.0.1:9222`，可用 `--cdp URL` 或环境变量 `CHATGPT_CDP` 改。

## 快速用法

```bash
# 同步：问一个问题，等它答完，答案打到 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**：

```bash
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 一条串行链。

## 已处理的边界情况（都是实战踩过的坑）
1. **「当前激活标签页」会漂移**：等待期间用户切了标签/App 会读错页面。→ 一律按 `/c/<id>`
   会话 URL 在所有 context/page 里定位目标标签，绝不用 "active tab"。
2. **附件"卡片出现 ≠ 上传完成"**：上传中发送按钮是**禁用**的。→ 上传后**轮询等发送按钮真正可用**
   (`!disabled && aria-disabled!=='true'`)再点，附件默认给到 120s。这是关键修复。
3. **模型/强度菜单是 pointer-only 的 Radix 菜单**：合成 `.click()` 打不开。→ 用 Playwright 的
   `click({force:true})`(真实指针事件)；且**空白新页面顶部没有模型切换器**，需先聚焦组合框、
   等工具栏 hydrate 出现再点。
4. **推理/Pro 模型会长时间思考**：仍是生成中、正文很短。→ 用足够长 timeout(同步默认 15min /
   监听 30min→可调，watch 默认 2h)，耐心轮询。
5. **完成判据**：`无 stop 按钮` **且** `助手条数 > 发问前 PREV_N` **且** `最新回合已带评价按钮
   (good-response，g>=n)` **且** `正文长度连续两次稳定`。good-response 按钮只在真正生成完才出现，
   能避免把中途停顿误判为完成。
6. **追问别抓成旧答案**：发问前记下 `PREV_N`，只认 `条数 > PREV_N` 的新回合。
7. **会话标签被关**：监听/追问时若 `/c/<id>` 标签不在了，自动新开标签导航回该会话 URL。
8. **未登录 / 页面没加载出输入框**：等 `#prompt-textarea` 出现，超时明确报错。
9. **连不上 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 依赖
```

