Video Publish Weixin — 微信视频号自动发布
Overview
在视频号助手网页端自动发布 MP4 视频:上传 → 填短标题/描述/话题 → 点发表 → 校验成功。基于 CloakBrowser(本地反检测浏览器 + 持久化 profile,微信登录态扫码一次即持久化)。已实测可稳定发布(含跳过「声明原创」弹窗的处理)。
⚠️ 登录有效期:实测微信视频号网页端扫码登录态约 4–5 小时 即失效(微信安全机制,并非 cookie 未持久化——CloakBrowser 的 launch_persistent_context 已真落盘 cookie 到 ~/.cloakbrowser-profile)。因此不能依赖一次扫码撑全天,必须:①发布脚本内置「登录失效自动拉扫码页续期」;②看门狗每 5 分钟探活兜底。否则自动发布会因登录过期而暂停。
前置条件(缺一不可)
- CloakBrowser 已安装:
bash pip install cloakbrowser python -m cloakbrowser install # 下载 Chromium 二进制(约 500MB) - 微信已登录视频号助手:首次运行会停在登录页,需用户手机微信扫码 + 确认登录;登录态保存在 profile(默认
~/.cloakbrowser-profile),后续免登。 - 视频文件就绪:MP4,≤2GB,建议 720P+。
使用方法
单次发布(核心入口)
python scripts/publish_video.py \
--video "/path/video.mp4" \
--title "重复的活 6招全自动" \
--desc "视频描述文字..." \
--topics "WorkBuddy AI自动化 效率工具"
参数说明:
- --video(必填)MP4 绝对路径
- --title(必填)短标题,≥6字且 ≤16字(视频号「短标题」字段硬限制 16 字,超限会被静默拒绝发表,URL 不变);不要用中文逗号等特殊字符(平台会警告并影响发布时间;用空格分隔,如「重复的活 6招全自动」)
- --desc(可选)描述,支持换行;可在描述里直接写 #话题
- --topics(可选)空格分隔的话题列表,自动加 # 并拼到描述末尾
- --profile(可选)登录 profile 目录,默认 ~/.cloakbrowser-profile
- --screenshot-dir(可选)截图目录,默认 ./shots
退出码:0=发布成功;1=发布失败;2=需扫码登录(URL 落在 login.html);3=参数错误。
发布成功标志:脚本日志中 "ok": true 且页面 URL 变为 platform/post/list。
批量 / 定时发布(推荐入口:auto_publish_once.py)
> 关键原则:自动化只跑脚本、以退出码为唯一成功标准,严禁 AI 自报成功,杜绝「假成功」。
- 准备一批视频文件夹,每个含
*.mp4+ 可选 sidecar(content.json/标题.txt/文案.txt)。 - 定时场景:在 WorkBuddy 建 automation 任务(rrule 如
FREQ=DAILY;BYHOUR=11,17),到点只执行一条命令(托管 Python 运行端到端脚本):
bash python scripts/auto_publish_once.py \ --source "/path/to/videos" \ --profile "~/.cloakbrowser-profile" \ --headless true - 成功判定(硬校验):脚本打开发布页 → 点发表 → 显式检查 URL 是否变为
platform/post/list;仅当 URL 校验通过才写.published标记。 - 退出码即真理(automation 据此判定,不再采信 AI 叙述):
-0+event=published→ 发布成功(已写标记)
-0+event=no_candidate→ 当日无未发布视频,正常结束
-2+event=need_login→ 登录态失效需手机微信扫码;不写标记、不报成功,通知用户后等下次/人工扫码
-1→ 发布失败(URL 未变),不写标记,等重试 - 去重:
.published标记只在真实发布成功时写入;后续扫描自动跳过,确保每支只发一次。
登录保活(必做,否则自动发布会因登录过期暂停)
微信视频号网页端会话约 4–5 小时 即失效(实测,微信安全机制,非 cookie 未持久化),到期后自动发布会检测到 need_login 并暂停。解决方案:建一个每日 00:01 的保活任务提前探活 + 拉起扫码页,让用户每天扫一次即可覆盖当日 07:00/11:00/17:00 三发。
# 保活脚本:先 headless 探活,已登录直接退出0;未登录则拉起有界面扫码页,扫成功退出0
python scripts/keepalive_login.py
scripts/keepalive_probe.py:纯 headless 探活,退出码0=有效 /1=需登录 /3=环境错(供轻量巡检)。scripts/keepalive_login.py:探活 → 失效则拉界面扫码 → 扫成功退出 0,封装「探活 + 拉扫码」全流程,AI 只需调一条命令。- 发布任务(
auto_publish_once.py)在need_login时也会自动尝试keepalive_login.py兜底拉扫码,再重发。 - 登录失效后绝不假成功、绝不写标记:脚本返回码 2,自动化自动 PAUSED 并通知扫码。
发布看门狗(调度漏触发兜底,必配)
> WorkBuddy automation 偶发漏触发(任务状态 ACTIVE 但 next_run_at 直接跳过窗口、无 run 记录)。单靠定时任务不可靠,必须加独立看门狗兜底。
看门狗脚本 scripts/watchdog_publish.py:每 5 分钟检查今天 7/11/17 三窗口是否各发够对应支数——按窗口独立判定(今天某窗口时刻之后 >=h:00 尚未发布任何一支,且当前已过该窗口,则补发一支),幂等、绝不重复发布。其内部调用 auto_publish_once.py(自带登录失效自动续期)。
两层兜底部署(若环境无法用系统级工具建 Windows 任务计划 schtasks,用以下替代):
1. 常驻后台循环(每 5 分钟):while true; do python scripts/watchdog_publish.py; sleep 300; done
2. 每小时的兜底 automation:每小时跑一次看门狗,会话断了仍持久兜底。
> 若环境允许,建议改用 schtasks 每 5 分钟直接跑 watchdog_publish.py,彻底脱离 WorkBuddy 调度依赖。
批量生成文案 sidecar(gen_sidecars.py)
> 用途:大量视频待发时,先批量给每个未发文件夹生成 content.json 文案模板(基于文件夹名段名自动差异化),彻底避免脚本退回「全平台统一兜底文案」导致后台看起来像重复发。
# 1) 先预览会生成哪些(不写文件,确认无误)
python scripts/gen_sidecars.py --source "/path/to/videos" --dry-run
# 2) 确认后真正写入 content.json
python scripts/gen_sidecars.py --source "/path/to/videos" --apply
规则:
- 只处理「含 .mp4 + 无 .published + 无现有 sidecar + 段名非空」的文件夹;
- 跳过纯日期时间戳目录、系统目录(.workbuddy、shots),绝不覆盖已有 sidecar;
- 生成 content.json:title=AI自动化 · [段名] 实操演示、desc 含段名、topics=[段名, AI自动化, 效率工具];(注意:若该模板因段名过长超 16 字,发布脚本 clean_title 会兜底截断到 16 字;auto_publish_once.build_text 对无 sidecar 视频也会生成紧凑标题并保证 ≤16 字)
- 想定制某支文案:直接编辑其 content.json,或删掉它改用 标题.txt(首行标题 / 次行描述 / 末行 #话题1 #话题2 #话题3);脚本优先用 sidecar 文案。
发布流程(内部实现,勿手动改动核心 selector)
- 打开
https://channels.weixin.qq.com/platform/post/create - 登录检测:URL 含
login→ 自动调keepalive_login.py拉起有界面扫码页续期(阻塞等待手机微信扫码,成功后续发);若超时或续期后仍登录失败 → 返回码 2,自动化 PAUSED 并通知扫码 - 上传:对隐藏
input[type=file]直接set_input_files()(无需文件对话框),轮询等待转码/上传完成(最多 6 分钟,检测页面『上传中/转码中』文字消失)再填表——视频号需转码完成后才能发表,未转完点发表会被静默拦截 - 填描述:
div.input-editor(contenteditable)click + 键盘输入 - 填标题:
input[placeholder='填写短标题有机会获得更多流量'](原生 input)直接 fill - 不勾选「声明原创」:勾选会弹「原创权益」确认弹窗,该弹窗挂在 React Portal,Playwright 跨 frame + evaluate 全 DOM 均无法定位其「我已阅读并同意」checkbox,无法自动化处理;跳过原创仍可正常发布(仅无原创标记/广告分成)
- 发表:force click「发表」最多 5 次、每次间隔 2 秒,直到 URL 变为
platform/post/list
封面规则(cover.jpg)
- 封面来源:视频同目录的
cover.jpg(视频生成时截取最后 2 秒画面作封面帧)。发布脚本自动取该图作为视频号封面,不使用平台默认截图。 - 上传机制:
auto_publish_once.py上传封面后重试 3 次,每次上传完成点「确定/完成/保存」后校验封面编辑弹窗是否真的关闭(=封面已应用);3 次均未确认生效则明确 logcover_upload_fail并跳过封面(视频回退平台默认封面),发布不被阻断。 - 不再静默吞:封面状态(
cover_status=uploaded/failed/missing/skipped)写入最终published事件,自动化汇报与看门狗日志均可见,绝不再被except静默吞掉。 - 自定义封面:想换封面,把自定义图命名为
cover.jpg放视频同目录即可;或用--cover <绝对路径>指定。
常见问题
- 返回码 2(需登录):通知用户浏览器已打开登录页,请手机微信扫码并点「确认登录」,然后重跑。
- 标题含特殊字符:平台警告「标题包含特殊字符,将修改发布时间」——把中文逗号「,」等换成空格。
- 上传后「添加描述」找不到:等上传/转码完成(脚本轮询检测,最多 6 分钟)后再填表;表单在主 frame(不是 iframe),描述区是
div.input-editor而非 input。 - 点「发表」后 URL 不变:可能被弹窗/遮罩挡住 force click,重试多次(脚本内置 5 次);仍失败则截图
after_publish.png排查。
参考资料
references/publish-guide.md— 详细技术实现、selector 表、踩坑记录、登录流程说明