在 README 中说明 DOM 自动化脆弱性、风控冲突、二次验证、架构复杂度及 HTTP SSO 取舍,便于后续维护与部署决策。 Co-authored-by: Cursor <cursoragent@cursor.com>
抖音 Cookie 一键提取
扫码登录抖音后,自动导出 JSON 格式 Cookie。
原理
采用 HTTP SSO 接口(无需 Playwright / 浏览器):
- 注册
ttwid设备标识 - 调用
passport/web/get_qrcode或sso.douyin.com/get_qrcode获取二维码 - 轮询
check_qrconnect检测扫码状态 - 确认后跟随
redirect_url完成会话,导出 Cookie
若服务器 IP 被抖音风控(错误码 4031),请配置住宅代理 API。
为什么不使用 Playwright
本项目早期版本基于 Playwright + Headless Chromium 实现扫码登录,但在实际使用与维护中暴露出大量问题。经过多轮修复后,仍无法稳定支撑「一键提取 Cookie」这一核心目标,因此彻底移除 Playwright,改为直接调用抖音 Passport / SSO 的 HTTP 接口。
1. 登录流程依赖脆弱的 DOM 自动化
Playwright 方案需要模拟用户在网页上的每一步操作:
- 打开
douyin.com并点击「登录」 - 切换到「扫码登录」标签
- 从页面
<img>/<canvas>中提取二维码 - 扫码后识别「身份验证」弹窗,再自动点击「短信验证码」「发送验证码」等按钮
- 跨 iframe、Shadow DOM 查找输入框并填入验证码
抖音前端 UI 频繁改版,按钮文案、CSS 类名、弹窗结构随时可能变化。任何一次改版都会导致:
- 找不到登录入口或二维码
- 误判登录状态(例如把「等待确认」当成「需要验证」)
- 自动填验证码失败,用户无法完成二次验证
这类问题无法通过局部修补根治,因为本质是在用浏览器自动化对抗一个持续变化的前端。
2. Headless 模式与风控冲突
无头浏览器(headless: true)极易触发抖音反爬与风控策略:
navigator.webdriver等特征可被检测- 滑块、图形验证码在 headless 下几乎无法完成
- 扫码后常出现二次验证(短信 / 密码 / 滑块),自动化脚本无法可靠处理
改为「可见浏览器 + 用户手动验证」虽能缓解,但又带来新问题:必须在服务器上弹出 GUI 窗口(Linux 无桌面环境不可用),且仍依赖 DOM 点击逻辑,并没有降低维护成本。
3. 二次验证是最大不稳定因素
真实场景中,用户手机确认登录后,网页端仍可能要求:
- 接收短信验证码
- 验证登录密码
- 完成滑块验证
旧方案试图用 Playwright 自动点击、自动填码、自动提交,实际效果很差:
- 验证码输入框分布在不同 iframe 中,选择器经常失效
- 轮询逻辑与用户手动操作互相覆盖(例如自动点击「接收短信」与用户选择密码验证冲突)
- 提交按钮文案不统一(「确定」「提交」「验证」等),跨 frame 点击失败率高
Cookie 提取工具不应承担「代替用户在网页里完成风控验证」的职责;这类步骤更适合由用户在 App 或官方页面自行完成,服务端只负责检测登录结果。
4. 架构复杂、难以维护
Playwright 版本将全部逻辑塞在单文件 app.py(约 1200 行),并引入额外复杂度:
| 问题 | 说明 |
|---|---|
| Flask 与 asyncio 桥接 | 需要自定义 run_async_sync() 和全局 event loop,易出现协程/线程竞态 |
| 浏览器生命周期 | 登录成功即关闭浏览器,调试困难;异常时容易残留僵尸进程 |
| 单全局会话 | LoginSession + 锁,同一时刻仅支持一个扫码任务 |
| 部署依赖重 | 除 Python 外还需 playwright install chromium(数百 MB) |
| 二维码提取不可靠 | 常退化为「整页截图」,用户扫到的并非标准 QR |
模块化拆分后,浏览器相关代码仍是最难测试、最难 Mock 的部分,投入产出比极低。
5. 与项目目标不匹配
本项目的核心目标是:
扫码登录成功后,导出网页端可用的 Cookie JSON
完成这一目标,并不需要渲染完整页面,只需要走通抖音官方的 扫码 SSO 协议:
get_qrcode → 展示二维码 → check_qrconnect 轮询 → redirect_url 换票 → 拿到 Cookie
这是一条稳定的 HTTP 状态机,与页面 DOM 无关。抖音网页版、创作者平台、早期开源项目均采用同一套 sso.douyin.com 接口,协议层比 UI 层可靠得多。
6. HTTP SSO 方案的优势与代价
优势:
- 无需安装 Chromium,部署仅需
pip install -r requirements.txt - 无 GUI / 无头浏览器依赖,适合 Linux 服务器与 Docker
- 逻辑清晰:
backend/sso/qr_login.py独立维护,易于单测 - 资源占用低:一个
requests.Session即可,内存占用从数百 MB 降至数 MB - 前端只展示二维码与轮询状态,不再耦合浏览器截图、验证表单等复杂 UI
代价(需知晓):
- 依赖抖音 SSO 接口,若接口参数变更需跟进适配
- 部分机房 IP 会被风控(错误码
4031),需配置住宅代理 API - 若账号在 SSO 层仍要求额外验证,需用户在手机端完成;HTTP 层无法代替网页内操作
综合权衡:HTTP SSO 更轻、更稳、更易部署,更符合「一键提取 Cookie」的产品定位;Playwright 适合需要完整浏览器行为的场景(如自动化发帖、复杂交互),不适合作为 Cookie 提取的主路径。
与其他方案对比
| 方案 | 说明 | 本项目 |
|---|---|---|
| HTTP SSO | 直接调用 passport / SSO 接口,轻量、可部署 | 当前采用 |
| Playwright | 模拟真实浏览器,重、易受 UI 改版影响 | 已移除(见上文) |
| 开放平台 OAuth | 需注册应用,返回 access_token 而非网页 Cookie |
不适用 |
| 读取本机浏览器 Cookie | 需用户事先在 Chrome 登录,非远程一键扫码 | 未采用 |
环境要求
- Python 3.9+
- Node.js 18+(仅构建前端时需要)
安装
pip install -r requirements.txt
cd frontend
npm install
npm run build
运行
py -3 app.py
环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
PORT |
5001 |
服务端口 |
LOGIN_TIMEOUT |
600 |
登录超时(秒) |
QR_POLL_INTERVAL |
2 |
建议前端轮询间隔 |
DOUYIN_AID |
6383 |
抖音 Web 应用 ID |
DOUYIN_SERVICE |
https://www.douyin.com |
SSO service 参数 |
API
| 接口 | 说明 |
|---|---|
POST /api/start_qr |
获取二维码(HTTP SSO) |
GET /api/check_login |
轮询扫码/登录状态 |
POST /api/reset |
重置会话 |
GET /api/debug |
SSO 轮询调试信息 |
POST /api/test_proxy |
测试代理 |
项目结构
app.py
backend/
sso/qr_login.py # HTTP 扫码登录核心
cookies.py # Cookie 检测
routes/ # API + SPA
frontend/ # Vue 3 前端