☰
微信公众号文章采集与导出系统实战:Python爬虫与批量归档
2026/10/24 3:04:51 网站建设 项目流程

简介:这是一款面向个人学习者与技术爱好者设计的微信公众号文章数据采集与导出系统,旨在解决公开内容批量获取、结构化存档与多维分析的实际需求。资源包共131个文件,涵盖34个TypeScript核心逻辑文件、24个Vue前端组件、29张PNG界面素材及10份Markdown说明文档,辅以JSON配置、CSS样式与Docker部署相关脚本,整体压缩后仅12.3MB,轻量易部署。已有199人下载学习,适用于需研究新媒体内容生态、训练NLP语料或构建自有知识库的技术实践者。用户可直接运行免环境依赖的HTML导出模块,完整保留图文排版;通过关键词检索公众号、标题筛选文章、专题批量下载,并提取阅读量、留言及转发等交互数据;项目支持Docker容器化部署与定时自动订阅,开放API便于二次集成,配套说明文档详述抓包授权等关键操作步骤。 做这个系统的念头,最初来自一个很现实的需求:个人知识库整理。我平时会收藏大量公众号文章,但公众号生态相对封闭,文章一旦被作者删除、迁移或者账号注销,内容就再也找不回来。零散收藏不仅查起来费劲,更怕哪天想引用的时候发现链接已经失效。于是我就萌生了一个想法:能不能自己写一套工具,把需要长期保存的文章完整抓下来,按我自己的规则归档、检索、二次分发?这套“微信公众号文章数据采集与导出系统”就是这么诞生的。

这个概念其实很简单:通过微信公众平台或微信客户端可访问的接口,把指定公众号的历史文章列表抓下来,再逐篇获取正文、作者、发布时间、封面图等数据,最后批量导出成可离线阅读的格式。整个过程涉及登录态维护、列表抓包、正文解析、图片处理、批量渲染等多个环节,每一环都有不少坑。这篇内容就围绕我在实际搭建过程中踩过的坑、试过的方案、最终跑通的流程展开,适合有Python基础、想自己搭建内容归档工具的朋友参考,也适合团队用来做公众号内容资产沉淀、舆情备份、行业报告素材收集等场景。

1. 为什么需要自建一套公众号文章采集导出工具

1.1 需求场景:从收藏到归档的痛点

公众号文章最大的问题在于“所有权”不在读者手里。你收藏了十篇深度好文,可能某天作者因为转载纠纷删文,或者账号被平台回收,内容就彻底消失。我们在做行业调研时尤其依赖公众号内容,一个细分领域往往有一批垂直账号持续输出高质量文章,这些内容分散在不同账号下,没有统一入口,也没法像网页那样直接离线保存。

自建系统解决的就是三件事:全量备份、统一检索、格式转换。全量备份是把某账号下的历史文章尽可能完整地保存下来,包括正文、图片、原文链接、发布时间等关键信息;统一检索是把所有采集到的文章放入一个本地库,按标题、作者、时间、关键词都能快速筛选;格式转换是把网页内容变成Markdown、PDF、Word等适合阅读、分享和存档的格式。这三个需求听起来不复杂,但真正动手做的时候,光“拿到文章列表”这一步就够折腾。

1.2 方案选型:现成工具与自己写的边界

市面上其实已经有一些在线的公众号文章采集工具和浏览器插件,简单场景下确实能用,但局限性很明显。免费的通常有数量限制,每天只能导几篇;收费的工具格式固定,导出的样式是别人定好的,不能按自己的需求调整;更重要的是,在线工具需要把公众号链接复制过去,遇到批量抓取几十个账号的时候就非常低效。

我自己也尝试过纯手工方式,也就是直接在PC端微信里一篇文章一篇文章地复制粘贴,再统一排版,但效率太低了。整理一百篇文章可能要花一整天,而且复制过来的图片链接经过防盗链处理后经常无法显示。最终我决定自建一套半自动化的采集系统,核心思路是:借助PC端微信登录后的会话数据拿到公众号列表接口的参数,用Python脚本定时抓取,然后做数据清洗和批量导出。这样既能绕过内容平台对第三方登录的种种限制,又能完全掌控数据格式,归档效率大幅提升。

2. 核心设计拆解:登录态、列表接口与正文解析

2.1 登录态与Cookie维护

公众号后台和微信客户端内部有一套完整的内容分发接口,其中最关键的是“公众号文章列表”接口,这类接口通常需要携带有效的身份凭证才能访问,一般表现为Cookie或Token。自建采集系统的第一关,就是拿到一个稳定可用的登录态。

