Python微信公众号爬虫实战:从抓包到数据落库的完整方案 简介面向微信公众号文章采集需求的爬虫实践资源适合有基础编程知识、希望批量获取公众号所有文章链接的开发者与数据分析人员。资源围绕微信公众号平台文章链接获取展开讲解从登录凭证取得、请求接口、解析参数到输出结果的一整套流程可用于内容归档、传播分析、学术研究等方向。压缩包共三十个文件以十三个Python脚本为核心分别处理文章地址提取、文章信息读取、接口调用封装等任务另附五份Markdown文档说明微信参数获取与常用接口的使用细节并用多张图片截图辅助理解还带有浏览器驱动及配置文件整体十七点二二MB目录结构清晰。目前已有五百八十人学习浏览借助配套文档可快速完成环境搭建与脚本调试模块化设计也方便按需修改扩展为定制化采集工具。 说句实话但凡接触过公众号数据分析的人迟早都会走到爬虫这一步。公众号文章不像普通网页那样有清晰的静态HTML也不提供公开的聚合接口想拿到历史文章列表、正文、评论数据就得在官方限制和个人研究需求之间找一条能走通的路。这个项目标题是“Python-微信公众号的爬虫”核心关键词就三个Python、微信公众号、爬虫。Python只是工具真正的难点在于弄懂公众号数据从哪来、怎么拿、拿到后怎么解析——这才是整个项目最花时间的地方。这篇文章我打算按自己实际做过的方案来写先讲清楚公众号数据获取的几条路线再对比为什么选PC端抓包这条路然后从环境准备、核心字段解析、请求流程、正文提取、缓存解析到常见问题排查一步步展开。适合的人很明确想用Python拉取公众号文章做数据分析、知识库构建、内容监控的开发者刚入门爬虫、但对微信公众号这种“半封闭”场景感兴趣的人也能从中找到一条可以落地的完整链路。1. 先搞懂数据从哪里来四条可行的路线网上聊公众号爬虫方案五花八门但真正能用的核心路线其实是固定的四条。我一开始也踩过不少弯路总觉得“官方有接口但权限不够那就找别的入口”结果每条路都有自己的坑。这里先把四条路线讲清楚后面再展开最稳的实操方案。1.1 官方接口路线权限门槛比想象中高微信公众平台官方提供了内容管理接口但注意这个接口不是给爬虫用的。它面向的是公众号运营者本人要求你拥有公众号后台权限而且仅仅能拉取自己账号的历史文章列表和各项统计数据。想通过微信开放平台接口去抓别人的公众号文章基本是行不通的权限模型里就没有这个授权方向。所以如果你研究的是“爬取任意公众号文章”官方接口这条路可以先放一边。1.2 搜狗微信搜索路线入口公开但限制太多搜狗有一个“搜狗微信搜索”按公众号名称或者文章标题可以搜到部分公众号内容。这个入口的好处是不需要登录、不需要任何微信身份直接requests请求就行。坏处也很明显反爬机制非常严格经常让人“验证码”拦下来而且搜到的文章不全、有时效性只覆盖最近一段时间的部分内容不是完整历史库。适合小批量、低频率地搜某篇文章是否被收录不适合做系统性采集。1.3 PC端代理抓包路线多数个人项目的首选这是我个人强烈推荐的一条路。微信PC客户端在Windows上会持续接收公众号消息当你点开一个公众号的历史消息列表时客户端会向微信服务器发起一个真正的JSON接口请求。如果我们在PC上配置一个本地代理比如mitmproxy就能截获这个请求拿到接口地址、请求参数和返回数据。基于这些数据你可以用Python模拟客户端继续请求历史列表从而实现“翻页读取”覆盖一个公众号的大部分历史文章。1.4 本地缓存解析路线适合做存量数据恢复微信PC客户端会缓存已加载过的公众号文章文章内容、封面图、摘要都可能落在本地数据库文件中。如果你只是想恢复自己账号“曾经浏览过”的文章内容解析本地缓存是最直接的办法不需要联网请求接口。但它的局限在于你只能拿到这个客户端“看过”的公众号内容无法自由扩展到一个全新公众号的全部历史文章。四条路放一起对比路线数据完整性破解难度防封风险适用范围官方接口仅限本账号低低自己公众号的数据统计搜狗微信搜索部分且滞后中高单篇临时搜索、验证收录PC端代理抓包高可翻页中中抓取任意公众号历史文章本地缓存解析仅限已浏览中无恢复浏览过的存量内容整体看下来PC端代理抓包是性价比最高的方案后面两章按这个路线展开。2. 环境准备与核心工具选型实战之前先确认环境。这个项目的技术栈很清晰Python 3.8以上 requests mitmproxy 数据库存储工具。下面把每一个工具的必要性和选型理由说清楚避免你装了一堆用不上的库。2.1 Python环境与依赖库如果你机器上还没有Python建议直接装Anaconda或者从Python官网下载安装包勾选“Add Python to PATH”。装完之后用pip安装几个关键库pip install requests pip install mitmproxy pip install pyquery pip install sqlite3 # 标准库自带的sqlite3模块一般不用额外安装requests是发HTTP请求用的三个核心能力用得上Session会话保持自动携带cookie、自定义Header、超时重试。pyquery用于解析文章正文里的HTML比正则表达式好维护得多。sqlite3用于本地存储抓取结果结构化数据直接落表。2.2 Windows上定位微信客户端缓存目录这个在热词里几乎每个月都有人问微信PC客户端的公众号推送缓存在哪里答案是它不是固定不变的不同版本差异较大。最常见的路径是C:\Users\你的用户名\Documents\WeChat Files\你的微信号\SNS\如果你的微信版本比较新可能在“FileStorage”目录下或者是“Applet”相关的子目录。更省力的方式是用Everything搜索工具直接搜“SNS”或“FileStorage”关键字按最近修改时间排序最后修改的数据库文件就是当前正在写入的缓存库。注意这个路径下可能有多个账号的目录需要先通过文件修改时间确定当前登录的微信号。2.3 mitmproxy的安装与启动mitmproxy是一个开源的中间人代理工具它可以在本机启动一个代理端口捕获本机进程发出的HTTP/HTTPS请求。正因为微信PC客户端走的是HTTPS所以我们首先要让mitmproxy拿到SSL加解密的能力运行一次mitmweb把mitmproxy的根证书安装到Windows系统“受信任的根证书颁发机构”中这样微信客户端请求HTTPS接口时数据包就能被本地代理正常解密。启动命令很简单mitmweb -p 8080 -w flows.mitm其中-p 8080指定监听端口-w flows.mitm把捕获到的流量实时写入文件方便后续离线分析。选mitmproxy而不是Fiddler或Charles关键原因是它原生支持Python脚本扩展你可以写一个addon脚本把特定接口的请求和响应自动保存成JSON。这一步直接把“抓包”和“写爬虫”衔接起来了。3. 实操从PC端抓取公众号文章列表的完整链路环境就绪后接下来就是整个项目最核心的部分拿到公众号历史文章列表的请求理解它的参数再让Python把这个流程自动化。3.1 用mitmproxy捕获历史列表请求操作步骤很简单先在Windows系统设置里开启“手动代理”地址填127.0.0.1端口填8080。然后打开微信PC客户端进入任意一个公众号的“历史消息”页面下拉刷新几次。此时切回mitmweb界面在请求列表中过滤一下重点关注请求URL中包含cgi-bin/appmsgpublish或cgi-bin/appmsg关键字的数据包。这两个接口是公众号历史文章列表的核心入口一个用于获取“发布列表”一个用于获取“文章列表数据”。找到之后把请求头、请求参数、响应JSON整体复制下来。3.2 拆解核心参数__biz与appmsg_token拿到的请求URL和参数里最关键的字段有三个__biz公众号的唯一业务标识每个公众号对应一个固定值相当于公众号在微信服务器中的身份证号。appmsg_token访问令牌由微信客户端在会话中动态生成它的有效期很短实测大约5分钟左右就会过期不能复用必须每次从新鲜请求中获取。cookie请求的凭证信息其中包含wap_sid2等关键字段。也是短时效的过期后需要重新登录微信客户端再抓一次。这里就能看出为什么“直接用requests调用接口”的方案很难长久token刷新机制太频繁了你很难凭一个“固定的cookie”长期跑。我自己常用的做法是先用mitmproxy抓一次完整请求把参数固化到本地配置然后写一个定时任务每3-4分钟重新捕获一次新token保持请求生命周期不过期。如果只是短时间跑一次脚本手工复制参数完全够用。3.3 编写文章列表请求脚本拿到token参数之后就可以写第一个真正能跑的脚本了。核心逻辑是用requests.Session把请求头补全提交POST请求解析返回的JSON。代码如下import requests import json import time # 从mitmproxy抓包结果中复制出来的固定参数 BIZ 你的__biz值 TOKEN 你的appmsg_token值 COOKIE 抓包得到的完整Cookie headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Referer: fhttps://mp.weixin.qq.com/mp/profile_ext?actionhome__biz{BIZ}, Cookie: COOKIE, } params { __biz: BIZ, appmsg_token: TOKEN, action: list_ex, begin: 0, # 分页起始位置第一次从0开始 count: 10, # 每页条数实测10条最稳定 f: json, } url https://mp.weixin.qq.com/mp/profile_ext def fetch_article_list(): resp requests.post(url, headersheaders, paramsparams, timeout10) data resp.json() if data.get(ret) 0: return data.get(general_msg_list), data.get(can_msg_continue), data.get(next_offset) else: print(请求失败返回错误码, data.get(ret), data.get(errmsg)) return None, False, None if __name__ __main__: msg_list, can_continue, next_offset fetch_article_list() if msg_list: msg_list json.loads(msg_list) for msg in msg_list.get(list, []): app_msg_list msg.get(app_msg_list, []) for article in app_msg_list: print(article.get(title), article.get(link))这段代码的关键点在第32行附近请求返回的general_msg_list默认是字符串格式必须先json.loads再遍历不然很容易栽在“明明有数据却打印不出内容”的坑上。can_msg_continue为1时表示还有下一页next_offset作为下一次请求的begin参数。3.4 翻页逻辑和正文提取翻页逻辑很简单用一个while循环就行。唯一要注意的是每次翻页的间隔建议设置在3到5秒以上别问为什么问就是太快会被微信风控返回的ret码会变成非0值。拿到文章链接后正文提取有两种方式第一种是直接用requests请求文章链接链接里已经包含__biz和idx参数返回的是完整HTML用pyquery定位div#js_content节点就能拿到正文。这种方式适合大部分文章代码量不大from pyquery import PyQuery as pq html requests.get(article_url, headersheaders).text doc pq(html) content doc(#js_content).text()第二种是直接解析文章链接中的sn参数拼请求去调用“获取文章内容”的接口。这种方式更稳定因为HTML页面里的图片加载方式可能被微信处理成懒加载直接请求接口返回的JSON会干净很多。如果遇到正文提取不全的情况优先换成接口方式。3.5 数据落库与增量更新抓取的字段至少包括文章标题、链接、摘要、封面图、发布时间、正文内容。存到sqlite里建一张表以文章链接作为唯一索引实现增量更新CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, url TEXT UNIQUE, summary TEXT, cover_img TEXT, publish_time INTEGER, content TEXT );插入时用INSERT OR IGNORE遇到重复链接直接跳过这样每次脚本只处理新增的文章比较高效。我习惯每次抓完写一个简单的统计日志打印本次新增条数和总条数方便快速核对数据有没有断层。4. 补充路线本地缓存解析的思路前面说过本地缓存解析适合恢复本机已浏览过的文章内容。这里补充两个实际会遇到的坑给需要走这条路的朋友一点参考。4.1 怎么判断缓存文件是否加密微信PC客户端的缓存数据库文件在不同版本里区别巨大。老版本里很多是明文SQLite直接用DB Browser打开就能看到表结构新版本部分数据库采用了加密格式文件名后缀仍然是db但内容已经不是标准文件头了。判断方法很简单用16进制编辑器打开文件如果文件头部是“SQLite format 3”这串ASCII就是明文库如果不是基本可以确认加密了。4.2 缓存解析需要注意的边界加密数据库的密钥一般跟当前登录账号相关不同版本提取方式不同网上也有一些开源工具做过这件事。但从数据体量和使用场景看我更推荐把本地缓存作为“辅助恢复手段”主力仍然放在抓包接口上。因为缓存库里只有你“看过”的公众号文章文章列表不全数据量完全看你的浏览历史参考价值毕竟有限。假如你只是想把个人历史浏览记录导出成自己读这条路很省事如果你要构建一个公众号内容监控系统还是要走第3章的接口方案。5. 常见问题与排查技巧实录不管方案多完整实际跑起来总会遇到各种问题。下面整理我在这个项目里遇到频率最高的几类问题按从“出现频率高到低”的顺序写。5.1 token过期和cookie失效这是最最常见的报错表现是请求返回ret: 200003或者invalid appmsg_token。pandas解法很固定重新到微信PC客户端里刷新一次公众号历史消息页面同步到mitmproxy里抓最新参数。我个人的经验是把token和cookie直接存到一个独立的配置文件里每次跑脚本前手动更新一次配合定时任务提醒比写复杂自动刷token代码更省心。5.2 返回ret非0的其它情况如果返回码不是0先对照下面这张表返回码常见原因处理办法0正常无200003访问令牌无效或过期重新抓包新token200013频率过高被限制等待10-30分钟降低请求频率1参数错误检查__biz、begin、count格式-3签名错误检查cookie是否完整、请求头是否有遗漏5.3 某些文章正文为空遇到这种情况先用浏览器打开文章链接手动验证能否正常访问。如果浏览器能打开但脚本拿不到正文大概率是页面里的懒加载机制导致的。处理方式是把pyquery的解析目标从#js_content改成rich_media_content类名或者改用文章内容JSON接口。5.4 抓取过程中被风控这一条必须认真讲。微信的风控不是看你单次请求多快而是看“行为是否符合人体操作规律”。连续翻页几十次不带停顿、单次请求间隔固定为3秒整、每天抓取同一公众号上千次这些机器行为很容易触发限制。应对策略是随机化请求间隔比如3到8秒随机、设置每天总抓取量上限、对多个公众号轮换访问而不是盯着一个号使劲刷。6. 数据边界与合法使用红线做到最后一步一定要聊一下数据使用的边界。爬虫技术本身是中性的公众号文章的内容版权依旧归属于原作者和平台。代码能把JSON请求发出去、把HTML解析干净但代码不能替你做数据合规决策。我自己的实践原则是三条第一只能把抓取到的数据用于个人学习、内容聚合阅读、非商业性质的统计分析如果要做产品需要提前确认内容的使用授权。第二抓取频率必须克制不要给目标服务器和微信后台造成压力。有人会觉得“反正接口在那里我多请求几次没事”但实际被限制之后不仅账号受影响连带着正常微信使用都会麻烦。第三公众号文章正文、图片、评论虽然可以被程序读取但再次整理发布时要尊重原创保留署名和来源链接擅自搬运、洗稿同样不可取。这几条算是给自己也给读者画一条清楚的下限保证技术能推进也不至于触线。最后说点项目实操的体会。做微信公众号爬虫最容易出现的情绪是“开头信心满满中途被token和风控磨得没脾气”。我的建议是搭一个尽量简单的工程骨架固定参数、独立配置文件、数据库表结构、日志输出这四件套先跑通不要一上来就追求“全自动无人值守”。踩过几次坑之后你会发现真正的价值不只是拿到文章数据而是你亲手理解了微信公众号这套半封闭系统的请求规律和数据结构——这套经验放到任何以“获取数据解析数据”为核心的项目里都通用。本文还有配套的精品资源点击获取