求职意向:先把「收藏」变成「资产」
它解决的问题特别具体:你收藏了一堆值得长期看的号,但想批量存下来的时候,没有工具能把正文连同图片一起拿走。手动复制粘贴不光累,还会丢图、丢视频、丢排版。
所以整条路线被拆成了三段,每段的责任人都不一样:
口径先说清楚:本页的实现细节来自作者原文 + 仓库源码的静态阅读(每条都能按下面的「源码索引」回查),我没有在本机实跑这套工具。所以这里不写「实测下载速度」,只写源码里看得见的事实与常量。
履历:七步流水线
每一步的产物落哪儿
| 阶段 | 输入 | 动作 | 产物 |
|---|---|---|---|
| 01 | 一个微信扫码 | 换取微信读书长效 Token,存入账号池 | data/account_pool.json(vid / accessToken / refreshToken / skey) |
| 02 | 作者任意一篇链接 | 解析出 bookId 并收藏为「公众号」 | 公众号条目 + fakeid ↔ bookId 映射 |
| 03 | 时间范围 / 关键词 | 分页拉列表 → 逐篇抓正文 → 图片本地化 | 下载目录/标题/ + media/ + 下载历史记录 |
| 04 | 下载目录 | Codex 逐篇核对正文、图片、来源 | 下载检查表.csv(可用 / 失败 / 待核) |
| 05 | 检查表 | Codex 建库:01-文章 / 02-方法笔记 / 03-分析结果 / 04-个人笔记 / 05-提示词 | 可被 Obsidian 打开的「GitHub学习库」 |
| 06 | 一个具体问题 | Codex 读库作答,关键建议附本地文章链接 | 03-分析结果/xxx.md + 首页新入口 |
| 07 | 新增下载件 | 放回原目录 → 增量入库 → 更新结论 | 文章数从 N 变 N+1,判断被修订而不是被覆盖 |
最值得学的是 STEP 7 的处理方式:新文章不是另建一套库,而是放回原来的原始下载目录,让同一个对话去「按原文链接查重 → 更新上一轮的结论」。它甚至把提示词写成了「原建议哪里不变、新增什么、什么时候需要做」——这三句是为了让模型修订而不是重写,避免每加一篇文章就把之前的结构推倒重来。
能力画像
| 能力 | 自评 | 依据 |
|---|---|---|
| 批量抓取 | 强 | 按时间范围分页到底,或最新 50 篇增量;自动跳过本地已有,断点续采是默认行为 |
| 内容完整度 | 强 | 正文 + 图片一起落盘(图片本地化到 media 目录),另出语义 Markdown 与矢量 PDF |
| 抗风控 | 很强 | 这是整个项目工程量最大的部分:401 静默续期、-2014 退避、-2041 防水墙熔断、多账号轮换、无头浏览器保活 Cookie |
| 增量订阅 | 强 | 标准 RSS 2.0,每号独立 feed + 聚合 feed,调度器定时跑,图片和链接域名可反代改写 |
| 可运维性 | 强 | 双数据库(SQLite 零配置 / MySQL)且能平滑降级回退;下载历史可从磁盘反查重建 |
| 指标(阅读量) | 无 | 微信读书不展示阅读数、赞数、精选留言 —— 这套 SOP 判不出哪篇是爆款 |
| 稳定性 | 看天 | 走的是非公开契约,签名靠逆向 libencrypt.so;上游一改就要等作者跟进 |
| 开箱成本 | 低 | 桌面端解压即用(Lite 40~60MB / Full 内置 Chromium 200~240MB),不必配 Python 环境 |
深度拆解:它到底是怎么拿到文章的
这是整套东西最聪明的一步,也是它和「扫码登录 mp.weixin.qq.com」那条老路彻底分开的地方。公众号后台要号主身份,只能管自己那个号,Cookie 还会隔天就掉。而微信读书给了任何一个登录用户「读任何号的历史推文」的能力 —— 于是它干脆去登录微信读书。
- 换回来的是一组完整身份:
vid/accessToken/refreshToken/skey/deviceId。 - 换完立刻调一次
activate_terminal_session()做 mobileSync —— 对齐官方客户端「登录完成即同步终端会话」的行为,否则新号在服务端眼里不算在线。 - 落地就是
data/account_pool.json,后面所有请求都从池子里「借」一个会话。
微信这边每个公众号的身份叫 __biz(形如 Mzg2Mjk5NTMyMA==),看着像密文,其实只是把纯数字 uin 做了 base64。把它解开、补上 MP_WXS_ 前缀,就得到微信读书里这本「书」的 bookId:
一旦接受这个映射,整个模型就顺了:公众号 = 一本书,推文 = 章节,翻页 = 翻章。所以后面所有接口参数都是 bookId + offset,而不是 fakeid + begin。代码里先把 book_id 算出来,算不出来直接抛「无效的公众号标识」,不做半吊子猜测。
拉列表这步写了四个接口、三层降级,思路很明确:任何一层挂了都不能让任务 500。
| 接口 | 作用 | 特点 |
|---|---|---|
| /web/mp/cover | 首屏 | 置顶 + 最新推文,100% 带 doc_url,成功率最高,所以拿来打头阵 |
| /web/mp/chapters | 主力分页 | 带 offset 翻页 + synckey 增量游标。注意:带 offset 时不追加 synckey,这是对齐官方 APK 的 SyncKeyRequestFeature |
| /web/mp/list | 备用列表 | 请求时自动补 synckey=0,走另一条聚合路径 |
| article/list | 最后兜底 | 拿到的只是条目,还要并发逐篇解析原生微信链接 |
- review_id 自带短链线索:形如
MP_WXS_2940696320_yvrxT0XE-9ELBG4gQZhB4g,下划线后面那段可以直接定位原文,不必再猜。 - 缓存分两级:chapters 列表 60 秒、book info 600 秒。翻页快的时候不会把上游打爆,翻页慢的时候也不会读到过期数据。
- 降级不抛错:受 499 临时限制时平滑降级到备用通道,函数注释里写得很直白 ——「绝不抛出 500」。
这是全项目最硬的一段。微信读书的每个请求都要带签名,签名算法原本在 Android 的 libencrypt.so 里(weread::GenSignature / nativeGetSignatures)。作者把它纯 Python 复刻了,所以不用跑 so、不用装模拟器:
细节里藏着三个「必须对齐」的点,错一个签名就全废:排序用的是字节序(不是字符序),移位量是异或和模 11,第一轮输出的是 64 字节小写 hex 再参与第二轮。另外 refreshToken 会自动换新的 accessToken,所以长效登录不是靠一直不关程序。
接口路线的命门从来不是「怎么抓」,是「抓多了会怎样」。这里做了四层防御,全部按上游真实错误码分级:
| 信号 | 含义 | 处理 |
|---|---|---|
| 401 | Token 过期 | 标记该账号 → 用 refreshToken 静默换新 → 0.5s 后重试,用户无感 |
| -2014 | 网关频控(OverFreqInterceptor) | 退避 2.5 秒降频重试一次;仍命中就熔断并转人工验证 |
| -2041 | 人机验证 / 腾讯防水墙 TCaptcha | 特征词表命中即记录取证 → 冷却 300 秒 → 人工过一次验证后把 wr_ticket + wr_randstr 票据缓存复用 |
| 499 / 429 | 临时限制 | 平滑降级到备用接口,不让整个任务挂掉 |
- 多账号轮换:每次请求
borrow_weread_session()借一个号,用完归还并按状态打分。官方 README 直接建议挂 2~3 个小号做负载均衡与智能退避。 - 防水墙识别:不只看状态码,还扫响应体里的
tcaptcha/captcha.qq.com/randstr/risk_control/verify_code等特征 —— 因为腾讯的验证页经常是 200 状态码返回一坨 HTML。 - Plan B 保活:
weread_browser.py用 Playwright 起无头浏览器,每个账号一个独立的 Persistent Profile,串行单实例(省内存),去真实网页里换当天的wr_skey。Cookie 会变,接口签名不会。 - 兜底还有第三条腿:仓库里留着
mac/目录 —— OCR + 点击 + 滚动的 GUI 自动化路径。作者自己也清楚接口会翻脸,所以留了「像人一样点」这条后路。
拿到的是一整页 HTML,但直接存下来是不能用的 —— 里面全是广告、二维码、引导关注。所以中间有一层可配置的清洗:
- 离线 HTML:图片全部本地化到同目录
media/,断网也能看原排版;/api/articles/serve-file/负责把本地图喂回页面。 - 语义 Markdown:给 Obsidian 和模型读,标题层级保留,是最适合 AI 分析的形态。
- 矢量 PDF:靠 Chromium 渲染,所以 Lite 版要你自备 Chrome / Edge,Full 版内置内核(体积涨到 200MB+,Docker 里
INSTALL_BROWSERS=1再加 1.5GB)。 - 元信息:发布时间精确到分钟、精准识别原创标记 —— 这两项是给「按时间归档 + 判断是不是转载」用的。
- 断点续采:
skip_existing=True是默认值,本地已有的直接跳过;下载历史和磁盘不一致时,_sync_history_from_disk()能从磁盘反推重建记录。
整个项目「能长期用」的分水岭就在这一层。没有 RSS,它只是个批量下载脚本;有了 RSS,它变成了能在任意阅读器里订阅的源。
- 标准 RSS 2.0,每号一个独立 feed + 一个全聚合 feed,支持全文或摘要输出。
- 调度器按设定间隔增量抓,命中新文章就入库并更新 feed;
RSS_TOKEN做访问鉴权,避免公网裸奔。 RSS_BASE_URL用来在反代场景下统一改写 XML 里的图片与链接域名 —— 这个细节说明作者真的部署过。- 安全建议也很克制:只反代三条路径(
/api/articles/rss、avatars/、serve-file/),管理后台彻底留在内网。
- 桌面端:PyInstaller 打包,GitHub Actions 自动出 Windows 与 macOS(arm64 + x86_64)两套。Lite 40~60MB 用你的 Chrome,Full 200~240MB 内置 Chromium。
- Docker:
ghcr.io/x554960766/wechat-mp-tools:latest一行起,端口 5200,只挂./data。轻量版镜像约 100MB。 - 双数据库:默认 SQLite 零配置;配 MySQL 也行,而且 MySQL 没就绪时会自动降级到 SQLite 顶着,恢复后再握手回来。
- 本地 Web UI:跑起来后
http://127.0.0.1:5200,整个操作都是点界面,不用敲命令 —— 这也是原文能写成「七个 STEP」的前提。
源码索引:上面每一句都能回查
| 文件 | 行数 | 看什么 |
|---|---|---|
| wechat_mp_login.py | 118 | 二维码轮询、errcode 语义、换 Token、mobileSync 激活 |
| backend/accounts.py | 520 | biz_to_book_id() / book_id_to_biz() 双向换算 |
| backend/articles.py | 2,083 | 四路接口兜底、分页、降级、下载任务、历史同步、内容清洗 |
| backend/weread_signer.py | 235 | S-Box、盐、两轮 SHA256 的完整签名实现 |
| backend/waterwall.py | 303 | TCaptcha 特征词表、300s 冷却、验证票据缓存 |
| backend/weread_browser.py | 242 | Playwright 独立 Profile 保活、Cookie 有效性校验 |
| backend/rss_feed.py / rss_scheduler.py | 568 / 995 | RSS 2.0 生成、增量调度、token 鉴权 |
| mac/article_finder.py · mac/steps/step3 | 132 / 249 | GUI 自动化兜底:搜一搜 → 公众号主页 → OCR 定位卡片 |
同题考场:接口路线 vs 界面路线
通道:HTTPS + GenSignature
命门:签名会改、频控会来
通道:UIA + SendInput + RapidOCR
命门:界面改版、坐标漂移
逐项对照
| 维度 | 微信 MP Tools(接口) | 公众号采集雷达(界面) |
|---|---|---|
| 阅读量 | 拿不到 微信读书不显示 | 直读 每次打开都是当天最新值 |
| 赞 / 转发 / 评论数 | 拿不到 | 底栏四件套 部分老文/转载文留空 |
| 精选留言 | 拿不到 | 首条 + IP + 时间 + 是否置顶(仅作者精选过的) |
| 正文与图片 | 完整落盘 HTML / MD / PDF 三格式 | 不落正文 只取标题、元信息与分享链接 |
| 标题 / 作者 / 发布时间 | 接口结构化返回 | 优先读文章页 HTML 元信息,比 OCR 稳 |
| 历史全量 | offset + synckey 翻到底,自动跳过已下载 | 主页从上翻到真到底,需处理懒加载与 UIA 截断 |
| 增量 / 订阅 | RSS 2.0 + 定时调度,可挂任何阅读器 | 没有订阅,每次重跑并靠去重 |
| 单篇耗时 | 秒级,可并发 | 约 15 秒,串行且不能动人手 |
| 风控形态 | 服务端:签名、-2014 频控、-2041 防水墙 | 客户端:界面改版、分辨率、坐标偏移 |
| 断点续采 | skip_existing + 磁盘反查 | 每篇即时落盘 + 差集补采 |
| 依赖 | Python / Chromium / 一个微信读书号(建议 2~3 个) | Windows 10/11 + 登录态微信 4.x + 40 个脚本 |
| 最终交付物 | HTML / MD / PDF 文件树 + RSS feed | 三 sheet Excel(清单 / 覆盖核对 / 口径说明) |
| 最擅长回答的问题 | 「这个号都写过什么?全部存下来给我读」 | 「这个号哪几篇是真爆款?数据拿给我」 |
把它们摆在一起看,结论其实挺扫兴也挺爽:它们不是竞品,是互补的两只眼睛。
- 雷达能告诉你「哪 20 篇值得存」,但它不存正文 —— 你拿到一堆阅读量数字,还得自己去把文章弄下来。
- 这套 SOP 能把「整本都存下来」,但它不知道哪篇重要 —— 全部下完,你会发现自己在 2,000 篇里迷路。
- 把它们接起来,正好补掉各自的盲区:雷达筛 → 工具整篇搬 → RSS 盯增量 → Obsidian 入库 → Codex 用。第一步用界面拿「判据」,第二步用接口拿「内容」。
面试反问:它做不到什么
libencrypt.so 逆向出来的,接口参数对齐的是官方 APK 的拦截器与重试策略。上游一改,就要等作者跟。这类工具的寿命不由使用者决定。顺带说清楚作者与出处:这套工具是开源项目 x554960766/wechatAutoRSSTool(Python,277 个文件,2026-06 建仓、11 月仍在更新,仓库标注 License 为 Other 而非标准协议,商用前自己确认);把这套工具串成 SOP 的是公众号「AI应用实战派pro」的你旺哥,原文《我把公众号文章从收集-下载-存到Obsidian知识库-AI分析,做成了一套SOP》(2026-10-29)。本页只做技术拆解与对照,工具版权归作者。
姊妹技能
如果你只想解决「我要知道哪个号哪几篇火」——去雷达那页就够了。如果你要的是「把这个号十年的东西整本存进本地库,以后能搜能问」——留在这一页。两个都要,就按上面那条流水线接着跑。
上游:x554960766/wechatAutoRSSTool · 原文:AI应用实战派pro · 你旺哥
口径:实现细节来自作者原文与仓库源码静态阅读(八层拆解均标注了源文件),未在本机实跑;不承诺任何抓取成功率。
← 回 skills 实验室