Skip to main content

一、背景

1.1、要解决的问题

在把 BlogLoom 的本地 Markdown 分发到 CSDN 之后,我们紧接着要打通第二个渠道:微信公众号。 公众号是内容分发绕不开的阵地,但它和 CSDN 有着本质不同的编辑器形态:
  • CSDN 的编辑器原生识别 Markdown,直接粘贴 Markdown 源码即可排版;
  • 公众号的编辑器是 ProseMirror 富文本,不识别 Markdown 源码——直接粘贴 Markdown 只会得到一堆带 #、*、反引号的纯文本。
除此之外,公众号还有一套极其繁琐的发布配置:首图要「从正文选择」、声明原创要勾「我已阅读」、群发要管理员扫码……每一个环节都是真人才能稳定点对的操作。

1.2、为什么单独成篇

上一篇(CSDN)讲的是「编辑器原生吃 Markdown、靠弹窗逐项配置」的模式;公众号这篇讲的是完全不同的三个难点:

1.3、设计目标


二、技术栈

公众号渠道同样基于「Playwright 主操作 + CDP 底层增强」的通用骨架,但在渠道层多了一个关键文件:
核心差异集中在 format.js:它解决了公众号「不认 Markdown」的根本矛盾。

三、核心功能

3.1、动作矩阵

3.2、登录态检测(checkLogin)

详细原理与代码见 4.2。

3.3、扫码登录(login)

3.4、正文样式转换(format.js)

详细原理与代码见 4.1。

3.5、进入编辑器(enterEditor)

3.6、标题 / 作者写入(setTitle / setAuthor)

3.7、正文写入(setContent)

3.8、发布配置项

3.9、发表(publish)

3.10、存草稿 / 删除

3.11、渠道专属参数透传(augmentPayload)


四、核心功能设计思路与原理

这一章逐段拆解公众号渠道最核心的机制。

4.1、正文样式转换:Markdown → 公众号富文本(重点)

问题:公众号编辑器不识别 Markdown,直接粘贴只会得到纯文本,排版全丢。 方案:参照已跑通的 auto-sync-blog,用在线排版工具 md.doocs.org 先把 Markdown 渲染成带内联样式的 HTML,复制该富文本,再粘贴回公众号编辑器。
关键点:
  • 同上下文新开页:转换页与主编辑页共享 Cookie/登录态,且转换完 close(),不污染主流程;
  • 走剪贴板而非逐字输入:长文逐字输入有性能问题,剪贴板粘贴一次到位;
  • 复制前先把「图注」设为「不显示」:md.doocs 默认会在图片下方渲染图注文字,公众号正文不需要,需先在右侧样式面板选中「不显示」。
图注隐藏的实现细节:样式面板默认收起,看不到「图注」区块时先点右上角「样式」展开;用 XPath 先锁定「图注/Caption」标题,再取其父区块内的「不显示/None」按钮,避免误点其他区块的同名按钮;选中态用 border-primary class 校验:
问题:公众号登录凭证复杂,怎么避免「假阳性」? 原理:双保险判定——
  1. 进入后台首页,出现账号名 .weui-desktop_name → 已登录;
  2. 否则看真正的会话 Cookie(slave_sid / slave_user / data_ticket)——它们仅在登录后下发;
  3. 都没有则视为未登录。
重点:不能用 wxuin / ua_id 判定——未登录态也会下发,会假阳性。登录凭证白名单只放 LOGIN_COOKIE_NAMES = ['slave_sid', 'slave_user', 'data_ticket']。

4.3、进入编辑器:内容管理 → 草稿箱 → 新的创作

问题:公众号编辑器藏得深,且「文章」可能新开标签页打开。 原理:路由链路——后台首页 → 内容管理 → 草稿箱 → 「新的创作」→ 「文章」。点「文章」时用 context.waitForEvent('page') 监听新标签页,若新开则切换到新页面继续操作:
同时判断是否被重定向到登录页(/loginpage/),是则抛 AUTH_REQUIRED。

4.4、标题 / 作者写入