我在实际开发中选用的是PC端微信的网页调试方式:在电脑上登录微信,打开某篇公众号文章,通过抓包工具观察请求,就能看到文章列表接口的请求参数和Cookie。把这个Cookie抽出来,放到采集脚本的请求头里,就能以当前微信账号的身份去请求指定公众号的历史文章列表。这里有一个容易被忽略的细节:Cookie有有效期,可能几小时也可能几天,取决于账号活跃度和操作频率。建议把Cookie保存在独立的配置文件中,脚本启动时读取,过期时重新抓包更新,不要写死在代码里,否则每换一次环境都要改代码。

另一个关键是User-Agent和Referer头。微信接口虽然不像普通网站那样严格校验User-Agent,但为了减少风控误伤,最好保持和PC端微信一致的浏览器标识。Referer字段通常要指到公众号的某篇文章页或主页,否则部分接口可能返回异常数据。我自己是把所有请求头都封装成了一个独立函数,抓包一次后统一配置,后续脚本只负责调函数,省心很多。

提示:微信的登录凭证属于个人敏感信息,任何情况下都不要把Cookie明文提交到公共代码仓库。建议用环境变量或者本地配置文件管理,并加入.gitignore忽略规则。

2.2 列表接口与数据字段

公众号文章列表的接口地址在不同版本下会有变化,但核心逻辑一致:传入账号标识fakeid和分页偏移量offset,返回该账号下历史文章的JSON数据。这里面的fakeid可以从公众号主页或会话列表请求里解析出来,通常是profile页面返回的一串加密字符串。

列表返回的数据里,每条文章记录一般包含这些核心字段:

  • title:文章标题
  • digest:摘要
  • link:文章详情页链接
  • update_time:发布时间戳
  • cover:封面图地址
  • publish_time:有时候会单独返回发布时间相关字段

如果只看列表不抓正文,系统就只能算一个索引工具,离“导出系统”还差很远。所以在拿到列表之后,还需要遍历每篇文章的link,进入详情页解析正文。这里需要注意:详情页的内容是HTML格式,直接存下来会出现大量无用标签、内联样式和动态加载的脚本,必须做HTML清洗,提取正文核心内容。

2.3 正文HTML清洗与图片处理

公众号文章的正文HTML总体比较规整,但夹杂了大量的<section>、<p>、<span>以及各种内联样式。如果直接保存,导出的Markdown或PDF会非常凌乱。我采取的方案是先用Python的BeautifulSoup或lxml解析HTML,按正文容器定位(一般是id="js_content"的节点),再递归去除脚本、样式标签和空节点,提取纯文本的同时保留必要的段落和图片引用。

图片处理是另一个大坑。公众号正文里的图片默认使用mmbiz.qpic.cn域名,这些图片在外部网络环境直接访问时需要附带正确的Referer,否则很容易出现防盗链拦截。采集时最好统一把图片下载到本地目录,并把正文里的图片链接替换成相对路径。这样导出的Markdown、PDF或HTML即便脱离网络也能完整显示图片。下载图片时建议设置合理的超时时间(比如15秒),并针对下载失败的内容做重试机制。

3. 实操落地:环境准备与关键代码实现

3.1 环境准备:依赖安装与目录规划

项目落地前,先把Python环境装好。我本机用的Python 3.10,依赖库清单如下:

pip install requests beautifulsoup4 lxml markdown pdfkit python-docx

这几个库的作用分别是:requests处理HTTP请求,BeautifulSoup4加lxml解析HTML,markdown把清洗后的内容转成Markdown,pdfkit负责把HTML转PDF,python-docx用来生成Word文档。如果需要把Markdown进一步转成带样式的HTML,可以再加一个markdown扩展插件。

目录结构我通常这样规划:

wechat_archiver/ ├── config/ │ ├── cookies.json │ └── target_accounts.txt ├── download/ │ └── images/ ├── output/ │ ├── html/ │ ├── markdown/ │ ├── pdf/ │ └── word/ ├── scripts/ │ ├── fetch_list.py │ ├── fetch_article.py │ ├── parse_content.py │ └── export.py └── logs/

配置文件单独放,方便多环境切换;下载的图片和输出文件分开管理,方便后续打包备份;日志目录用来记录每次采集的结果,排查问题时非常有用。

3.2 核心采集流程:列表分页与文章详情请求

