微信百宝箱(wx-kit)迭代历程:我砍掉了做两个月的功能,又把这个工具一点点救了回来
三个月前,我写过一篇文章,介绍自己刚做出来的 wx-kit。
它是一个微信公众号文章下载器。丢进去一条文章链接,它会把正文、图片和视频保存到本地,还能导出 Markdown、网页和 PDF。那时候我已经给它加上了批量下载、文库管理和公众号订阅,也做了一套纯 JSON 的命令行接口,方便 AI agent 直接调用。
文章发出去以后,项目还在继续往前走。版本从 v0.3.0 一路更新到 v0.8.5,批量下载和订阅越做越完整。我花了两个月处理登录、判重、定时检查、失败重试和各种微信文章类型,终于把这两项能力磨到了自己愿意日常使用的程度。
然后,公众号文章列表接口突然不能用了。
最开始我以为是自己的公众号账号被封控。换一个号登录,还是不行。再换,结果也一样。我来回查了不少地方,最后在 GitHub 上几个同类项目的 issue 里看到,其他人也遇到了相同情况。
问题不在我的账号。大家依赖的那条接口失效了。
这意味着 wx-kit 无法继续获取一个公众号的文章列表。批量下载没了列表,不知道该下载哪些文章。订阅也一样,连新文章有没有出现都看不到。
前面两个月做的东西,一下失去了入口。
做不到,就先撤下来
当时当然想过继续找办法。代码还在,技术上也完全可以把入口继续放着,再补一句“偶尔可能恢复”。
可这会把麻烦推给用户。
一个按钮摆在那里,用户会默认它能用。点下去以后转半天,没有结果,再换账号、重新登录、反复扫码,最后也不知道是自己操作错了,还是软件坏了。开发者心里清楚这套流程已经靠不住,界面却还在让用户尝试,这件事我接受不了。
我最后发了 v0.9.0,把按公众号批量下载和订阅整条撤下。相关代码没有删除,原来的订阅数据也保留着,但界面入口、后台调度和实际网络请求全部停掉。命令行里已有的相关命令仍能被识别,只会直接告诉调用者,这项能力目前不可用。
那次最难受。做到 v0.8.5 后,前面花了两个月做的批量下载和订阅,只能整条下线。
单篇文章下载依然正常,文库也还在。可我知道,wx-kit 最有想象力的那一部分少了一大块。
事情过了一阵。有一天,我准备把一篇微信文章分享给别人,在分享列表里看到了微信读书。
我顺手把文章发过去,在微信读书里打开,文章可以正常阅读。接着我点了一下标题下面的公众号名称,竟然弹出了这个公众号的文章列表。
我当时心里一喜。
天无绝人之路啊。
微信读书给了一次机会
既然微信读书能展示公众号文章列表,背后就一定有数据。接下来的问题很直接,wx-kit 能不能借这条通道重新拿到文章清单。
最先找到的是微信读书移动端接口。它给的信息很全,能拉历史文章,还有阅读和点赞数据。可真跑起来以后,请求直接返回 499 和错误码 -2041。换成真实手机的请求特征也没解决,登录凭据又会因为客户端身份对不上而失效。
移动端走不通,只能转向网页端。
网页端有一个接口,可以拿到某个公众号最新的一篇文章。只有一篇,也没有完整历史。它至少能回答一件事,公众号现在最新的文章是哪篇。
这已经足够恢复增量订阅。应用定时记住上次看到的文章,下次再检查,如果最新一篇变了,就提醒用户或者自动下载。
我和 AI 很快把旧的订阅流程接到了微信读书上。旧代码没有白留,订阅检查、下载和记录的大部分流程都能继续用,只需要把前面获取文章的那一段换掉。v0.10.0 看起来已经有了着落。
真机一跑,先撞上 401。
原因很具体。登录用的是移动端协议,业务请求走的是网页端接口,两边需要的凭据根本不是同一种东西。测试环境里的模拟数据把这个错误一路放行了,真实服务器第一下就认了出来。
我们改成网页端登录,又处理了 Cookie、短链接和几个字段类型问题。最新一篇终于能稳定拿到了。
历史列表仍然返回 -2041。
排查到这里时,出现过一个很有迷惑性的现象。同一份登录凭据在系统 Chrome 里曾经成功拿到列表,放进 Electron 和普通网络请求里却失败。这个对照太像浏览器网络特征造成的风控了。我们于是把微信读书请求搬进内嵌 Chromium,希望让它和真实浏览器保持一致。
改造做完,列表还是失败。
最后一次实验,我直接在真正的 Chrome 窗口里重新扫码登录。登录凭据是全新的,会话也在正常更新。随后请求文章列表,结果依旧是 -2041。
这个实验把客户端差异排除了。服务端限制的是账号和文章列表端点,换浏览器、换请求库、继续伪装客户端都没有用。先前那次成功,只是碰上了限制尚未生效的时间窗口。
两天排查到这里,答案已经很清楚。历史文章批量下载依然无法恢复。微信读书留下的能力只有最新一篇,wx-kit 便只保留最新一篇能支撑的功能。
公众号订阅重新上线了。它每次只能看到当前最新文章,两次检查之间如果连续发了多篇,较早的文章可能会错过。这个限制现在会直接写在产品说明里。按公众号批量下载的入口继续移除,因为它需要完整列表,最新一篇替代不了。
这次恢复算不上完整,却是可靠的。用户看到的每个入口,都有一条当时确实能跑通的路径。
系统没查到,不能说成没有
订阅恢复以后,我又遇到一个很小、后果却很糟的错误。
微信读书登录状态过期时,接口会返回 401。程序里有一层兜底,把这个错误吞掉,变成一个空结果。上层收到空结果以后,按照正常逻辑显示“没有新文章”。
那天我明明知道两个公众号发了新文章,wx-kit 却告诉我没有。我绕过应用直接请求接口,才看到真正的 401。
它根本没有完成检查。
这两种情况对用户的意义完全不同。确实没有新文章,用户什么都不用做。登录过期,用户需要重新扫码。程序把后者说成前者,界面显得很平静,用户却会悄悄漏掉内容。
修复的代码只有几行。401 保留为明确的登录失效错误,任何兜底都不能把它吞成空列表。订阅页收到这个错误后,会直接提示重新登录。
我后来把这条写进了项目规则。失败要保留它原来的类型。程序查不到,就告诉用户为什么没查到,不能把失败说成什么都没有。
每次检查也要留下记录。查了哪些账号、发现几篇、下载成功几篇,用户都能在界面里看见。系统已经知道的事情,就别让用户靠猜。
从微信走到墨问
做到 v0.10.6 时,我开始考虑把墨问笔记也接进 wx-kit。
墨问有官方命令行工具 mocli,可以搜索用户和读取笔记清单。正文却麻烦一些。初步测试下来,官方接口只允许作者读取自己笔记的完整结构,其他人的笔记只能拿到简介和字数。
AI 根据这个结果,准备把方案收口到“只能下载自己的笔记”。
我问了它一句。
“你都能获取到 URL,为何不能下载全文?不要局限于人家的接口啊。”
wx-kit 最早做的事情就是按 URL 下载网页。墨问笔记既然能在浏览器里打开,正文总要通过某种方式送到页面上。我们重新做了一轮验证,用 Electron 自带的浏览器在后台打开笔记页面,成功拿到了完整正文。
当天晚些时候,我又从浏览器的网络请求里找到了墨问页面加载正文所用的接口。它能返回结构化的 HTML、图片信息和笔记数据,速度比完整渲染网页快得多。
最后定下来的办法分成两段。找作者、搜笔记和拉清单走 mocli 的官方接口。下载公开正文时,使用墨问分享页自己调用的数据通道,浏览器渲染保留为备用方案。付费笔记和他人的私密笔记拿不到,就明确告诉用户,不做权限绕过。
这套组合让墨问很快进入了 wx-kit。用户可以按作者查找笔记,勾选后批量下载,也可以直接粘贴单篇链接。接着又加上作者订阅,检查新笔记的频率和自动下载设置与公众号共用,但两边各自保存检查记录,互不影响。
到了 v0.11.2,墨问又补上了关键词搜索。搜到一篇笔记后,可以点作者继续查看他的其他内容。笔记里引用了另一篇笔记,下载后的正文会在原位置显示标题、摘要和作者。图集缺图时,程序会继续调用墨问网页使用的另一个接口把图片补齐。
这些功能听起来比最初的“下载一篇微信文章”走远了不少,使用方式却没有变复杂。用户负责找到想留下的内容,wx-kit 把正文和媒体保存到本地,进入同一个文库。以后要阅读、搜索、导出给 AI,文件都在自己电脑上。
v0.11.2 现在能做什么
今天的 wx-kit 仍然可以下载微信公众号文章。粘贴一个或多个链接,正文、图片和视频会保存到本地,可以导出 Markdown、HTML、PDF、封面和元信息。普通图文之外,文字消息、视频消息和图片消息也做了适配。解析或媒体下载遇到异常时,结果里会留下告警。
下载后的内容进入本地文库,可以搜索、按公众号分组、阅读和导出素材,也能生成 Astro 站点所需的文章目录。GUI 适合平时点选使用,命令行继续输出纯 JSON,AI agent 和脚本都能直接调用。
公众号订阅已经恢复,但依赖微信读书提供的最新一篇。它适合增量跟踪,无法回补完整历史。按公众号批量下载仍然不可用。
墨问这边可以按作者或关键词找笔记,批量下载公开内容,也能订阅作者的新笔记。使用发现和订阅功能前,需要安装并登录 mocli。付费内容与他人私密笔记遵守墨问原有权限。
wx-kit 目前已经迭代到 v0.11.2。它仍然开源,依旧没有后台服务器,所有文章和笔记都保存在用户自己的电脑上。
三个月前写第一篇介绍时,我把重点放在“把内容从封闭平台保存下来”和“让 AI 可以直接使用这些内容”。这两个出发点没有变。中间发生的这些事,让我对做工具多了一点具体认识。
加上一个功能很有成就感。确认一项能力已经不可依赖,然后把它完整撤掉,也是在对产品负责。
AI 可以陪我追错误、设计实验,也能把验证过的决定落实成代码和测试。服务端返回 -2041 时,它同样变不出一条不存在的接口。我们能做的是把能走的部分做稳,把走不通的部分说明白。
v0.9.0 发布时,我以为自己只是删掉了两个月的成果。现在到了 v0.11.2,订阅换了一种方式回来,墨问也进入了同一个文库。那些被撤下的功能没有原样复活,wx-kit 却比当时更清楚自己能做什么。
