豆包网页版逆向 API 网关 — BrowserOnly 架构
基于 Playwright + Chromium,字节 JS 拦截器自动注入 a_bogus/msToken
┌──────────────┐ ┌──────────────────────────────────────────┐
│ 客户端 │ │ doubao2API (FastAPI, 端口 7861) │
│ (curl/SDK) │────→│ │
│ │←────│ /v1/chat/completions (OpenAI 兼容) │
└──────────────┘ │ │
│ ┌─ DoubaoClient ──────────────────────┐ │
│ │ AccountPool → BrowserEngine │ │
│ │ ↓ ↓ │ │
│ │ SessionStore Playwright+Chromium │ │
│ │ ↓ ↓ │ │
│ │ build_payload JS fetch(浏览器内) │ │
│ │ ↓ │ │
│ │ 字节JS自动注入 │ │
│ │ a_bogus/msToken │ │
│ │ ↓ │ │
│ │ doubao.com SSE 流 │ │
│ │ ↓ │ │
│ │ DoubaoSSEParser │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────┘
核心原理:豆包前端的 window.fetch 已被字节 JS 劫持,在浏览器内调用 fetch() 时,a_bogus 和 msToken 会被自动注入到 URL query 参数中。因此只需在 Playwright 打开的浏览器页面中执行 fetch,无需自己实现反爬签名。
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| Python | 3.10+ | 推荐 3.12 |
| Playwright | latest | 自动安装 Chromium |
| 豆包账号 | - | 需要一个已登录的 sessionid |
cd doubao2API
python start.pystart.py 会自动完成:
- 安装 Python 依赖 (
fastapi,uvicorn,pydantic-settings,playwright) - 下载 Playwright Chromium 浏览器(首次运行)
- 启动后端服务在
http://127.0.0.1:7861
cd doubao2API
# 1. 安装依赖
pip install -r backend/requirements.txt
# 2. 安装 Playwright Chromium(首次)
python -m playwright install chromium
# 3. 启动服务
PYTHONPATH=. python -m uvicorn backend.main:app --host 0.0.0.0 --port 7861==================================================
doubao2API BrowserOnly Gateway 已上线
后端 API: http://127.0.0.1:7861
API 文档: http://127.0.0.1:7861/docs
==================================================
⚠️ 首次启动需要等待 Chromium 下载和浏览器页面初始化,约 30-60 秒。
doubao2API 使用豆包的 Cookie sessionid 进行认证,不是邮箱/密码/Token。
- 打开浏览器访问 https://www.doubao.com 并登录
- 按
F12打开开发者工具 - 切换到 Application (应用程序) 标签页
- 左侧找到 Cookies →
https://www.doubao.com - 在 Cookie 列表中找到
sessionid,复制其 Value
示例 sessionid: 64b2be47...
64b2be47...
⚠️ sessionid 是敏感信息,请勿泄露给他人。Cookie 有效期约 30 天(见sid_guard中的过期时间)。
所有管理接口需要 Authorization: Bearer <ADMIN_KEY> 认证,默认 ADMIN_KEY 为 admin。
curl -X POST http://127.0.0.1:7861/api/admin/accounts/add \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"sessionid": "64b2be47...", "name": "doubao_rx"}'响应:
{"status": "ok", "name": "我的豆包账号"}curl http://127.0.0.1:7861/api/admin/accounts \
-H "Authorization: Bearer admin"响应:
{
"accounts": [
{
"sessionid": "64b2be47...",
"name": "我的豆包账号",
"status": "valid",
"status_text": "正常",
"inflight": 0,
"consecutive_failures": 0,
"last_error": ""
}
]
}curl -X POST http://127.0.0.1:7861/api/admin/accounts/remove \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"sessionid": "要删除的sessionid"}'如果设置了 API Key,则只有持有有效 Key 的请求才能调用 API:
curl -X POST http://127.0.0.1:7861/api/admin/apikeys/add \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"key": "sk-doubao-mykey123"}'curl http://127.0.0.1:7861/api/admin/status \
-H "Authorization: Bearer admin"curl -X POST http://127.0.0.1:7861/api/admin/max_inflight \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"value": 2}'doubao2API 提供与 OpenAI 完全兼容的 /v1/chat/completions 接口。
curl http://127.0.0.1:7861/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer admin" \
-d '{
"model": "doubao",
"messages": [{"role": "user", "content": "你好,介绍一下你自己"}],
"stream": false
}'响应(与 OpenAI 格式一致):
{
"id": "chatcmpl-a1b2c3d4e5f6",
"object": "chat.completion",
"created": 1775994514,
"model": "doubao",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "你好!我是豆包..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 150,
"total_tokens": 159
}
}curl http://127.0.0.1:7861/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer admin" \
-d '{
"model": "doubao",
"messages": [{"role": "user", "content": "写一首关于春天的诗"}],
"stream": true
}'响应(SSE 格式):
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":...,"model":"doubao","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":...,"model":"doubao","choices":[{"index":0,"delta":{"content":"春"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":...,"model":"doubao","choices":[{"index":0,"delta":{"content":"风"},"finish_reason":null}]}
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":...,"model":"doubao","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
当用户消息包含画图/生成图片意图时,自动路由到豆包文生图 Agent:
curl http://127.0.0.1:7861/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer admin" \
-d '{
"model": "doubao",
"messages": [{"role": "user", "content": "画一只可爱的猫咪"}],
"stream": false
}'响应中 content 包含 Markdown 图片链接,images 字段包含原始 URL 列表:
{
"choices": [{
"message": {
"role": "assistant",
"content": "\n"
}
}],
"images": ["https://lf-ai-img.bytetos.com/...", "https://..."]
}doubao2API 支持多种模型名,均映射到豆包的 bot_id:
| 传入 model | 实际 bot_id | 说明 |
|---|---|---|
doubao |
7338286299411103781 |
默认模型 |
doubao-pro |
同上 | 别名 |
gpt-4o |
同上 | OpenAI 兼容 |
gpt-4o-mini |
同上 | OpenAI 兼容 |
claude-3-5-sonnet |
同上 | Anthropic 兼容 |
deepseek-chat |
同上 | DeepSeek 兼容 |
7338286299411103781 |
直接使用 | 纯数字 bot_id |
目前所有模型名都映射到默认 bot_id。不同模型的 bot_id 可通过 F12 抓包获取后更新
BOT_MAP。
doubao2API 的多轮对话由豆包服务端管理——客户端不需要发送历史消息。每次请求只需传当前消息,服务端根据 conversation_id 自动加载上下文。
但如果你从 OpenAI SDK 发送带历史消息的请求,doubao2API 也兼容——它只提取最后一条 user 消息发送给豆包。
from openai import OpenAI
client = OpenAI(
api_key="admin", # ADMIN_KEY 或你添加的 API Key
base_url="http://127.0.0.1:7861/v1"
)
# 非流式
response = client.chat.completions.create(
model="doubao",
messages=[{"role": "user", "content": "你好"}],
stream=False
)
print(response.choices[0].message.content)
# 流式
stream = client.chat.completions.create(
model="doubao",
messages=[{"role": "user", "content": "讲个笑话"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)API 支持三种鉴权方式(任选其一):
# 1. Authorization Header
-H "Authorization: Bearer admin"
# 2. X-API-Key Header
-H "x-api-key: admin"
# 3. Query Parameter
http://127.0.0.1:7861/v1/chat/completions?key=admin如果未添加任何 API Key,则所有请求均可访问(仅验证 ADMIN_KEY)。
cd doubao2API
# 构建镜像(首次较慢,需下载 Chromium)
docker compose up -d --build
# 查看日志
docker compose logs -fcurl -X POST http://YOUR_SERVER:7861/api/admin/accounts/add \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"sessionid": "你的sessionid", "name": "production-account"}'docker-compose.yml 已配置 ./data 目录挂载,账号和用户数据会持久保存。
创建 .env 文件:
PORT=7861
ADMIN_KEY=your-secure-admin-key
BROWSER_POOL_SIZE=3
MAX_INFLIGHT=1
DEFAULT_BOT_ID=7338286299411103781所有配置可通过环境变量或 .env 文件设置:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
PORT |
7861 |
API 网关监听端口 |
ADMIN_KEY |
admin |
管理后台鉴权密钥 |
REGISTER_SECRET |
"" |
注册密钥(暂未使用) |
ENGINE_MODE |
browser |
引擎模式(仅 browser) |
BROWSER_POOL_SIZE |
2 |
浏览器页面池大小 |
MAX_INFLIGHT |
1 |
每账号最大并发请求数 |
BASE_URL |
https://www.doubao.com |
豆包基础 URL |
DEFAULT_BOT_ID |
7338286299411103781 |
默认模型 bot_id |
DEFAULT_FP |
doubao2api_default_fp |
设备指纹 |
ACCOUNT_MIN_INTERVAL_MS |
1200 |
同账号最小请求间隔 (ms) |
REQUEST_JITTER_MIN_MS |
120 |
请求抖动延迟下限 (ms) |
REQUEST_JITTER_MAX_MS |
360 |
请求抖动延迟上限 (ms) |
RATE_LIMIT_BASE_COOLDOWN |
600 |
限流基础冷却时间 (s) |
RATE_LIMIT_MAX_COOLDOWN |
3600 |
限流最大冷却时间 (s) |
ACCOUNTS_FILE |
data/accounts.json |
账号数据文件路径 |
USERS_FILE |
data/users.json |
用户数据文件路径 |
SESSIONS_FILE |
data/sessions.json |
会话数据文件路径 |
doubao2API/
├── backend/
│ ├── __init__.py
│ ├── main.py # FastAPI 入口,lifespan 管理引擎+账号池+客户端
│ ├── requirements.txt # fastapi, uvicorn, pydantic-settings, playwright
│ ├── api/
│ │ ├── __init__.py
│ │ ├── v1_chat.py # /v1/chat/completions OpenAI兼容接口(流式+非流式+文生图)
│ │ ├── admin.py # /api/admin 账号管理+API Key管理+系统状态
│ │ └── probes.py # /healthz + /readyz 健康检查
│ ├── core/
│ │ ├── __init__.py
│ │ ├── config.py # Settings + BOT_MAP + resolve_bot_id() + API_KEYS
│ │ ├── database.py # AsyncJsonDB
│ │ ├── browser_engine.py # Playwright+Chromium + JS_STREAM_DOUBAO + fetch_chat()
│ │ └── account_pool.py # Account(sessionid) + AccountPool
│ └── services/
│ ├── __init__.py
│ ├── doubao_client.py # DoubaoClient: 串联引擎+账号池+SSE解析,支持chat/chat_stream/with_retry
│ ├── sse_parser.py # DoubaoSSEParser: 7种SSE事件解析→StreamResult
│ └── session_store.py # SessionStore: 会话状态+build_full_payload()
├── data/
│ ├── accounts.json
│ ├── users.json
│ ├── sessions.json
│ └── api_keys.json
├── start.py # 一键启动脚本
├── Dockerfile # Python 3.12 + Playwright Chromium
├── docker-compose.yml # 端口7861
└── .env.example
用户请求 → v1_chat.py → DoubaoClient.chat_stream()
├─ AccountPool.acquire() → 获取可用账号
├─ SessionStore.build_full_payload() → 构建豆包请求体
├─ BrowserEngine.fetch_chat() → 浏览器内 fetch
│ └─ JS_STREAM_DOUBAO → 字节JS自动注入签名 → SSE 流
└─ DoubaoSSEParser._stream_sse() → 逐事件解析
└─ yield delta/image/error/done → OpenAI 格式 SSE
A: 设置镜像源后重试:
set PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright
python -m playwright install chromiumA: 需要先通过管理后台添加豆包 sessionid:
curl -X POST http://127.0.0.1:7861/api/admin/accounts/add \
-H "Authorization: Bearer admin" \
-H "Content-Type: application/json" \
-d '{"sessionid": "你的sessionid"}'A: 豆包 sessionid 有效期约 30 天。过期后需要重新从浏览器获取新的 sessionid,然后:
- 通过
/api/admin/accounts/remove删除旧账号 - 通过
/api/admin/accounts/add添加新 sessionid
A: doubao2API 使用浏览器模式,每次请求需要:
- 注入 Cookie → 刷新页面 → 等待 JS 加载
- 请求间有抖动延迟(120-360ms,防风控)
首次请求可能需要 5-10 秒,后续请求通常 2-5 秒。可通过以下方式优化:
- 增大
BROWSER_POOL_SIZE(更多浏览器页面并行) - 减小
ACCOUNT_MIN_INTERVAL_MS(缩短请求间隔,但有风控风险)
A: 在豆包网页版切换到目标模型,然后 F12 抓包查看 /chat/completion 请求体中的 client_meta.bot_id 字段。获取后在 config.py 的 BOT_MAP 中添加映射。
A: 支持。添加多个 sessionid 后,AccountPool 会自动轮询分配,并有以下策略:
- 账号间轮询(优先选 inflight 最少的)
- 请求间隔抖动(防风控)
- 限流自动冷却(指数退避)
- 失效账号自动标记跳过
A: 只需要 sessionid。doubao2API 会自动同时注入 sessionid 和 sessionid_ss(豆包双重验证)。
A: 支持。通过 /api/admin/apikeys/add 添加 API Key 后,请求必须携带有效 Key。支持三种方式:
Authorization: Bearer <key>x-api-key: <key>- URL query
?key=<key>
| 特性 | qwen2API | doubao2API |
|---|---|---|
| 端口 | 7860 | 7861 |
| 引擎 | Camoufox (Firefox) | Playwright (Chromium) |
| 认证 | JWT Bearer Token | Cookie sessionid |
| 模型标识 | model name | bot_id (数字) |
| 反爬方式 | 无 a_bogus | a_bogus (字节JS自动注入) |
| 消息格式 | 纯文本 content | content_block 嵌套结构 |
| 新会话 | 两步创建 | 一步创建+发消息 |