先实现列表分页抓取。公众号列表接口一次最多返回一定数量的文章,通常需要多次请求,每次把偏移量累加,直到返回的数据条数为空才停止。以下是核心逻辑的简化示例:

import requests import json def fetch_article_list(session, fakeid, offset=0, count=10): url = "https://mp.weixin.qq.com/cgi-bin/appmsg" params = { "action": "list_ex", "begin": offset, "count": count, "fakeid": fakeid, "type": "9", # 9表示图文消息 "query": "", "token": session.token, "lang": "zh_CN", "f": "json", "ajax": "1", } headers = { "User-Agent": session.user_agent, "Referer": "https://mp.weixin.qq.com/", "Cookie": session.cookie_str, } resp = requests.get(url, params=params, headers=headers, timeout=20) data = resp.json() if data.get("ret") == 0: return data.get("app_msg_list", []), data.get("app_msg_cnt", 0) else: return [], 0

这里有几个参数需要说明一下。fakeid是公众号的数字标识,type=9表示抓取图文类型,count是单次请求数量,建议不超过10,太大容易触发风控。token字段在公众平台的请求里经常出现,它不是Cookie本身,而是和Cookie联动的一个参数,一般从Cookie中解析出来。

拿到文章列表后,对每一篇的link发起详情请求,再用parse_content.py里的清洗逻辑提取正文。详情页的响应通常是完整HTML,我建议不要直接用正则去抠内容,因为公众号编辑器会生成各种奇怪的嵌套结构,正则很容易漏。用BeautifulSoup按id="js_content"定位正文容器最稳妥。

3.3 批量导出:从Markdown到PDF、Word

清洗并保存好文章正文后,导出环节才是真正体现“系统”价值的地方。我默认会把每篇文章同时存一份Markdown和一份HTML,然后按需批量生成PDF或Word。

Markdown格式适合自己用编辑器阅读、做知识库索引;HTML格式适合快速预览和线上分享;PDF和Word主要给同事或客户交付。导出PDF时,我用的方案是先把正文塞到一个带基本样式的HTML模板里,再用pdfkit调用本地安装的wkhtmltopdf来渲染。这里有个坑:如果本机没有安装wkhtmltopdf,直接调用会报错。安装时要注意把可执行文件的路径加到系统PATH里,否则pdfkit找不到程序。

import pdfkit options = { "encoding": "UTF-8", "page-size": "A4", "margin-top": "15mm", "margin-bottom": "15mm", "margin-left": "15mm", "margin-right": "15mm", "enable-local-file-access": "", } html_content = f""" <html> <head><meta charset="utf-8"></head> <body> <h1>{article['title']}</h1> <p class="meta">作者:{article['author']} | 发布时间:{article['publish_time']}</p> <hr> {article['content_html']} </body> </html> """ pdfkit.from_string(html_content, output_path, options=options)

导出Word相对简单,python-docx可以逐段添加标题和正文段落。需要注意图片的插入方式:本地图片路径必须真实存在,跑批量导出时最好先检查图片是否下载完整,否则生成的Word文档会缺图。

3.4 增量抓取与断点续传

全量抓取第一次跑完之后,后续再抓同一批账号,就只需要关心新增文章,没必要重新抓全量。我的做法是在本地维护一个简单的数据库文件,记录已抓取文章链接的哈希值。每次列表请求返回后,先检查链接是否在库里,已经在库里的直接跳过,新的再进入详情抓取和导出流程。

import hashlib import json def is_duplicate(article_url, seen_path="seen.json"): url_hash = hashlib.md5(article_url.encode("utf-8")).hexdigest() try: with open(seen_path, "r", encoding="utf-8") as f: seen = json.load(f) except FileNotFoundError: seen = {} if seen.get(url_hash): return True seen[url_hash] = True with open(seen_path, "w", encoding="utf-8") as f: json.dump(seen, f, ensure_ascii=False, indent=2) return False

这样每次跑完一批,就只更新增量部分,耗时从全量的几十分钟降到几分钟。另外,断点续传也很重要,尤其是文章数量达到几百上千篇时,中间可能因为网络波动、风控拦截导致脚本中断。我每次抓取的文章链接和成功状态都会实时写入日志,脚本重启后可以直接从日志中最新的成功位置继续,不用从头开始。

4. 排障实录:常见问题与解决办法

4.1 文章列表接口返回空数据

抓包时接口正常,但脚本跑起来却经常拿不到数据,这种问题我遇到过好几次。首先要确认fakeid是不是有效的,公众号主页的fakeid有时候会包含URL编码,直接复制到参数里可能出错。其次要检查Cookie是否过期,接口返回的JSON里ret字段如果是非零值,大概率是凭证失效,重新抓包更新Cookie即可。

还有一个容易忽略的点:请求的User-Agent和Referer必须和抓包时一致,尤其是Referer。如果列表接口要求必须从公众号主页或某篇文章页跳转进入,而你的脚本里缺失了这个头部,服务端可能直接拒绝返回数据。我在代码里专门封装了一个make_headers函数,把Referer集中管理,排查问题时可以快速切换。

4.2 登录态频繁失效

Cookie隔几个小时就失效,是采集系统最大的痛点。我在实践中发现,频繁请求接口或者短时间内并发太多,会加速Cookie失效。建议控制请求频率,抓完一篇文章后间隔2到5秒再抓下一篇,模拟真实浏览节奏。另一方面,不要在采集当天反复重新登录微信网页端,登录状态一旦改变,之前的Cookie就全部作废。

如果Cookie还是频繁失效,可以考虑把关键账号的采集任务分散到不同时间段执行,比如每个小时跑一批,而不是一口气全部跑完。这样既能降低风控风险,也能让采集系统的整体稳定性明显提升。

4.3 图片下载失败与防盗链

图片下载失败最典型的原因就是防盗链。直接使用requests.get请求图片URL时,如果请求头里没有带正确的Referer,微信的图片服务器很可能返回403。解决方案是在下载图片时也带上文章页的Referer。另外,某些历史文章的图片可能已经被源站清除,下载时会返回404,这部分需要跳过并在日志里记录,不要因为一张图失败就终止整个任务。

def download_image(img_url, save_path, referer): headers = { "User-Agent": "Mozilla/5.0 ...", "Referer": referer, } 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) else: raise RuntimeError(f"download failed: {resp.status_code}")