标题编辑器是 contenteditable/ProseMirror,fill 不一定可靠,用键盘输入最稳:全选清空 → keyboard.type 逐字输入 → 回读校验。 作者栏(#js_author_area #author)是必须先填的——不填作者,后续原创弹窗的「我已阅读」就无法勾选。同样全选替换 + 回读校验兜底。

4.5、正文写入:样式粘贴 + 回退兜底

重点:微信粘贴外部富文本后会弹「内容结构检测」确认框,必须点「继续插入」,否则内容不会真正写进正文。同时保留原始 writeContent 兜底,样式转换失败时仍能发布。

4.6、首图:从正文选择 + 上传校验

问题:公众号封面面板按正文顺序增量渲染,图片没传完时第一张并不是正文首图。 原理:setCover(page, firstBox, expectedImages)——传正文图片总数,轮询面板 item 数量直到达到期望值(或连续若干秒不再增长),再取第一张:
然后「下一步」→「完成」,最后校验封面是否真上传成功(预览区出现 background-image 且非空 url);失败重试一次:

4.7、原创:声明类型 + 勾协议(多重试)

问题:微信的自定义组件首次打开常不响应,且「我已阅读」勾选失败会导致声明不生效。 原理:chooseOrigin 采用多轮重试——最多 4 轮,每轮打开弹窗 → 点「文字原创」→ 反复勾「我已阅读」直到 isChecked() 为真 → 确定 → 校验弹窗是否已关闭;失败则关弹窗下一轮再试:
勾选对 <label> 触发 DOM click,重试直到真勾上。

4.8、发表:群发弹窗 + 二次确认 + 扫码

问题:公众号发表可能触发群发(需管理员扫码),终态如何界定? 原理:publish 流程——点底部「群发」→ 弹窗 1(非群发则关闭群发开关)→ 确认 → 弹窗 2(二次确认「继续发表」)→ 等待成功 toast。群发需要扫码,给出一段确认窗口,返回:
重点:公众号发表后可能进入扫码/审核,所以终态是 SUBMITTED 而不是 PUBLISHED(通过 channel.successStatuses = ['SUBMITTED'] 声明),避免机器误判失败。

4.9、渠道专属参数透传

公众号的 --author / --wechat-name / --collection / --group-send 等参数,核心 CLI 不感知,统一 --key value 原样透传给渠道。渠道用 augmentPayload 组装,优先级:CLI 参数 > 元数据 extra > conf 默认:

五、实战:发布与链路自测

5.1、存草稿(推荐首测)

草稿场景也会先配置封面/摘要/原创/合集/创作来源(configureOnDraft: true),再保存草稿。

5.2、正式发表

默认有头模式可见全过程;未登录自动拉起登录;发表后若需群发则在浏览器完成管理员扫码。

5.3、链路自测:gzh test publish

公众号自测用草稿模式,避免自动群发/审核:
返回 status=DRAFT_SAVED_AND_DELETED(channel.testMode='draft' 控制)。

六、踩坑与优化(重点复盘)

6.1、坑一:直接粘贴 Markdown 变纯文本

公众号编辑器不识别 Markdown,直接粘贴只得到纯文本,#、*、反引号全暴露。
  • 优化:用 md.doocs 先把 Markdown 渲染成带样式的 HTML 再粘贴。

6.2、坑二:粘贴后内容没进去(内容结构检测)

微信粘贴外部富文本后弹「内容结构检测」确认框,不点「继续插入」内容不会写入正文。
  • 优化:confirmInsertDialog 循环点「继续插入」,并回读正文长度,为 0 则回退原始写入策略。

6.3、坑三:登录「假阳性」

未登录态也会下发 wxuin / ua_id,用它们判定会把「未登录」误判为「已登录」。
  • 优化:登录凭证白名单只放 slave_sid / slave_user / data_ticket。

6.4、坑四:首图选错/选空

封面面板按正文顺序增量渲染,图片没传完时第一张不是正文首图。
  • 优化:传图片总数,轮询面板 item 数量直到达到期望值再取第一张,并校验上传成功(失败重试一次)。

6.5、坑五:原创声明不生效

微信自定义组件首次打开不响应,「我已阅读」勾选失败导致声明不生效。
  • 优化:多轮重试 + 对 <label> 触发 DOM click,反复校验 isChecked() 直到真勾上。

6.6、坑六:发表终态判断

发表后可能进入扫码/审核,返回 PUBLISHED 会导致机器误判失败。
  • 优化:终态定为 SUBMITTED(successStatuses: ['SUBMITTED']),发表后给出扫码确认窗口。
重点:公众号的坑集中在「内容不进去」和「状态假成功」两类,应对手段是「回读校验」+「重试」+「兜底回退」。

七、验证测试

7.1、mock 单测

用 test/helpers/mock-page.js 模拟 Playwright,无需真实浏览器即可验证:
覆盖 gzh 的 checkLogin / enterEditor / setTitle / setAuthor / setContent / preparePublish / publish / saveDraft / deleteBlog / augmentPayload 等每一个脚本工具。

7.2、真实链路自测

gzh test publish 走「发布草稿 → 删除」,验证完整链路且不触发群发、不留残留。

八、总结

公众号渠道的引入,验证了「按渠道分层」这套骨架的可扩展性:复用 Playwright + CDP、登录判定、CLI 契约等通用能力,只在 channels/gzh/ 里新增渠道专属逻辑(format.js 样式转换、augmentPayload、testMode、successStatuses)。 核心收获:
  • 编辑器不认 Markdown 就转 HTML:md.doocs 渲染 + 剪贴板富文本;
  • 内容不进就回退兜底:回读校验 + 原始写入策略;
  • 状态不进就定 SUBMITTED:扫码/审核流程不该被当成失败;
  • 一切关键动作都要回读校验:拒绝「假成功」。
项目地址:https://github.com/changluya/BlogLoom | Skill 目录:https://github.com/changluya/BlogLoom/tree/master/skills/blogloom-publisher-skill

参考资料

[1]. md.doocs.org:Markdown 公众号排版工具 [2]. Playwright 官方文档(Locators、Actions、Page Context) [3]. Chrome DevTools Protocol(Input.insertText / Network.getCookies) [4]. Playwright connectOverCDP:复用已有浏览器登录态
整理者:长路 创建时间:2026.10.6 更新时间:2026.10.6

下一步