当前位置: 首页 > news >正文

Obsidian + Claude Code 搭自动化发布客户端:Playwright × 掘金/知乎/CSDN 的全链路踩坑实录

Obsidian + Claude Code 搭自动化发布客户端:Playwright × 掘金/知乎/CSDN 的全链路踩坑实录

AI工具人PM 的实战笔记:前几篇讲了掘金、知乎各自的自动化踩坑。这三篇合起来——我用 Obsidian + Playwright + Claude Code + Electron,从源码文件到三个平台一键发布,搭了一整套系统。这不是教程,是我的真实踩坑记录。


起因:三个平台的编辑器让我疯掉了

掘金是 CKEditor(直接往 DOM 里注入 HTML),知乎是 Draft.js(基于 React 的富文本编辑器,数据存在 Immutable.js 结构里,DOM 上看不到正文内容),CSDN 又是另一套编辑模式。

每次手动发一篇文章要开三个浏览器窗口,切换七八次——标题复制一次,内容复制三次(格式还不完全一样),标签一个个手选。

如果一天发一篇,一个月就是三十次这样的循环。但真正要命的是:

手动发的时候你不知道失败原因是什么。页面卡了?Cookie 过期了?网络超时了?你只能盯着转圈的那个按钮,不知道问题出在哪。

自动化是出路。但问题在于:怎么确保你的自动化真的跑通了?


架构:Obsidian 写 → Python 发 → Electron 看

┌─────────────────────────────────────────────────┐ │ Obsidian (Markdown 源文件) │ │ └── 待发布/ ← frontmatter: title, url, status │ │ └── 已发布/ ← 各平台归档 │ ├─────────────────────────────────────────────────┤ │ Python 后端 (vault-scripts/) │ │ ├── daily_publish.py ← 调度 + CLI 入口 │ │ ├── juejin.py ← 掘金 Playwright 引擎 │ │ ├── zhihu.py ← 知乎 Playwright 引擎 │ │ └── csdn.py ← CSDN Playwright 引擎 │ ├─────────────────────────────────────────────────┤ │ Electron 客户端 (pubhub) │ │ ├── main.js ← 主进程 + IPC handler │ │ ├── preload.js ← 安全桥接 │ │ ├── renderer/ ← Vue.js 前端 │ │ │ ├── index.html ← 表格列表 + 详情弹窗 │ │ │ ├── app.js ← 发布状态管理 │ │ │ └── style.css ← 暗色侧边栏 + 进度面板 │ │ └── data/ ← article_cache.json │ └─────────────────────────────────────────────────┘

核心设计原则: -Obsidian 是唯一的源。不用维护多份内容,frontmatter 字段统一管理 URL 和状态 -Python 负责重活。Playwright 控制 Chromium,模拟人在浏览器里的每一步操作 -Electron 提供反馈。CLI 脚本跑完后你知道发了吗——前端可视化看到每个平台的具体状态


IPC:主进程和渲染进程的对话

Electron 的安全模型规定渲染进程不能直接调用 Node API。所以需要一个中间层:

// preload.js — 安全的桥接 contextBridge.exposeInMainWorld('electronAPI', { scanArticles: () => ipcRenderer.invoke('scan-articles'), publishArticle: (title, platform) => ipcRenderer.invoke('publish-article', title, platform) }); // main.js — 实际执行 ipcMain.handle('publish-article', async (event, articleTitle, platform) => { const pythonScript = path.join(obsidianRoot, 'vault-scripts/daily_publish.py'); execFile('python', [pythonScript, '--once', '--title', articleTitle, '--platform', platform], ...); // stdout/stderr 解析为 JSON 返回给前端 });

关键点: -nodeIntegration: false+contextIsolation: true— 渲染进程沙箱化 ---title+--platform— 精准路由到目标文章和目标平台,不走全量队列 - 正则解析 stdout — Python 输出终端日志 → 前端能解析每个平台的状态


坑一:logger is not defined

CSDN 发布脚本的某一行用了logger.log(25, ...)打了一条 debug 日志,但文件头部没 import logging。结果整篇文章的发布流程中断,stderr 被吞掉,前端收到的错误信息是空白。

修复方式就是在文件开头加上:

import logging logger = logging.getLogger("csdn_publisher")

这个小 bug 卡了我一个小时——因为错误不在 daily_publish.py,不在 main.js,而在 csdn.py 内部。调试的时候需要一层层追 traceback。


坑二:Playwright inner_text(timeout=N) 新版已废弃

旧代码里写了opt.inner_text(timeout=100).strip()。在 Playwright 1.40+ 版本中,inner_text()不再接受 timeout 参数——这个参数在更早的版本已经移除了,只是之前的版本没有报错。

去掉 timeout 参数后,所有平台的自动化才真正跑通。这提醒我们:自动化脚本的生命周期比你想的长,依赖库更新时它也会跟着变老。


坑三:数据去重合并

