我一直很关注公众号文章导出和爬取,今天看到一个很有意思的开源项目:https://github.com/wechat-article/wechat-article-exporter ,用了一种很有意思的方法解决了这个问题。
核心原理(一句话)
它不是爬虫,是微信公众号管理后台的「代理人」——通过你扫码登录微信公众号后台(mp.weixin.qq.com),拿到 session cookie,然后用微信后台自己的内部 API 来拉取任何公众号的文章。
关键技术链路
第一步:登录(最关键)
用户浏览器 → Nuxt 服务端 → mp.weixin.qq.com
- 调用
scanloginqrcode?action=getqrcode获取二维码 - 用户用微信扫码确认
- 轮询
action=ask等待扫码结果 - 扫码成功后 POST
bizlogin?action=login - 微信返回
redirect_url里带token,加上Set-Cookie里的一堆 cookie - 服务端生成一个
auth-key把 token + cookie 存到 KV 存储,客户端只持有这个 key
⚠️ 你不需要是那个公众号的管理员。只要有任何一个微信公众号的管理权限就行——微信后台登录后,搜索公众号的 API 是全局的。
第二步:搜索公众号
GET https://mp.weixin.qq.com/cgi-bin/searchbiz?query=xxx&token=xxx
用微信后台的搜索接口搜任何公众号,返回 fakeid(微信内部 ID)。
第三步:拉文章列表
GET https://mp.weixin.qq.com/cgi-bin/appmsgpublish?fakeid=xxx&token=xxx
用的是微信后台的素材管理 API,可以拉到目标公众号的全部历史文章列表,包括:标题、摘要、链接、封面、发布时间、作者、是否原创、所属合集。
第四步:下载文章内容(需要代理)
文章内容不是从后台 API 拿的,而是直接访问文章的 URL(mp.weixin.qq.com/s?__biz=xxx)。但微信有严格的反爬,直接从服务器 IP 访问会被封,所以项目部署了一套代理池架构:
- 公共代理:Cloudflare Workers 部署的 96 个节点(6 个域名 × 16 个子域名)
- 请求路径:浏览器 → CF Worker 代理节点 → mp.weixin.qq.com → 返回 HTML
代理管理器(ProxyManager)实现了:自动选最优代理(失败最少 + 最久未用)、失败自动冷却 + 指数退避重试、并发控制(HTML 可高并发,阅读量数据限 2 并发)。
第五步:解析文章内容
拿到 HTML 后,从中提取 window.cgiDataNew 这个 JS 对象——这是微信文章页的核心数据结构,包含完整文章内容(HTML)、作者、公众号名、创建时间、IP 归属地、阅读量、点赞、分享、评论数。
解析方式很聪明:
- 浏览器端:创建隐藏 iframe 执行 JS,直接拿
window.cgiDataNew - 服务器端:调用外部 JS 执行服务(因为 Cloudflare Workers 禁止
eval)
第六步:抓阅读量 / 评论(可选)
阅读量和评论需要手机端微信的认证凭证(uin、key、pass_ticket)。项目提供了一个 mitmproxy 插件:手机设置代理 → 打开目标公众号文章 → 插件自动截获 Set-Cookie 提取凭证 → 暴露给前端使用。
第七步:导出
支持 HTML、Markdown、DOCX、Excel、JSON、TXT 多种格式。所有数据存在浏览器端的 IndexedDB(通过 Dexie.js),不依赖服务器存储。
架构亮点
- Nuxt 3 全栈:前后端一体,服务端做代理转发,客户端做 UI + 数据存储
- 无需自建后端存储:IndexedDB 做本地缓存,auth-key KV 做 session 管理
- 96 节点代理池:用 Cloudflare Workers 免费额度,分散请求避免封 IP
- 两套认证体系:公众号后台 cookie(搜索 + 列表)+ 手机端微信 credential(阅读量 + 评论)
- 增量下载 + 缓存:已下载的文章 HTML 缓存在 IndexedDB,不重复抓
风险和限制
- session 有效期约 4 天:需要重新扫码
- 微信风控:抓取频率过高会触发验证码或封 IP
- Credential 很短命:手机端凭证 key 有效期很短,过期要重新抓
- 法律灰色地带:利用微信后台 API 批量抓取,违反微信 ToS
- 只能抓公开文章:付费文章、仅粉丝可见的无法抓取