
1. 内容整体设计与思路拆解1.1 需求源头为什么偏偏是公众号文章的阅读数和点赞数做公众号运营或者自媒体数据调研的人大概率都遇到过这种场景某天老板甩过来一批竞品公众号的链接让你统计一下最近一个月每篇文章的阅读量、点赞量、在看量还强调“下班前给我”。如果文章数量只有十几篇手动复制粘贴还扛得住但当数量到了几十上百篇甚至要持续每周统计人肉操作就纯属折磨。微信公众号文章的阅读数、点赞数官方并没有开放一个公开的、无需授权的数据查询接口。你在浏览器里能看到的数字是文章页面通过内部接口渲染出来的。这意味着想拿到这些数据只能靠爬虫模拟用户的访问行为再从页面源码或接口响应里把数字解析出来。这篇文章要做的就是一套最小可用的抓取方案拿到一篇公众号文章的链接后自动抓取标题、阅读数、点赞数、在看数并把结果结构化输出。整个流程不依赖任何付费工具用 Python 加 requests 库就能跑通实测单篇耗时在5秒以内批量抓取时配合并发可以大幅缩短总时长。1.2 技术方案选型requests 还是 Selenium为什么先选 requests公众号文章页面属于典型的“服务端渲染局部动态加载”混合结构。文章标题、正文、作者、发布时间这些基础信息在 HTML 源码里直接就有但阅读数、点赞数这些互动数据是通过页面加载后发起的二次请求拿到数据以 JSON 格式返回。针对这种结构技术选型上有三条路用 Selenium 或 Playwright 这类浏览器自动化工具模拟真实用户访问整个页面等动态内容渲染完再去取值。用 requests 直接请求文章页面解析 HTML 拿到基础信息同时逆向出内部的数据接口直接请求接口拿互动数据。用第三方平台提供的现成 API付费或限量调用。我最终选了 requests 方案。原因是公众号文章页面的动态数据接口非常规整接口地址、请求参数都是固定的只要处理得当requests 的效率和稳定性远高于浏览器自动化方案。Selenium 在遇到复杂反爬时是很好的兜底但它的缺点是重、慢、耗资源——启动一个浏览器实例就要好几秒跑批量任务时对机器内存也是负担。而 requests 只要把 Header、Cookie 模拟到位单请求延迟可以控制在几百毫秒级别配合并发批量抓取时优势非常明显。注意这里说的接口模拟是指通过分析前端页面的正常网络请求用代码去模拟浏览器的行为。在实际操作中请务必只抓取自己有权访问、不涉及他人隐私和版权的内容不要对目标站点造成压力。1.3 这套方案能解决什么问题以及它的边界在哪里这套方案适合的场景我实际验证过的主要有三类第一类是自媒体运营者的“数据周报”。每周把自己账号的文章链接汇总一下跑一次脚本就能生成一张表格省去手工点开每篇文章记数字的麻烦。第二类是竞品分析。做内容方向调研时把竞品公众号近期的文章链接收集起来批量抓取阅读和点赞数据可以直观看到哪些选题数据好、哪些方向用户不买账。第三类是历史数据归档。公众号后台只能看最近一段时间的部分数据通过爬虫定期抓取并归档可以在年底复盘时拿出完整的趋势曲线。边界也要说清楚公众号文章链接分为两种一种是普通的mp.weixin.qq.com/s/xxx链接直接在浏览器里能打开另一种是带有__biz等参数的特殊链接常见于公众号菜单和历史消息页。本方案针对的是第一种普通链接也是日常分享和转发时最常见的形式。另外某些特殊场景下文章可能会被删除、设置仅粉丝可见或开启地域限制这些都会导致抓取失败代码中需要做异常兜底。2. 核心细节解析与实操要点2.1 文章页面结构拆解数据和信息分别藏在哪先花点时间把公众号文章页面的结构看清楚后面写代码才不至于两眼一抹黑。用 Chrome 打开任意一篇公众号文章按 F12 打开开发者工具切到 Network 面板刷新页面你会看到页面加载过程中发起了很多请求。其中关键的有两类第一类是页面本身的 HTML 文档请求。响应当中包含了文章的标题og:title、作者、发布时间、正文内容等信息。这些信息不需要额外接口直接从 HTML 里解析就能拿到。第二类是获取阅读数和点赞数的异步请求。在 Network 面板里筛选XHR或JS会看到某个请求的路径中包含appmsgstat或getappmsg之类的关键字。点击该请求在 Preview 或 Response 标签页里可以看到返回的 JSON 数据里面通常包含{ appmsgstat: { read_num: 12345, old_read_num: 0, like_num: 123, old_like_num: 0, friend_subscribe_num: 0, old_friend_subscribe_num: 0 } }其中read_num是阅读数like_num是点赞数。有部分文章会显示“在看”数据对应的是old_like_num或另一个字段具体看接口返回。这个 JSON 结构在不同时期有过微调所以写解析代码时最好先打印原始返回确认字段名后再写对应逻辑。为什么这个接口能直接请求到数据关键在于请求参数里带有appmsgid和idx这两个核心参数它们是从文章链接或页面源码中提取出来的相当于这篇文章在微信服务器上的唯一标识。只要这两个参数正确加上合法的请求头请求就会返回对应的统计数据。2.2 请求头模拟被拦截和不被拦截的差别就在这公众号的数据接口虽然不像电商平台那样有复杂的风控但基本的校验还是有的。其中最基础、也最关键的就是请求头里的 User-Agent 和 Referer。我在调试过程中遇到的情况是如果不带浏览器 User-Agentrequests 默认的python-requests/x.x.x会被微信服务器直接拒绝返回 403 或空数据。加上一个真实的浏览器 User-Agent 后请求基本就能通了。一段我在实际项目中常用的请求头配置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: https://mp.weixin.qq.com/, Accept: application/json, text/plain, */*, Accept-Language: zh-CN,zh;q0.9,en;q0.8, }很多初学者容易忽略 Referer。实际上微信的接口会校验请求来源如果 Referer 不是mp.weixin.qq.com域名下的页面部分接口会返回异常。为了省事我一般直接把文章链接本身作为 Referer实测兼容性最好。2.3 Cookie 与登录态什么场景必须带什么场景可以不带关于 Cookie我测试过的结论是对于普通公开文章的阅读数和点赞数接口不携带 Cookie 通常也能正常返回数据。但有一种情况例外——如果文章数据接口对未登录用户做了限制或者你的访问频率触发了风控就需要在请求中加上 Cookie 字段。获取 Cookie 的方法很简单用浏览器打开文章页面F12 打开开发者工具切换到 Network 面板随便点一个请求在 Request Headers 里找到Cookie: ...这一行复制完整值即可。不过要提醒的是Cookie 属于敏感信息它等同于你账号的部分凭证。代码里如果写死了 Cookie不要在公开仓库里直接提交建议通过环境变量或配置文件传入避免泄露。我自己写爬虫脚本时会用os.getenv(WX_COOKIE)这种方式从环境变量读取而不是把 Cookie 硬编码在代码里。安全提醒Cookie 泄露等同于账号泄露含个人信息。请仅用于自己账号有权访问的内容且不要在公开平台明文上传完整 Cookie。2.4 阅读数、点赞数与“在看”的区别很多人会疑惑点赞数就是“在看”吗其实不是。微信文章底部有三个互动数据阅读数、点赞数、在看数。早期的微信版本只有“点赞”后来改版成了“在看”再后来“点赞”和“在看”同时存在。不同时期的数据含义也不同接口返回字段里有两个like_num相关的值分别对应点赞和在看具体以接口返回为准。在抓取时建议把原始 JSON 完整保存下来而不是只挑一两个字段。原因有两个一是公众号接口字段可能调整保存原始数据方便追溯二是后续如果要分析趋势原始数据随时可以重新解析。我的习惯是每篇文章的数据存一行 JSON落盘到本地文件方便后续用 Pandas 或 Excel 做二次分析。3. 实操过程与核心环节实现3.1 环境准备Python 及相关库安装我默认你已经装好了 Python 3.7 以上的版本。如果还没装去 Python 官网下载对应系统的安装包安装时记得勾选“Add Python to PATH”否则后续在命令行里运行python会提示找不到命令。在终端里创建并激活虚拟环境然后安装依赖mkdir wechat-spider cd wechat-spider python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate pip install requests beautifulsoup4 lxml这里只用到了三个库requests负责发 HTTP 请求beautifulsoup4和lxml负责解析 HTML从页面源码里提取文章标题等基础信息。如果你只要阅读数和点赞数连beautifulsoup4都可以不装因为标题也在 HTML 的元信息里用正则也能抠出来但用解析库更稳。3.2 完整代码实现与逐段注释下面直接上完整代码。这个脚本核心流程分三步先用文章链接请求页面 HTML解析出appmsgid和idx参数然后请求数据接口获取阅读数和点赞数最后把结果按 JSON 格式输出。import requests import re import json from bs4 import BeautifulSoup # 请求头模拟真实浏览器 def get_headers(referer_urlNone): 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, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, } if referer_url: headers[Referer] referer_url else: headers[Referer] https://mp.weixin.qq.com/ return headers def extract_article_info(html): 从文章页面 HTML 中提取基础信息。 核心是拿到 appmsgid 和 idx这两个参数后面请求数据接口要用。 # 方式一从页面源码中通过正则匹配 appmsgid_match re.search(rvar appmsgid (\d), html) idx_match re.search(rvar idx (\d), html) # 方式二如果上面匹配不到从 meta 标签或 window.__DATA 里找 if not appmsgid_match: appmsgid_match re.search(rappmsgid\s*:\s*?(\d)?, html) if not idx_match: idx_match re.search(ridx\s*:\s*?(\d)?, html) # 标题优先从 og:title 元信息取 soup BeautifulSoup(html, lxml) og_title soup.find(meta, propertyog:title) title og_title[content] if og_title else 未知标题 return { appmsgid: appmsgid_match.group(1) if appmsgid_match else None, idx: idx_match.group(1) if idx_match else None, title: title, } def fetch_read_like_num(appmsgid, idx, article_url): 请求数据接口获取阅读数、点赞数等统计数据。 # 实际请求中这里的接口路径以页面抓包结果为准 # 下面是一个常见的数据接口形式字段需要根据实际返回调整 api_url https://mp.weixin.qq.com/mp/getappmsgext params { appmsgid: appmsgid, idx: idx, f: json, } headers get_headers(referer_urlarticle_url) headers[Accept] application/json, text/plain, */* response requests.get(api_url, paramsparams, headersheaders, timeout10) response.raise_for_status() data response.json() appmsgstat data.get(appmsgstat, {}) return { read_num: appmsgstat.get(read_num, 0), like_num: appmsgstat.get(like_num, 0), old_like_num: appmsgstat.get(old_like_num, 0), friend_subscribe_num: appmsgstat.get(friend_subscribe_num, 0), } def crawl_article(url): 主流程抓取单篇文章数据。 session requests.Session() session.headers.update(get_headers()) # 第一步请求文章页面拿 HTML 和基础信息 resp session.get(url, timeout10) resp.raise_for_status() html resp.text info extract_article_info(html) if not info[appmsgid] or not info[idx]: raise ValueError(未能从页面中解析到 appmsgid 或 idx页面结构可能有变化) # 第二步请求数据接口拿统计数据 stats fetch_read_like_num(info[appmsgid], info[idx], url) # 第三步汇总结果 result { url: url, title: info[title], appmsgid: info[appmsgid], idx: info[idx], **stats, } return result if __name__ __main__: # 示例换成你要抓取的文章链接 test_url https://mp.weixin.qq.com/s/your_article_id_here try: result crawl_article(test_url) print(json.dumps(result, ensure_asciiFalse, indent2)) except Exception as e: print(f抓取失败{e})这段代码经过了简化处理重点在于展示整体思路。真正的“数据接口路径”和“参数名”需要你在实际操作中打开开发者工具、抓包后按实际情况填写原因是公众号的接口路径并非完全固定不同时期和不同账号类型可能存在差异。3.3 如何定位数据接口用浏览器抓包找出真实请求为了确保你能找到自己场景下的真实接口这里把抓包定位的过程完整拆解一遍首先用 Chrome 打开目标文章按 F12 打开开发者工具切换到 Network 标签页。刷新页面此时可以看到很多网络请求。接着在筛选框里输入json或者appmsg快速过滤出疑似接口的请求。找到一个名称中包含getappmsgext或类似关键词的请求点击它。切换到 Headers 标签页能看到完整的 Request URL 和 Query String Parameters。把 Request URL 复制出来备用。再切换到 Response 或 Preview 标签页查看返回数据确认数据里是否包含read_num和like_num字段。实际操作中原文里讲的“固定写死的接口路径”其实只对部分账号类型有效不同场景下接口域名可能不同——有的走mp.weixin.qq.com有的走channels.weixin.qq.com或新的数据域名。所以最稳妥的方式不是我在代码里给一个固定接口而是教会你用抓包的方式定位到真实接口再填入代码。上面的代码中api_url就是一个占位请务必替换成你自己抓包拿到的地址。3.4 数据接口的参数说明与异常处理从抓包结果看到的数据接口参数一般包含以下几类参数说明是否必填appmsgid文章唯一标识从页面源码提取是idx文章在公众号内的序号标识是f返回格式一般传 json是random随机数部分场景需要因接口而异uin用户标识未登录时可能为空否key登录态令牌部分接口需要因场景而异pass_ticket临时票据因场景而异在处理这些参数时我的建议是先把抓包里看到的完整参数都复制到代码里确保能正常返回数据后再逐个删减参数测试哪些是必须的哪些是可有可无的。这样既能保证功能正常又能降低请求的复杂度。异常处理这块我的代码里已经做了几个基本动作设置超时时间、捕获请求异常、检查 HTTP 状态码。但还需要再加两层防护一是对 JSON 解析做容错。接口偶尔会返回 HTML 格式的错误信息而不是 JSON这时调用response.json()会抛出异常。可以先判断响应头的Content-Type或直接用 try-except 包住解析逻辑。二是对数据做缓存。如果做的是定时任务建议每个 URL 抓完后先把结果存到本地文件再失败重试。这样一来即使某次任务中间挂了已经抓到的数据也不会丢。3.5 批量抓取与并发设计让 100 篇文章从 8 分钟压缩到 20 秒单篇抓取跑通了以后大多数人下一步的需求就是批量。我自己的经验是批量场景下最大的瓶颈是网络 IO而不是 CPU。如果文章数量多串行跑会很慢每篇按 2~3 秒算100 篇就要 5 分钟左右。但只要控制好频率用线程池并发请求速度可以提升一个量级。下面是我常用的并发抓取代码片段from concurrent.futures import ThreadPoolExecutor, as_completed def batch_crawl(urls, max_workers5): results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map {executor.submit(crawl_article, url): url for url in urls} for future in as_completed(future_map): url future_map[future] try: result future.result() results.append(result) print(f[OK] {url} - 阅读数{result[read_num]}) except Exception as e: print(f[FAIL] {url} - {e}) return results这里要特别强调并发数max_workers的选择。我踩过坑一开始图快把并发调到 20结果跑了没一会儿就开始出现大量超时和 403 错误。后来把并发数降回 5虽然速度慢了一点但整体稳定很多。服务器端其实是有访问频控的短时间高并发的请求很容易被识别为异常行为。如果你只是个人做数据分析5 个并发已经足够100 篇文章跑下来不到 30 秒。如果你有更多文章要抓建议采用“每批 5 个并发、每批间隔 2 秒”的策略稳妥第一。另外配合time.sleep()做限速也很有用。每次请求前随机休眠 0.5 到 1.5 秒可以让请求分布更接近真实用户行为。3.6 数据存储从 JSON 到 Excel 的快速方案数据抓下来之后存成 JSON 是最灵活的方式。但很多人拿到数据后习惯用 Excel 看那这里也顺手提供一个把 JSON 转 Excel 的代码片段用的是pandas库import pandas as pd import json with open(results.json, r, encodingutf-8) as f: data json.load(f) df pd.DataFrame(data) df.to_excel(wechat_articles_stats.xlsx, indexFalse) print(f已导出 {len(df)} 条数据到 wechat_articles_stats.xlsx)如果数据量不大也可以直接用 Python 内置的csv模块写 CSV 文件Excel 和 WPS 都能直接打开不依赖 pandas。这个方案更适合轻量场景不用为此装一个几百 MB 的 pandas 依赖。4. 常见问题与排查技巧实录4.1 接口返回 403 或空数据怎么回事这个问题的根源大概率在请求头。把抓包工具里的完整请求头复制下来和你代码里的请求头逐行对比重点看 User-Agent、Referer、Accept 字段是否一致。如果请求头已经和浏览器一致还是 403可以考虑加 Cookie。用浏览器打开文章页F12 里找到请求头里的 Cookie复制到代码里再试试。加了 Cookie 之后绝大多数 403 问题都能解决。还有一种可能文章本身被删除或设置了访问限制。这种时候接口会返回错误信息不会返回统计数据。建议先把文章链接在浏览器里手动打开确认能正常访问再抓取。4.2 解析不到 appmsgid 或 idx页面结构变了怎么办公众号页面历史上调整过多次结构appmsgid和idx变量的位置不是一成不变的。如果你遇到解析不到的情况最简单的排查方法是在浏览器里打开文章页查看 HTML 源码搜索appmsgid关键字看看它现在以什么形式存在。常见的情况有三种变量形式var appmsgid 123456;JSON 字符串形式appmsgid:123456隐藏在某个 script 标签的全局变量里window.__DATA__ {...}根据实际形式调整正则表达式即可。我上面的代码已经写了两种匹配方式如果还不够可以继续加匹配规则。核心思路是不管页面怎么变接口请求总归需要这两个参数把它们拿到手就成功了一半。4.3 返回了数据但 read_num 一直是 0哪里出了问题这种情况通常是接口路径或参数虽然是通的但实际请求的并不是真正返回统计数据的那个接口。我遇到过一种情况接口返回的 JSON 里确实有appmsgstat这个字段但所有数字都是 0。后来发现是我把接口地址配错了请求到了一个与当前文章不匹配的接口。排查方法很简单在浏览器里打开文章页F12 刷新找到真正返回非零阅读数据的请求对比它和代码里的请求地址、参数差异。如果浏览器里能看到数据而代码里拿到的是 0那问题一定出在请求参数或请求头上。另外read_num在长时间后可能会被微信缓存导致数据不更新。如果你抓的是刚发布不久的文章间隔几分钟再请求一次数据大概率会变化。4.4 文章数量多时如何避免封禁和限流虽然公众号接口不像主流电商平台那样有严格的反爬机制但也不建议无限频率地请求。我自己在跑批量的经验是单账号场景下并发数控制在 5 以内。两次请求之间加随机延时。不要让每次请求的间隔完全一致那样反而更像脚本。定时任务场景下每天的请求总量不要过于夸张正常的数据分析需求不至于触发风控。如果你确实需要抓取大量历史文章建议分批进行每批之间间隔较长的时间。例如每天抓几百篇分多天完成。这不是效率问题而是可持续性问题。4.5 公众号文章链接失效了怎么处理公众号文章链接有时会失效例如文章被删除、公众号迁移、链接过期等。遇到这种情况抓取时就会报 404 或页面无法访问。在批量任务里建议单独建一个failed_urls.txt文件把所有失败的链接记录下来方便后续人工确认。我在代码里没有为每个 URL 做单独的文件记录因为实际场景里失败原因各不相同一次性把所有失败信息打出来反而不利于排查。更推荐的做法是在except分支里把失败链接和一个简单的原因标识写入本地日志文件任务跑完后集中排查。4.6 关于微信公众号平台接口的政策风险提示公众号数据接口和相关页面的访问规则可能随时间变化。技术方案只适用于合规的个人学习、数据分析和内容运营场景。使用爬虫时需要注意以下几点一是尊重平台的用户协议。不要将抓取的数据用于商业售卖、大规模采集他人隐私或任何违法用途。二是控制访问频次。普通个人分析场景一天几百次请求是合理的但如果做几万、几十万的批量抓取就明显超出了个人合理使用范畴既不建议也不正当。三是注意数据字段的合法性。阅读数和点赞数是公开展示的数据统计这类公开数据用于分析一般没有问题但如果涉及用户个人信息就要额外谨慎。5. 扩展应用与进阶思路5.1 定时抓取打造你自己的公众号数据看板如果你不是只抓一次数据而是想持续跟踪数据的增长趋势定时抓取就是刚需。实现方式分两层第一层是在 Python 脚本外做定时调度以 Linux 服务器上的crontab为例每天凌晨 2 点执行一次脚本0 2 * * * cd /path/to/wechat-spider /usr/bin/python3 main.py run.log 21Windows 环境下可以用“任务计划程序”创建定时任务触发条件设为“每天”。第二层是脚本内部做增量抓取。维护一个last_run.txt文件记录上次运行时间每次抓取时只处理这个时间点之后新发布的文章链接。也可以维护一个已抓取链接的去重集合避免重复抓取。数据落地之后接一个可视化面板比如用 Grafana、Metabase 或者简单的 Flask ECharts 页面展示。我在实际项目中用的是一个极简方案抓取结果写到 SQLite 数据库然后用一个 Flask 页面展示按日期的阅读趋势折线图效果不比商业产品差多少。5.2 从单篇到整个公众号历史文章链接的批量获取单篇文章的抓取没问题后你很可能想批量抓取一个公众号的所有历史文章。这个场景下核心问题是“如何拿到这个公众号的所有文章链接”。有几个思路第一个思路如果公众号有自定义菜单菜单里的历史文章链接是可以拿到的。如果你能获取到公众号的历史消息页 URL其中通常会包含__biz参数和appmsgid列表这种方式获取链接最直接。第二个思路通过搜狗微信搜索按公众号名称搜索文章。这种方式拿到的链接时效性有限搜狗对爬虫也有一定的反爬措施不是最优选。第三个思路如果你已经关注了该公众号可以在微信客户端里打开历史消息页手动下拉加载用抓包工具记录链接。这种方式效率低但胜在数据准确。实际项目里如果你是某公众号的运营者可以直接从公众平台后台导出文章列表和链接这是最合规、最高效的方式。如果是竞品分析建议先评估体量量小的话手动收集链接也完全可以接受。5.3 数据清洗与二次分析阅读量和发布时间有什么关系抓完数据后最有意思的环节是分析。我自己常用几个分析维度发布时间与阅读量的关系。把文章按发布时间分桶上午、中午、傍晚、深夜对比各时段的平均阅读量可以推测账号粉丝的活跃时段。标题长度与阅读量的关系。统计不同标题长度区间下的平均阅读数有些账号能看出明显的规律。点赞率点赞数除以阅读数的异常检测。正常文章的点赞率在 0.5%~2% 之间如果某篇异常高通常是内容引发了强烈共鸣或者有社群转发助推。这些分析做下来基本就是一份完整的公众号内容诊断报告了。5.4 反爬升级如果遇到浏览器环境校验怎么办requests 方案最大的软肋是遇到强浏览器环境校验也就是服务器检测到你用的是非浏览器环境要求执行 JavaScript 挑战或验证码。公众号接口目前很少走到这一步但如果未来遇到有两条路一条路是换用 Playwright 或 Selenium真实加载一个浏览器内核让服务端以为是真人访问。代价是速度慢、资源占用高。另一条路是模拟 TLS 指纹。这个技术细节比较深大致思路是requests底层用的 OpenSSL 指纹和浏览器不一样部分服务端会通过 TLS 指纹识别爬虫。解决方案是使用curl_cffi库它能模拟浏览器的 TLS 指纹。我还没有在公众号场景遇到过这个级别的校验但在技术预研时验证过curl_cffi的有效性。感兴趣的话可以提前了解万一以后遇到不需要临时抱佛脚。写在最后的一些经验做爬虫这几年我最大的体会是爬虫的核心不是代码写得多么花哨而是对目标网站结构的理解程度。你理解得越透彻代码就越简洁问题就越少。公众号文章数据抓取这个需求本质上就是一个“页面解析 接口请求 数据提取”的组合。真正到实战里你会发现 80% 的时间花在分析页面结构、调试请求头、处理边界情况上真正写代码的时间反而很少。最后分享一个小技巧在写这类带数据接口的爬虫时先把接口的完整请求复制成 curl 命令保存到一个requests.txt文件里。后续无论是重建代码、对比参数还是排查问题这个 curl 命令都是最可靠的参照物。很多时候你把代码调到头秃结果一看原始 curl 请求发现只是少传了一个Accept头。希望这篇文章能帮你少走一些弯路。如果你按照上面的步骤操作遇到问题欢迎对照“常见问题”一节逐一排查。公众号的数据接口和服务端策略可能随版本更新而变化但“抓包分析 — 代码实现 — 异常兜底”这个流程在很长一段时间内都适用。