同一个文章可能同时出现在待发布/已发布/(比如刚发布还没从待发布目录移走)。扫描时需要按标题 key 去重并合并平台信息:

pending: [{zhihu: success}, {juejin: pending}] archive/csdn/: [{csdn: success}] 合并后: [{zhihu: success}, {juejin: pending}, {csdn: success}]

如果不去重,同一篇文章会在缓存里出现两条记录,前端显示的统计数据就会翻倍。


坑四:文件删除顺序

最危险的一步:发布成功后要删除待发布目录中的原文件。但如果删除过早(比如先删源文件再归档),一旦归档步骤失败,文章就永久丢失了。

正确的顺序: 1. 更新 frontmatter,写入各平台 URL 2. 拷贝到已发布目录(备份) 3. 确认拷贝成功 4. 才删除待发布目录中的文件


效果对比

维度手动客户端
单篇文章发布~15 分钟,三平台来回切换~10 秒自动完成
状态追踪打开三个网站逐个确认一行表格一目了然
失败排查不确定哪个环节出问题逐平台显示具体错误原因
重试操作从头再来一遍失败按钮可直接点重试
历史记录没有每篇文章的前后状态可追溯

总结:为什么一定要做这个客户端?

手动自动化都好用,但自动化的价值不在于快,而在于可见

一个 Python 脚本就能搞定批量发布——我早就有了。但它的问题是:脚本跑完后你不知道结果。stdout 是文本,你需要 grep 才能看懂。

加了一个 Electron 客户端,把每个平台的发布状态、URL、时间戳、错误信息全部可视化呈现出来。这才是完整的闭环:

写 → 自动化发 → 看到结果 → 有问题可以重试 → 下次不再踩同样的坑

这个流程不是"省了多少分钟"的问题,而是让整个发布过程变成了可观测、可控制的系统

对产品经理来说,这是一个把模糊过程变成清晰数据的典型案例——不是所有的东西都需要 GUI,但当你能看到每个环节的真实状态时,决策的质量会显著提升。

http://www.jsqmd.com/news/1289623/

相关文章:

  • 5个必学ShaderGraph节点:unity-shadergraph-sandbox项目常用节点实战案例
  • 南昌家庭聚餐火锅推荐|同城多场景火锅门店实景觅食指南 - 品牌2026推荐
  • Magicodes.IE.IO:XLSX 包结构:ZIP、关系文件与顺序写入
  • 2026年交通标志牌制造领域的关键能力维度与供应体系观察 - 优企名品
  • 华庆包装:全程真空吸附印刷模切机专属技术解决方案,数码印刷机/印刷粘箱联动线,全程真空吸附印刷模切机直销厂家口碑推荐 - 品牌推荐师
  • 好用的远程桌面软件怎么选 优质的远程桌面软件推荐
  • 2026 年主流 AI 修图工具测评!ImageGood 领衔,新手零基础修图全覆盖 - 米諾
  • 【Linux】Linux 系统负载查看与瓶颈判断运维手册
  • 10分钟部署Metasploitable2靶场:国内镜像加速与SSH免密登录实战
  • Fang实战案例:构建高可用的Rust后台任务处理系统
  • iDRAC-Redfish-Scripting与SCP功能结合:服务器配置文件导入导出全流程
  • Get It.本地数据安全指南:你的学习资料如何得到全面保护
  • Bootstrap for Ember.js面板组件教程:打造精美内容展示区域
  • 电动机降压启动技术解析与应用实践
  • 南昌举办生日宴的火锅店推荐|多场景适配本地觅食实用指南 - 品牌2026推荐
  • 全球EMBA特色择校指南,民营企业家怎么选更适配
  • Path of Building PoE2:终极流放之路2角色构建规划器完全指南
  • Lix持久化机制解析:如何确保你的数据在频繁修改中安全可靠?
  • Sharp-dumpkey终极指南:3分钟快速获取微信数据库密钥的免费工具
  • 2026上海日本留学机构哪家好 实力品牌盘点 - 谁都没有我好看
  • Tanel Poder的TPT-Oracle高级技巧:DBA必备的性能调优秘籍
  • 南昌排队王火锅店觅食指南:覆盖全场景的本地火锅打卡盘点 - 品牌2026推荐
  • 2026年大庆汽车贴膜选店指南:结合本地气候的选店标准与门店参考 - 米諾
  • 一键备份QQ空间:GetQzonehistory终极记忆守护者
  • AM64x硬件防火墙实战:从寄存器解析到内存保护配置
  • OpenMCP插件 vs Web vs App:三种部署模式优缺点对比
  • 2026客服Agent产品推荐:实测后总结了这份选型清单 - 2027品牌AI展
  • 人工智能国际EMBA择校指南,企业家进阶怎么选
  • 2026年甄选:仓储仓库地坪施工领域具备专业实力的服务公司解析 - 优企名品
  • SPARTA空间音频插件对比:为什么它比传统音频工具更胜一筹?