16 KiB
16 KiB
Day 7: 社交媒体发布功能完善
日期: 2026-01-21
目标: 完成社交媒体发布模块 (80% → 100%)
📋 任务概览
| 任务 | 状态 |
|---|---|
| SuperIPAgent 架构分析 | ✅ 完成 |
| 优化技术方案制定 | ✅ 完成 |
| B站上传功能实现 | ⏳ 计划中 |
| 定时发布功能 | ⏳ 计划中 |
| 端到端测试 | ⏳ 待进行 |
🔍 架构优化分析
SuperIPAgent social-auto-upload 优势
通过分析 Temp\SuperIPAgent\social-auto-upload,发现以下更优设计:
| 对比项 | 原方案 | 优化方案 ✅ |
|---|---|---|
| 调度方式 | APScheduler (需额外依赖) | 平台 API 原生定时 |
| B站上传 | Playwright 自动化 (不稳定) | biliup 库 (官方) |
| 架构 | 单文件服务 | 模块化 uploader/ |
| Cookie | 手动维护 | 自动扫码 + 持久化 |
核心优势
- 更简单: 无需 APScheduler,直接传时间给平台
- 更稳定: biliup 库比 Playwright 选择器可靠
- 更易维护: 每个平台独立 uploader 类
📝 技术方案变更
新增依赖
pip install biliup>=0.4.0
pip install playwright-stealth # 可选,反检测
移除依赖
- apscheduler==3.10.4 # 不再需要
文件结构
backend/app/services/
├── publish_service.py # 简化,统一接口
+ ├── uploader/ # 新增: 平台上传器
+ │ ├── base_uploader.py # 基类
+ │ ├── bilibili_uploader.py # B站 (biliup)
+ │ └── douyin_uploader.py # 抖音 (Playwright)
🎯 关键代码模式
统一接口
# publish_service.py
async def publish(video_path, platform, title, tags, publish_time=None):
if platform == "bilibili":
uploader = BilibiliUploader(...)
result = await uploader.main()
return result
B站上传 (biliup 库)
from biliup.plugins.bili_webup import BiliBili
with BiliBili(data) as bili:
bili.login_by_cookies(cookie_data)
video_part = bili.upload_file(video_path)
ret = bili.submit() # 平台处理定时
📅 开发计划
下午 (11:56 - 14:30)
- ✅ 添加
biliup>=0.4.0到requirements.txt - ✅ 创建
uploader/模块结构 - ✅ 实现
base_uploader.py基类 - ✅ 实现
bilibili_uploader.py(biliup 库) - ✅ 实现
douyin_uploader.py(Playwright) - ✅ 实现
xiaohongshu_uploader.py(Playwright) - ✅ 实现
cookie_utils.py(自动 Cookie 生成) - ✅ 简化
publish_service.py(集成所有 uploader) - ✅ 前端添加定时发布时间选择器
🎉 实施成果
后端改动
-
新增文件:
backend/app/services/uploader/__init__.pybackend/app/services/uploader/base_uploader.py(87行)backend/app/services/uploader/bilibili_uploader.py(135行) - biliup 库backend/app/services/uploader/douyin_uploader.py(173行) - Playwrightbackend/app/services/uploader/xiaohongshu_uploader.py(166行) - Playwrightbackend/app/services/uploader/cookie_utils.py(113行) - Cookie 自动生成backend/app/services/uploader/stealth.min.js- 反检测脚本
-
修改文件:
backend/requirements.txt: 添加biliup>=0.4.0backend/app/services/publish_service.py: 集成所有 uploader (170行)
-
核心特性:
- ✅ 自动 Cookie 生成 (Playwright QR 扫码登录)
- ✅ B站: 使用
biliup库 (官方稳定) - ✅ 抖音: Playwright 自动化
- ✅ 小红书: Playwright 自动化
- ✅ 支持定时发布 (所有平台)
- ✅ stealth.js 反检测 (防止被识别为机器人)
- ✅ 模块化架构 (易于扩展)
前端改动
-
修改文件:
frontend/src/app/publish/page.tsx: 添加定时发布 UI
-
新增功能:
- ✅ 立即发布/定时发布切换按钮
- ✅
datetime-local时间选择器 - ✅ 自动传递 ISO 格式时间到后端
- ✅ 一键登录按钮 (自动弹出浏览器扫码)
🚀 部署步骤
1. 安装依赖
cd backend
pip install biliup>=0.4.0
# 或重新安装所有依赖
pip install -r requirements.txt
# 安装 Playwright 浏览器
playwright install chromium
2. 客户登录平台 (极简3步)
操作流程:
-
拖拽书签(仅首次)
- 点击前端"🔐 扫码登录"
- 将页面上的"保存登录"按钮拖到浏览器书签栏
-
扫码登录
- 点击"打开登录页"
- 扫码登录B站/抖音/小红书
-
点击书签
- 登录成功后,点击书签栏的"保存登录"书签
- 自动完成!
客户实际操作: 拖拽1次(首次)+ 扫码1次 + 点击书签1次 = 仅3步!
下次登录: 只需扫码 + 点击书签 = 2步!
3. 重启后端服务
cd backend
uvicorn app.main:app --host 0.0.0.0 --port 8006 --reload
✅ Day 7 完成总结
核心成果
-
QR码自动登录 ⭐⭐⭐⭐⭐
- Playwright headless模式提取二维码
- 前端弹窗显示二维码
- 后端自动监控登录状态
- Cookie自动保存
-
多平台上传器架构
- B站: biliup官方库
- 抖音: Playwright自动化
- 小红书: Playwright自动化
- stealth.js反检测
-
定时发布功能
- 前端datetime-local时间选择
- 平台API原生调度
- 无需APScheduler
-
用户体验优化
- 首页添加发布入口
- 视频生成后直接发布按钮
- 一键扫码登录(仅扫码)
后端 (13个):
backend/requirements.txtbackend/app/main.pybackend/app/services/publish_service.pybackend/app/services/qr_login_service.py(新建)backend/app/services/uploader/__init__.py(新建)backend/app/services/uploader/base_uploader.py(新建)backend/app/services/uploader/bilibili_uploader.py(新建)backend/app/services/uploader/douyin_uploader.py(新建)backend/app/services/uploader/xiaohongshu_uploader.py(新建)backend/app/services/uploader/cookie_utils.py(新建)backend/app/services/uploader/stealth.min.js(新建)backend/app/api/publish.pybackend/app/api/login_helper.py(新建)
前端 (2个):
frontend/src/app/page.tsxfrontend/src/app/publish/page.tsx
📝 TODO (Day 8优化项)
用户体验优化
- 文件名保留: 上传视频后保留原始文件名
- 视频持久化: 刷新页面后保留生成的视频
功能增强
- 抖音/小红书实际测试
- 批量发布功能
- 发布历史记录
📊 测试清单
- Playwright 浏览器安装成功
- B站 Cookie 自动生成测试
- 抖音 Cookie 自动生成测试
- 小红书 Cookie 自动生成测试
- 测试 B站立即发布功能
- 测试抖音立即发布功能
- 测试小红书立即发布功能
- 测试定时发布功能
⚠️ 注意事项
-
B站 Cookie 获取
- 参考
social-auto-upload/examples/get_bilibili_cookie.py - 或手动登录后导出 JSON
- 参考
-
定时发布原理
- 前端收集时间
- 后端传给平台 API
- 平台自行处理调度 (无需 APScheduler)
-
biliup 优势
- 官方 API 支持
- 社区活跃维护
- 比 Playwright 更稳定
🔗 相关文档
🎨 UI 一致性优化 (16:00 - 16:35)
问题:导航栏不一致、页面偏移
- 首页 Logo 无法点击,发布页可点击
- 发布页多余标题"📤 社交媒体发布"
- 首页因滚动条向左偏移 15px
修复:
frontend/src/app/page.tsx- Logo 改为<Link>组件frontend/src/app/publish/page.tsx- 删除页面标题和顶端 paddingfrontend/src/app/globals.css- 隐藏滚动条(保留滚动功能)
状态:✅ 两页面完全对齐
🔍 QR 登录问题诊断 (16:05)
问题:所有平台 QR 登录超时 Page.wait_for_selector: Timeout 10000ms exceeded
原因:
- Playwright headless 模式被检测
- 缺少 stealth.js 反检测
- CSS 选择器可能过时
状态:✅ 已修复
🔧 QR 登录功能修复 (16:35 - 16:45)
实施方案
1. 启用 Stealth 模式
# 避免headless检测
browser = await playwright.chromium.launch(
headless=True,
args=[
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
'--disable-dev-shm-usage'
]
)
2. 配置真实浏览器特征
context = await browser.new_context(
viewport={'width': 1920, 'height': 1080},
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
locale='zh-CN',
timezone_id='Asia/Shanghai'
)
3. 注入 stealth.js 脚本
stealth_path = Path(__file__).parent / 'uploader' / 'stealth.min.js'
if stealth_path.exists():
await page.add_init_script(path=str(stealth_path))
4. 多选择器 Fallback 策略
"bilibili": {
"qr_selectors": [
".qrcode-img img",
"canvas.qrcode-img",
"img[alt*='二维码']",
".login-scan-box img",
"#qrcode-img"
]
}
# Douyin: 4个选择器, Xiaohongshu: 4个选择器
5. 增加等待时间
- 页面加载:3s → 5s +
wait_until='networkidle' - 选择器超时:10s → 30s
6. 调试功能
# 保存调试截图到 backend/debug_screenshots/
if not qr_element:
screenshot_path = debug_dir / f"{platform}_debug.png"
await page.screenshot(path=str(screenshot_path))
修改文件
后端 (1个):
backend/app/services/qr_login_service.py- 全面重构QR登录逻辑
结果
- ✅ 添加反检测措施(stealth模式、真实UA)
- ✅ 多选择器fallback(每平台4-5个)
- ✅ 等待时间优化(5s + 30s)
- ✅ 自动保存调试截图
- 🔄 待服务器测试验证
📋 文档规则优化 (16:42 - 17:10)
问题:Doc_Rules需要优化,避免误删历史内容、规范工具使用、防止任务清单遗漏
优化内容(最终版):
-
智能修改判断标准
- 场景1:错误修正 → 直接替换/删除
- 场景2:方案改进 → 保留+追加(V1/V2)
- 场景3:同一天多次修改 → 合并为最终版本
-
工具使用规范 ⭐
- ✅ 必须使用
replace_file_content - ❌ 禁止命令行工具(避免编码错误)
- ✅ 必须使用
-
task_complete 完整性保障 (新增)
- ✅ 引入 "完整性检查清单" (4大板块逐项检查)
- ✅ 引入记忆口诀:"头尾时间要对齐,任务规划两手抓,里程碑上别落下"
-
结构优化
- 合并冗余章节
- 移除无关项目组件
修改文件:
Docs/Doc_Rules.md- 包含检查清单的最终完善版
⚡ QR 登录性能与显示优化 (17:30)
问题:
- 速度慢: 顺序等待每个选择器 (30s timeout × N),导致加载极慢
- B站显示错乱: Fallback 触发全页截图,而不是二维码区域
优化方案:
-
并行等待 (Performance):
- 使用
wait_for_selector("s1, s2, s3")联合选择器 - Playwright 自动等待任意一个出现 (即时响应,不再单纯 sleep)
- 超时时间从 30s 单次改为 15s 总计
- 使用
-
选择器增强 (Accuracy):
- 由于 B站登录页改版,旧选择器失效
- 新增
div[class*='qrcode'] canvas和div[class*='qrcode'] img
修改文件:
backend/app/services/qr_login_service.py
⚡ QR 登录最终坚固化 (17:45)
问题:
- 并行等待虽然消除了顺序延迟,但 CSS 选择器仍然无法匹配 (Timeout 15000ms)
- 截图显示二维码可见,但 Playwright 认为不可见或未找到(可能涉及动态类名或 DOM 结构变化)
解决方案 (三重保障):
- 策略 1: CSS 联合选择器 (超时缩短为 5s,快速试错)
- 策略 2 (新): 文本锚点定位
- 不不再依赖脆弱的 CSS 类名
- 直接搜索屏幕上的 "扫码登录" 文字
- 智能查找文字附近的
<canvas>或<img>
- 策略 3 (调试): HTML 源码导出
- 如果都失败,除了截图外,自动保存
bilibili_debug.html - 彻底分析页面结构的"核武器"
- 如果都失败,除了截图外,自动保存
修改文件:
backend/app/services/qr_login_service.py(v3 最终版)
⚡ QR 登录终极修复 (17:55)
致命问题:
- 监控闪退: 后端使用
async with async_playwright(),导致函数返回时浏览器自动关闭,后台监控任务 (_monitor_login_status) 操作已关闭的页面报错TargetClosedError。 - 仍有延迟: 之前的策略虽然改进,但串行等待 CSS 超时 (5s) 仍不可避免。
解决方案:
-
生命周期重构 (Backend):
- 移除上下文管理器,改为
self.playwright.start()手动启动 - 浏览器实例持久化到类属性 (
self.browser) - 仅在监控任务完成或超时后,在
finally块中手动清理资源 (_cleanup)
- 移除上下文管理器,改为
-
真·并行策略:
- 使用
asyncio.wait(tasks, return_when=FIRST_COMPLETED) - CSS选择器策略 和 文本定位策略 同时运行
- 谁先找到二维码,直接返回,取消另一个任务
- 延迟降至 0秒 (理论极限)
- 使用
修改文件:
backend/app/services/qr_login_service.py(v4 重构版)
🐛 并行逻辑 Bug 修复 (18:00)
问题现象:
- B站登录正常,但 抖音秒挂 ("所有策略失败")。
- 原因:代码逻辑是
asyncio.wait(FIRST_COMPLETED),如果其中一个策略(如文本策略)不适用该平台,它会立即返回None。 - BUG: 代码收到
None后,错误地以为任务结束,取消了还在运行的另一个策略(CSS策略)。
修复方案:
- 修正并行逻辑:
- 如果一个任务完成了但没找到结果 (Result is None),不取消 其他任务。
- 继续等待剩下的
pending任务,直到找到结果或所有任务都跑完。
- 扩展文本策略:
- 将 抖音 (Douyin) 也加入到文本锚点定位的支持列表中。
- 增加关键词
["扫码登录", "打开抖音", "抖音APP"]。
修改文件:
backend/app/services/qr_login_service.py(v5 修正版)
⚡ 抖音文本策略优化 (18:10)
问题:
- 抖音页面也是动态渲染的,"扫码登录" 文字出现有延迟。
- 之前的
get_by_text(...).count()是瞬间检查,如果页面还没加载完文字,直接返回 0 (失败)。 - 结果:CSS 还在等,文本策略瞬间报空,导致最终还是没找到。
优化方案:
- 智能等待: 对每个关键词 (如 "使用手机抖音扫码") 增加
wait_for(timeout=2000),给页面一点加载时间。 - 扩大搜索圈: 找到文字后,向父级查找 5层 (之前是3层),以适应抖音复杂的 DOM 结构。
- 尺寸过滤: 增加
width > 100判断,防止误匹配到头像或小图标。
修改文件:
backend/app/services/qr_login_service.py(v6 抖音增强版)
状态: ✅ 抖音策略已强化
✅ 验证结果 (18:15)
用户反馈:
- B站:成功获取 Cookie 并显示"已登录"状态。
- 抖音:成功获取 Cookie 并显示"已登录"状态。
- 结论:
- 并行策略 (
asyncio.wait) 有效解决了等待延迟。 - 文本锚点定位 (
get_by_text) 有效解决了动态页面元素查找问题。 - 生命周期重构 (
manual start/close) 解决了后台任务闪退问题。
- 并行策略 (
下一步:
- 进行实际视频发布测试。