From cd65b4ccc91e7b7f4e1e2f3a39dcc76600bddadb Mon Sep 17 00:00:00 2001 From: travel Date: Thu, 25 Jun 2026 11:07:56 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=E4=B8=8D=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20Playwright=20=E7=9A=84=E8=AF=A6=E7=BB=86=E6=8A=80?= =?UTF-8?q?=E6=9C=AF=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 README 中说明 DOM 自动化脆弱性、风控冲突、二次验证、架构复杂度及 HTTP SSO 取舍,便于后续维护与部署决策。 Co-authored-by: Cursor --- README.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1ae558f..5213a55 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,108 @@ > 若服务器 IP 被抖音风控(错误码 4031),请配置**住宅代理 API**。 +## 为什么不使用 Playwright + +本项目早期版本基于 **Playwright + Headless Chromium** 实现扫码登录,但在实际使用与维护中暴露出大量问题。经过多轮修复后,仍无法稳定支撑「一键提取 Cookie」这一核心目标,因此彻底移除 Playwright,改为直接调用抖音 Passport / SSO 的 HTTP 接口。 + +### 1. 登录流程依赖脆弱的 DOM 自动化 + +Playwright 方案需要模拟用户在网页上的每一步操作: + +- 打开 `douyin.com` 并点击「登录」 +- 切换到「扫码登录」标签 +- 从页面 `` / `` 中提取二维码 +- 扫码后识别「身份验证」弹窗,再自动点击「短信验证码」「发送验证码」等按钮 +- 跨 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 接口,轻量快速 | **当前采用** | -| Playwright | 模拟浏览器,重、易碎 | 已移除 | -| 开放平台 OAuth | 需注册应用,返回 access_token 非网页 Cookie | 不适用 | +| HTTP SSO | 直接调用 passport / SSO 接口,轻量、可部署 | **当前采用** | +| Playwright | 模拟真实浏览器,重、易受 UI 改版影响 | **已移除**(见上文) | +| 开放平台 OAuth | 需注册应用,返回 `access_token` 而非网页 Cookie | 不适用 | +| 读取本机浏览器 Cookie | 需用户事先在 Chrome 登录,非远程一键扫码 | 未采用 | ## 环境要求