资讯动态

用Python爬虫采集微信公众号阅读数和点赞数:从抓包到实战

发布时间:2026/10/3 3:16:46 来源:尧图企业网站定制
做公众号数据分析的时候我最大的痛点就是手动统计阅读数和点赞数。尤其是一篇文章发出去之后每隔一段时间就要打开页面看一眼数据几篇文章还好几十篇复盘下来整个人都是晕的。后来我直接用Python爬虫把微信公众号文章的阅读数、点赞数抓下来整个过程从打开编辑器到看到结果5分钟都用不上。这篇文章就把我实际在用的这套抓取方案完整拆开讲清楚从抓包分析到最终代码都会给到适合手里有Python基础、正在做公众号运营或自媒体数据复盘的朋友直接参考。先说结论微信文章页面里的阅读数和点赞数并不是写死在HTML源代码里的而是页面加载完成后通过一个内部接口取回来的。所以网上很多“直接解析HTML”的教程在抓文章标题、正文时没问题但一旦想拿阅读数、点赞数就会扑空。真正靠谱的做法是模拟浏览器的请求逻辑先访问文章页面从页面里提取参数再调用微信的数据接口拿到JSON格式的数据。下面我按我当时的排查顺序从头到尾把这条链路拆给你看。1. 项目需求与整体思路1.1 为什么阅读数、点赞数无法直接解析HTML我最早也走过弯路拿到一篇文章链接后直接用requests把网页源代码拉下来然后用正则去匹配“阅读数”“点赞数”这类关键词结果搜了半天只找到个位数匹配大部分页面连“阅读”两个字都搜不到几个更别说数字了。后来打开浏览器开发者工具才发现文章页面的数字区域在初始HTML里基本是个空壳真正的数据是页面加载完成后前端脚本再去请求一个接口拿到结果后渲染上去的。这一点可以用个生活里的例子来理解你去餐厅吃饭菜单上会印着每道菜的菜名和价格但“今天这道菜卖出多少份”这种经营数据菜单上不会有你得去问服务员。这里的“菜单”就是文章HTML“服务员”就是微信内部的数据接口。想拿到阅读数、点赞数不能只看菜单得找到服务员。所以项目的核心思路就变成了两步第一步拿到文章页面的HTML第二步从HTML中找出接口需要的关键参数然后主动去调用那个接口。只要接口返回正常阅读数、点赞数、甚至发布时间、封面图这些字段都能一并拿到。1.2 两种常见方案的对比与选型在确定技术路径之前我简单对比过两种主流方案。第一种是直接解析HTML用正则或者XPath去页面里找数据。优点是实现最简单不需要额外接口代码也就十几行。缺点是拿不到阅读数和点赞数因为这两个数字是异步加载的。当然如果你只是想抓文章标题、作者、正文内容那这个方案完全够用。第二种是调用微信文章数据接口也就是mp.weixin.qq.com/mp/getappmsgext这个地址。优点是返回的数据结构化程度很高阅读数、点赞数、在看数都分得很清楚而且数据准确不需要自己做任何估算。缺点是要先从HTML里解析出几个签名参数并且这些参数有时效性过期之后需要重新访问文章页面获取。我把两个方案放在一起对比了一下对比项直接解析HTML调用getappmsgext接口数据完整性只能拿到页面静态内容阅读数、点赞数、在看数等都有阅读数/点赞数拿不到可以拿到实现难度低中等稳定性受页面结构变化影响受接口参数变化影响速度快快多一次请求最终我选了调用接口的方案因为没有这个接口整个项目就失去了意义。虽然参数解析看起来多了一步但换来的是准确可靠的数据这笔账怎么算都划算。1.3 项目最终技术路径选型确定之后整体链路就很清晰了一共六步准备一条公众号文章的链接格式通常是https://mp.weixin.qq.com/s/xxxx。用requests请求这个链接拿到网页HTML。用正则表达式从HTML中提取__biz、appmsg_token、mid、idx、sn这几个关键的请求参数。拼接出getappmsgext接口的完整URL并携带必要的请求头。发起请求拿到JSON数据。从JSON中解析appmsgstat字段读出read_num阅读数和like_num点赞数。整条链路里最核心的技术点就是搞清楚这几个参数分别代表什么、从哪里提取这也是我下一节要重点讲的内容。2. 抓包解析找出真正的数据接口2.1 在浏览器中定位文章数据请求如果你想把微信文章数据接口彻底搞明白最快的方式不是去看别人的代码而是自己动手抓一次包。我建议你不要跳过这一步因为微信前端的参数偶尔会调整亲手抓一次包后续遇到参数对不上的时候才知道去哪里排查。具体操作很简单用电脑浏览器打开任意一篇公众号文章按F12打开开发者工具切到Network面板然后刷新页面。接着在Network的过滤框里输入getappmsgext你会看到一个以这个名字开头的请求。点开这个请求先看Preview标签页里面就是接口返回的JSON数据展开appmsgstat节点能看到read_num和like_num这两个就是我们要的东西。看到这个接口之后再切到Headers标签页往下翻到Query String Parameters里面就是接口调用时携带的所有参数。你做抓包分析时重点就是看这一串参数弄清楚哪些是页面里动态生成的哪些是可以直接写死的。我当时第一次看到那十几个参数的时候也愣了一下但拆开看之后发现真正需要从页面提取的其实只有五个左右其他都是固定值。2.2 关键参数从哪来接口参数很多但真正决定请求能否成功的核心参数掰着手指头数也就这几个__biz公众号的唯一标识是一段经过处理的字符串在文章HTML源码里能直接搜到通常出现在var biz xxxx这种格式的代码里。mid文章所属素材的ID同样在HTML源码中格式一般是var mid xxxx。idx文章在当天推送中的序号比如当天第一篇是1第二篇是2可以理解为文章在那一批推送里的位置编号。sn文章的签名参数也可以理解为文章正文的唯一标识在HTML源码里同样能找到。appmsg_token访问文章的令牌这是接口校验的关键参数从页面HTML中通过正则就能提取到但它有一定时效性长期不用会失效每次使用前重新请求一次文章页面即可。除了上面这几个还有一些固定参数比如fjson、x50、wx_header1、appmsg_type9这些直接写死在代码里就行。另外还有一个rand参数是用来防止请求重复的随机数用random.random()生成即可。很多初学者看到参数多就害怕其实绝大部分参数都是固定值真正需要动态获取的就那几个理清楚之后代码写起来非常快。2.3 返回数据长什么样接口返回的数据是标准JSON去掉无关字段之后核心部分长这样{ appmsgstat: { read_num: 12345, old_read_num: 12200, like_num: 67, old_like_num: 60 }, appmsgid: 123456789, base_resp: { err_msg: ok, ret: 0 } }其中read_num是当前的阅读数like_num是当前的点赞数两个带old_前缀的字段是此前某个统计节点的旧数据一般我们用不到。base_resp里如果ret等于0说明请求成功如果不是0就要结合错误码去排查。有一点需要提醒你微信接口的返回字段偶尔会调整比如历史上就曾改动过点赞和“在看”的展示逻辑所以你在实际抓包时看到的字段名可能和我这里写的不完全一样。遇到这种情况不要慌以自己抓包看到的JSON为准微调一下解析代码就行。3. 完整代码实现与关键细节3.1 环境准备与依赖在写代码之前先把环境准备好。Python版本建议3.8以上我用的是3.10整个项目只需要一个第三方库就是requests用来发HTTP请求。安装代码就一行pip install requests如果你是在国内网络环境下使用而且默认源下载速度很慢可以临时指定清华镜像源来加速pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple除了这个库之外不需要额外安装其他东西也不需要selenium、不需要浏览器驱动因为整个抓取过程都是直接通过HTTP请求完成的速度很快这也是用requests方案最舒服的地方。正则表达式用的是Python自带的re模块不需要额外安装。3.2 核心代码提取参数并请求接口下面是完整的核心代码我已经把注释写得很详细你复制下来之后只需要替换最后一行的文章链接就能直接运行。import requests import re import random def get_article_stats(url): 根据公众号文章链接抓取该文章的阅读数和点赞数。 # 创建会话保持请求状态一致 session requests.Session() # 基础请求头模拟浏览器访问 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: url, } # 第一步请求文章页面拿HTML resp session.get(url, headersheaders) resp.encoding utf-8 html resp.text # 第二步用正则从HTML中提取接口所需的动态参数 biz re.search(rvar biz ([^]), html).group(1) appmsg_token re.search(rvar appmsg_token ([^]), html).group(1) mid re.search(rvar mid ([^]), html).group(1) idx re.search(rvar idx ([^]), html).group(1) sn re.search(rvar sn ([^]), html).group(1) # 第三步拼接数据接口地址 api_url https://mp.weixin.qq.com/mp/getappmsgext # 请求参数 params { __biz: biz, appmsg_type: 9, mid: mid, idx: idx, sn: sn, version: 26070303, f: json, x5: 0, wx_header: 1, appmsg_token: appmsg_token, rand: random.random(), } # 请求数据接口 api_headers { User-Agent: headers[User-Agent], Referer: url, } data_json session.get(api_url, paramsparams, headersapi_headers).json() # 解析返回结果 if data_json.get(base_resp, {}).get(ret) 0: stat data_json[appmsgstat] return { read_num: stat[read_num], like_num: stat[like_num], } else: print(请求失败返回内容, data_json) return None if __name__ __main__: article_url https://mp.weixin.qq.com/s/你的文章链接 result get_article_stats(article_url) print(result)这段代码的逻辑不复杂核心就是把我们刚才在抓包分析里看到的流程完整复现了一遍先访问文章页面提取参数再请求数据接口最后解析JSON。如果一切正常你运行后会在控制台看到类似这样的输出{read_num: 12345, like_num: 67}3.3 5分钟快速运行指南我知道很多人拿到代码后最关心的问题就是怎么在最短时间内跑起来我按时间线给你拆一下总共五步每一步都不复杂。第1分钟确认本机已安装Python 3.8以上版本。在命令行执行python --version就能看到版本号。如果没有安装先去官网下载对应系统的安装包装的时候记得勾选“Add Python to PATH”。第2分钟安装依赖库。执行pip install requests如果已经装过这一步可以直接跳过。第3分钟把上面的完整代码保存成一个文件随便起个名字比如wechat_stats.py。然后打开文件把最后一行的文章链接替换成你自己的公众号文章链接。注意链接必须是以https://mp.weixin.qq.com/s/开头的标准文章链接如果是短链接或者从其他渠道复制的链接建议先在浏览器里打开一次再复制地址栏里的完整地址。第4分钟在命令行执行python wechat_stats.py。如果报错先看是不是链接没替换、库没安装或者Python环境有问题。第5分钟看到输出结果。只要不报错基本上几秒内就能拿到阅读数和点赞数。3.4 多篇文章批量抓取扩展单篇抓取跑通之后你大概率会遇到批量抓取的需求比如要复盘一个公众号最近一个月发的所有文章。这时候可以把所有文章链接放在一个txt文件里每行一条然后循环调用上面的函数。批量代码也很简单我在实际项目里是这么写的import time with open(article_urls.txt, r, encodingutf-8) as f: urls [line.strip() for line in f if line.strip()] for url in urls: result get_article_stats(url) print(url, result) time.sleep(2) # 每抓一篇休息2秒降低请求频率这里有一个非常重要的细节每个循环之间必须加sleep哪怕只是1秒也好。不加sleep直接100篇文章连续请求很容易触发平台的风控机制。我自己的经验是批量抓取时每篇间隔2秒以上抓二三十篇基本没问题。4. 常见问题排查与避坑技巧4.1 高频报错与解决方案速查这个项目虽然代码量不大但实际跑起来之后新手容易踩的坑还真不少。我把自己遇到过的、以及身边朋友问过的高频问题整理成了一张速查表建议收藏备用。问题现象可能原因解决方案正则匹配不到参数报AttributeError页面结构发生变化变量名对不上打开文章源码搜索var biz、var mid等关键词按实际格式修改正则接口返回ret不等于0appmsg_token过期或参数不完整重新请求一次文章页面刷新appmsg_token后再试请求超时或返回空白网络波动或触发频率限制稍等几分钟再试不要连续高频请求阅读数一直等于旧值接口返回了old_read_num解析时用read_num字段不要用old_read_num提示“环境异常”被拦截请求头不完整被识别为脚本检查User-Agent和Referer是否设置正确这里面最常出问题的就是第一行正则匹配不到参数。因为公众号前端代码是可能更新的半年前我写的正则是var biz ...后来有一段时间页面里变成了var biz ...单双引号都出过。所以我的建议是如果匹配报错先不要在代码层面反复试而是直接把HTML源码拉下来用编辑器的搜索功能搜一下biz、mid这些关键词看到实际长什么样再回头改正则效率最高。4.2 容易被忽略的三个细节第一个细节是Referer。很多人代码写完之后直接请求接口结果发现返回异常但明明所有参数都从页面里提取了。原因往往是接口请求时没有带Referer或者Referer指向了别的地址。微信对这个字段校验得很严格它得像“我从这篇文章页面跳转过来”一样指向原文地址。这一点我刚开始也栽过后来在浏览器抓包里对比了一下才反应过来。第二个细节是文章链接的格式。从公众号历史消息或者第三方平台复制出来的链接有时候不是标准的mp.weixin.qq.com/s/格式可能是带了一堆追踪参数的长链接甚至可能是跳转链接。我的习惯是先把链接在浏览器里打开一次等页面跳转稳定后再复制地址栏里的最终地址作为抓取入口。第三个细节是Cookie。大多数普通文章不需要登录也能拿到数据但极少数情况下尤其是企业主体公众号或部分转载文章接口会要求带Cookie才能正常返回。如果你发现参数全对、Referer也对但接口仍然报错可以在浏览器里登录一下微信然后把Cookie复制到代码里放到请求头中再试一次。4.3 频率控制与运行稳定性关于请求频率我想多啰嗦几句。虽然技术上我们可以做到一秒请求十几次但完全没有必要而且后果可能很严重。一次大规模的并发抓取不仅可能导致你的IP被临时限制访问公众号文章页面还会给目标服务器带来不必要的压力。这个项目本质上是用于个人数据分析和学习研究的不是用来搞轮询监控的所以一定要克制。我自己的稳定运行策略是单篇抓取随意批量抓取时每篇间隔2秒到3秒一个批次的文章数量控制在50篇以内抓完一批之后如果还要继续就休息几分钟再开始。这种节奏下我连续用了很长时间没有出现过被限制访问的情况。如果你需要抓的量大也可以考虑用多账号轮换的方式但这就涉及更多的账号安全问题我个人不建议个人项目这么折腾。5. 合规边界与使用建议5.1 明确哪些操作容易踩线聊完技术必须把合规的事情说清楚。虽然阅读数和点赞数是展示在文章页面上的公开数据但这并不意味着可以无限度地采集和使用。以下两类操作是我强烈不建议的。第一类是在代码里尝试绕过反爬机制比如主动破解签名算法、伪造加密参数、大规模轮换IP等。这些行为已经明显超出了“正常浏览”的范畴一旦被识别轻则IP受限重则可能影响账号安全。我们写爬虫的初衷是为了提高工作效率不是为了和平台对抗。第二类是恶意高频抓取尤其是不加任何时间间隔地循环请求一秒钟打几十个请求上去。这种做法的目的通常是批量监控或者数据倒卖无论从哪个角度看都不合适。我们做数据分析要的是稳定可靠的数据来源而不是一次性的疯狂抓取。所以我建议使用这个脚本时只用来处理你自己能正常打开阅读的文章只抓取你实际需要的数据量不扩散、不滥用。5.2 数据使用的合理场景说了那么多限制那这个脚本到底适合用在哪些场景呢我根据自己的经验总结了几类。第一类是公众号内容复盘。很多做自媒体的人都会遇到这个问题后台只能看到自己账号的详细数据想看自己某篇文章在朋友圈的传播效果还是在文章页面看阅读数和点赞数最直观。这个脚本可以把历史文章的阅读数据快速整理成表格省去手动记录的痛苦。第二类是竞品公开数据的大致趋势观察。你可以把自己关注的同行公众号文章链接收集起来定期抓一次阅读数和点赞数观察内容方向和数据表现之间的关系。注意这里是“大致观察”不是让你去搭建一个全天候的竞品监控系统量级上一定要控制住。第三类是技术学习。这个项目本身就是一个很好的爬虫练手案例它涉及了请求模拟、参数提取、接口调用、JSON解析等一系列基础技能代码量又不大非常适合刚入门爬虫的朋友拿来拆解学习。我个人的体会是把这套脚本用在“自己的数据”和“少量公开数据”上它就是一个高效的小工具如果贪心把它用在“大量抓取”和“越权操作”上它就会变成一个烫手山芋。边界始终在心里技术本身没有对错但怎么用完全取决于我们自己。最后再分享一个我踩过多次坑之后养成的习惯每次在大规模抓取之前我会先用一篇文章测试一下接口是否正常确认返回的ret是0之后再批量跑。这个小习惯帮我省了不少时间因为公众号前端的参数偶发调整一旦你闷头跑了几十篇才发现参数已经过期前面所有请求都是白费的。希望这个脚本也能成为你日常运营和数据复盘里的一个趁手工具。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