4.4 导出PDF或者Word时遇到样式错乱

经常出现的情况是:Markdown里看内容是正常的,但转成PDF后段落间距异常、代码块底色丢失,或者中文字体之间出现多余空格。原因多半是HTML模板里的CSS样式不够完善,比如没有设置font-family,导致wkhtmltopdf用了默认英文字体来渲染中文。建议在HTML模板里显式加入中文字体配置,比如微软雅黑、思源黑体,并且对正文、图片、引用、代码块都定义好基础样式。Word版本如果图片错位,通常是因为文章里有多个图片并列,python-docx默认按顺序插入,没有处理浮动布局,解决办法是统一把图片设置为居中显示,并限制最大宽度。

5. 合规边界与长期维护建议

5.1 合规注意事项

做数据采集,合规这根弦一定要绷紧。公众号文章虽然内容公开,但版权仍然属于原作者。自建采集导出系统,建议仅用于个人备份、学习研究、内部分析等合法用途,不要将采集到的内容批量打包后公开传播,更不要用于商业牟利。尤其是涉及付费专栏、原创声明、授权转载等内容的文章,使用时必须尊重原作者权利。

另外,采集行为本身要控制在合理频率内,不要对目标平台造成明显压力。平台有风控机制是正常的,作为采集方更应该有自律意识,控制并发数,做好限速,避免给他人和自己的账号带来不必要的风险。

5.2 长期维护建议

这套系统不是一次性开发完就万事大吉,它本质上是一个需要长期维护的数据管线。我自己的维护节奏是这样的:每周检查一次Cookie是否失效,每个月抽查几篇文章确认正文解析规则仍然正确,每次微信客户端升级后观察抓包结果是否有变化。如果正文结构出现新的嵌套标签,不需要重写解析器,只要往清洗规则里补充对应的节点处理逻辑就行。

日志是维护系统最重要的辅助手段。每次采集任务的开始时间、结束时间、成功文章数、失败原因都应该记录下来,方便回溯。我还加了一个简单的数据统计脚本,每周输出一次采集总量和成功率,低于某个阈值时自动排查接口是否变更,这样做能让你对系统状态心中有数,不至于等到内容断更才发现问题。

最后分享一个我自己总结的小原则:能用配置文件解决的问题,就不要写死在代码里;能增量采集的地方,就不要每次全量跑。这套系统跑了大半年,整体稳定,偶发问题基本集中在登录态变化上,提前做好Cookie更新和异常告警,比什么都重要。如果你也在规划类似的内容归档工具,建议先跑通一个公众号的完整流程,再逐步扩展到批量账号,这样磨出来的系统会扎实很多。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询