简介:微信公众号文章批量下载工具是一款由吾爱破解论坛用户开发的绿色免安装软件,面向需要备份公众号历史内容的编辑、运营与个人收藏用户,解决公众号文章分散、不便离线阅读与存档的问题。工具支持单篇与批量下载,可将文章保存为网页、Markdown、PDF与Word文档等格式,同时支持下载视频、音频与封面图,并具备自动监听剪切板、自定义下载时长等功能,3.2版本还修复了秘钥获取、公众号ID失败及闪退等常见问题。资源包共5个文件,压缩包大小约79.11MB,包含3个可执行程序、1个说明文档和1个网页版使用说明,主程序与文档转换辅助程序一应俱全,解压后双击即可运行。目前已有3569人学习下载,适合需要快速搭建公众号文章备份方案、追求多格式输出与稳定下载体验的中初级用户使用。 先说个真实的场景:有个做行业资讯号的朋友,半年积累了两百多篇深度文章,某天想把这些内容整理成内部资料库,结果发现手动一篇篇复制粘贴,一天都搞不定三分之一。另一个做竞品分析的朋友,想把几个头部公众号的历史文章批量下载下来做选题拆解,网上一搜全是收费工具,要么失效,要么不敢用。
其实这个需求背后就一句话:微信公众号文章采集工具源码,本质上是要解决两个问题——第一,怎么稳定地拿到公众号文章列表;第二,怎么把文章正文、图片、视频批量下载到本地。这篇博文就把我实际跑通过的一个方案完整拆开讲清楚:从PC微信本地缓存提取文章链接,到解析正文、批量化下载的完整代码思路。适合有Python基础、想做公众号内容备份或数据分析的开发者参考。
1. 做采集工具前,先弄懂公众号文章的"来龙去脉"
1.1 公众号文章的URL体系
公众号文章在PC端和手机端的链接格式都是统一的,长这样:
https://mp.weixin.qq.com/s/xxx-yyy-zzz这个链接里最关键的就是/s/后面的那串字符串,它是文章的唯一标识符(mid/sn 的派生值)。只要拿到这个链接,你就能通过HTTP请求拿到完整的文章HTML页面,正文、封面图、作者、发布时间、阅读量(部分字段在源码里)都在里面。
但核心难点从来不是"如何解析一篇文章",而是"如何批量拿到这些链接"。没有链接列表,解析能力再强也没用。
1.2 文章链接的获取路径对比
我梳理过目前市面上主流的四种拿链接的方式,各有各的坑:
| 方案 | 可行性 | 坑在哪里 |
|---|---|---|
| 微信公众平台后台接口 | 仅限账号管理员 | 只能拿你自己的号,且需要Token;不能拿别人的文章 |
| 搜狗微信搜索 | 基本已废 | 反爬极度严格,验证码频繁,文章收录不全 |
| PC微信本地缓存 | 目前最稳定 | 只能拿到"在PC端浏览过"的文章,需要解析本地数据库 |
| 第三方平台接口 | 不稳且涉嫌违规 | 收费高、封号风险大、随时可能跑路 |
综合对比下来,PC微信本地缓存是我的首选方案。原因很简单:微信公众号文章在PC微信里打开过的,都会被微信客户端缓存在本地硬盘上。这个缓存是"物理上已经到你电脑上的数据",你做本地解析、本地归档,不涉及破坏任何网络请求链路。从合规和技术稳定性两个角度看,它都是最优解。
2. PC微信缓存:批量下载工具的"粮仓"到底在哪
2.1 微信PC版的本地存储结构
微信PC版会在你的用户目录下创建一个以微信号命名的文件夹,里面存放所有聊天记录、图片、文件缓存。在Windows上,默认路径是:
C:\Users\你的用户名\Documents\WeChat Files\不同版本的微信目录名略有差异,有的是WeChat Files,有的是xwechat_files。进入你的微信号目录后,重点关注这几个子目录:
FileStorage:图文消息、文件、图片、视频的存储目录MsgAttach:聊天中涉及的附件缓存Msg:聊天记录数据库文件
公众号文章在PC微信里被打开后,微信会把文章的HTML文件缓存到 FileStorage 目录下。你直接在资源管理器里搜*.html,能搜出一大堆以*.htm结尾的文件,其中相当一部分就是公众号文章的本地缓存。
2.2 如何从缓存目录快速定位文章HTML
我实际测试下来的经验是,公众号文章缓存在这里的路径通常是:
WeChat Files\微信号\FileStorage\MsgAttach\一串随机ID\File\2024-01\xxx.htm文件名是随机字符串,没有规律,但文件内容有规律——每个缓存HTML文件的<title>都是文章标题。这就好办了,我们可以直接用Python遍历目录,用标题关键字或URL特征去筛选,不需要关心文件名怎么生成。
2.3 从缓存HTML里提取真正的文章链接
缓存文件本身是微信帮我们保存的"快照",但我们做归档时,往往希望拿到线上的原文链接。好消息是:文章HTML里会保留原始的canonical链接或og:url元信息。
我们在解析时,直接用正则或XPath提取这个字段就行:
<meta property="og:url" content="https://mp.weixin.qq.com/s/xxx-yyy">拿到这个content,就掌握了文章的标准永久链接。后续无论是重新抓取最新数据,还是分享给其他人,都用这条链接。
2.4 批量扫描缓存的代码框架
下面这段代码,是我工具里"采集端"的骨架,作用就是遍历PC微信缓存目录,把所有疑似公众号文章的HTML文件找出来,并提取标题和链接:
import os import re from pathlib import Path def scan_wechat_cache(base_dir): """ 扫描微信缓存目录,返回文章链接列表 base_dir: 微信文件目录,例如 r"D:\WeChat Files\wxid_xxxx" """ article_urls = [] # 只扫描 FileStorage 下的一层子目录,避免全盘扫描太慢 for root, dirs, files in os.walk(base_dir): # 跳过非文件存储目录,提效 if "FileStorage" not in root: continue for name in files: if not name.endswith((".htm", ".html")): continue file_path = Path(root) / name try: html_content = file_path.read_text(encoding="utf-8", errors="ignore") except Exception: continue # 提取 og:url m = re.search(r'property="og:url"\s+content="(https://mp\.weixin\.qq\.com/s/[^"]+)"', html_content) if m: article_urls.append(m.group(1)) # 去重 return list(set(article_urls)) if __name__ == "__main__": urls = scan_wechat_cache(r"D:\WeChat Files\wxid_xxxx") print(f"发现 {len(urls)} 篇公众号文章") with open("urls.txt", "w", encoding="utf-8") as f: f.write("\n".join(urls))这段代码跑完后,你会得到一个urls.txt,里面是所有在PC端打开过的公众号文章链接。这就是后续批量下载的输入清单。
3. 可运行的公众号文章批量下载工具:核心代码模块拆解
拿到链接清单后,下一步是写"下载端"。我把整个工具拆成了四个模块:正文提取模块、图片下载模块、格式化导出模块、重试与去重模块。下面逐个说。
3.1 正文提取模块:别用正则硬刚HTML
很多新手上来就用正则去匹配文章正文,一旦微信调整页面结构,正则就废了。我推荐用lxml或BeautifulSoup做DOM解析,稳得多。
公众号文章的正文部分,在HTML里通常位于<div id="js_content">这个元素内。你只需要把这个div提取出来,再去掉内部的<script>、<style>、广告位节点,就能得到干净的正文HTML。
from bs4 import BeautifulSoup def parse_article(html_text): """ 从公众号文章HTML中提取标题、正文、封面图 """ soup = BeautifulSoup(html_text, "lxml") title = soup.find("h1", class_="rich_media_title") title_text = title.get_text(strip=True) if title else "未命名文章" content_div = soup.find("div", id="js_content") if not content_div: return None # 去掉脚本和样式 for tag in content_div.find_all(["script", "style"]): tag.decompose() # 提取正文中的图片地址 imgs = [] for img in content_div.find_all("img"): src = img.get("data-src") or img.get("src") if src: imgs.append(src) return { "title": title_text, "content_html": str(content_div), "images": imgs }这里有个细节值得注意:公众号文章里的图片,真实地址在>import requests def download_image(img_url, save_path): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Referer": "https://mp.weixin.qq.com/" } resp = requests.get(img_url, headers=headers, timeout=15) if resp.status_code == 200: with open(save_path, "wb") as f: f.write(resp.content) def download_all_images(images, save_dir, session=None): for idx, url in enumerate(images): ext = url.split("?")[0].split(".")[-1] if ext not in ("jpg", "jpeg", "png", "gif", "webp"): ext = "jpg" # 直接用 md5 命名,避免重名 import hashlib filename = hashlib.md5(url.encode()).hexdigest() + "." + ext download_image(url, os.path.join(save_dir, filename))
实测下来,带上Referer的下载成功率接近100%。极少数图片会偶发超时,重试两次基本都能过。
3.3 视频下载:藏在一个更深的字段里
公众号文章里的视频,不是简单的<video src="...">。微信会在HTML里注入一段var msg_cdn_url = "https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=xxx",真实的视频文件地址还需要再解析。
我在实际工具里是这么处理的:先正则匹配var msg_cdn_url = "([^"]+)",如果匹配到,就说明文章里嵌入了视频,再访问这个视频播放页,从页面里提取mp4链接。这部分逻辑较长,这里给一个最小可用的版本:
def find_video_url(html_text): m = re.search(r'var msg_cdn_url = "([^"]+)"', html_text) return m.group(1) if m else None视频链接提取出来后,下载方式跟图片一样,带上Referer即可。需要提醒的是,微信视频文件较大,建议用流式下载并实时写入文件,避免占用过多内存。
3.4 三种导出格式:HTML、Markdown、JSON
下载工具最终要输出的不能只是一堆零散文件。我做了三种导出格式,满足不同使用场景:
- HTML单文件:把正文、图片打包进一个文件,适合直接用浏览器阅读。图片需要转成Base64嵌进去,文件会比较大,但方便分享。
- Markdown:适合导入Obsidian、Notion、语雀等笔记工具,做知识库管理。
- JSON:适合数据分析,把标题、链接、作者、发布时间、正文纯文本、图片数量、视频地址全量导出,喂给后续统计脚本。
Markdown导出的核心逻辑就是遍历正文DOM,把标题标签、段落、图片依次转换成Markdown语法。图片建议存为本地相对路径,这样整个文章目录可以整体迁移。
3.5 断点续传与失败重试
批量下载最怕跑到一半网络抖动,结果前面的全白干。我做的方案是维护一个download_status.json,记录每篇文章的下载状态:
pending:待下载processing:下载中done:完成failed:失败
每次启动工具时,先读这个状态文件,只处理pending和failed的文章。这样即使中途退出,下次接着跑就行。
4. 批量下载实测中遇到的坑与我的处理方式
4.1 循环依赖的链接解析陷阱
有些公众号文章的正文里会嵌套引用其他公众号文章,这些嵌套链接在js_content里也能提取到。如果你不加判断地把所有链接都下载,工具会陷入"文章A包含文章B,文章B又包含文章A"的无限递归。
我的处理方式是:只下载og:url与当前页面URL一致的文章,其他链接一律标注为"外链"单独记录,不递归下载。要深度采集的话,可以做一个单独的待处理队列,自己去控制深度。
4.2 微信返回的正文HTML编码问题
公众号文章的HTML页面默认是UTF-8,但老文章偶尔会出现部分字符乱码。我建议在解析前先做一次编码嗅探:
import chardet def decode_html(content_bytes): result = chardet.detect(content_bytes) return content_bytes.decode(result["encoding"] or "utf-8", errors="ignore")用chardet判断编码,比死认UTF-8稳健很多。特别是处理2018年以前的历史文章时,这个步骤特别重要。
4.3 图片加载失败的替换策略
即使带了Referer,仍有小概率图片下载失败。我的策略是:下载失败超过三次,就把图片地址替换为一个占位图片,并在导出目录下生成一个failed_images.txt记录失败链接。这样至少保证导出流程不断掉。
4.4 不要直接抓线上正文,优先使用本地缓存HTML
我最初的设计是:拿到urls.txt后,直接往mp.weixin.qq.com发请求去抓取正文。后来发现两个问题:第一,请求频率稍微高一点,微信会临时限制IP,返回环境异常的提示页;第二,部分文章对未登录用户只返回摘要,拿不到全文。
后来我调整了策略:优先解析PC微信缓存里的HTML文件,只有缓存里没有的文章才去线上抓取,且请求间隔限制在2秒以上。这样既稳又快,毕竟缓存已经在你硬盘上了,白白放着不用纯属浪费。
4.5 去重与增量更新的实现
如果你的工具会定期跑,还要考虑增量问题。我用的去重逻辑是"URL + 内容Hash"双重判断:
import hashlib def article_hash(title, content_text): md5 = hashlib.md5() md5.update((title + content_text).encode("utf-8")) return md5.hexdigest()每次下载完成后,把文章URL和Hash存到index.json。下一次扫描时,如果URL已存在且Hash一致,就跳过。这样同一个公众号文章即使缓存了多份,也不会重复下载。
5. 工具的价值边界:能做的事与不该做的事
5.1 合理的应用场景
基于这套思路开发的工具,我在实际中主要用在这些场景:
- 个人知识库建设:把自己读过的好文章批量归档到本地,配合Obsidian做二次整理,查找效率比翻公众号历史记录高太多了。
- 竞品内容分析:把几个对标公众号的文章批量下载后,用文本分析脚本统计高频标题关键词、内容主题分布、更新频率。
- 内容迁移:从A平台迁到B平台时,不需要一篇篇复制,直接批量导出Markdown后统一导入。
- 离线阅读:出差路上没有网络,本地归档的文章可以随时翻阅。
5.2 使用中必须守住的红线
这部分我必须说清楚:批量下载工具本身是中性技术,但用在哪里决定了它是否合规。
- 仅用于个人学习、研究、备份自己有权访问的内容,没有问题。
- 未经授权,大规模采集他人公众号文章并二次发布、售卖、洗稿,涉嫌侵犯著作权,不要做。
- 采集涉及个人隐私内容(如非公开文章、付费文章、定向推送文章),不要做。
- 用工具对微信平台造成异常压力(高频请求、绕过风控),属于破坏平台规则,风险自己承担。
我在源码里特意加了一个"下载限速"配置项,默认每篇文章间隔2秒,并且单次任务最多下载500篇。这不是技术做不到,而是刻意设置的使用边界——采集工具的价值在于帮自己省时间,而不是成为批量搬运的机器。
5.3 后续可以扩展的方向
如果你愿意继续折腾,这套工具的扩展空间还挺大:
- 接入一个简单的Web界面,输入公众号名称或文章链接,前端点一下就能下载。
- 把下载结果同步到阿里云OSS或S3,做成自己的文章备份云盘。
- 对正文文本做自动摘要和关键词抽取,配合大模型API,实现个人文章库的智能检索。
最后说一点个人的体会。公众号文章采集工具这类东西,技术难度其实不算特别高,真正麻烦的全是细节——缓存文件路径要适配不同版本、图片防盗链要带Referer、老文章编码要嗅探、批量请求要限速。每踩一个坑,就把对应的异常处理补进代码里,来回迭代几次,工具就变得非常皮实。我建议你也先从一份小小的urls.txt开始,跑通一篇,再逐步扩展成完整的批量流水线。不用纠结第一版写得漂不漂亮,先跑起来,后面再慢慢打磨。
本文还有配套的精品资源,点击获取