ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信爬虫实战:公众号历史文章与阅读点赞评论采集全解析

微信爬虫实战:公众号历史文章与阅读点赞评论采集全解析 简介这是一份基于 Node.js 的微信爬虫项目源码面向需要批量采集公众号数据的开发者与数据分析人员。它借助 AnyProxy 中间人代理机制可抓取微信文章的阅读量、点赞数、在看数、评论及正文内容并支持获取公众号历史文章链接代码已适配 AnyProxy 4同时提供 Docker 部署方案可运行于个人电脑或服务器。压缩包共 80 个文件约 1.13MB以 40 个 js 与 9 个 jsx 业务脚本为核心辅以 json 配置、html 页面、png/svg 图标及 woff2、ttf 等字体资源另含 Dockerfile、docker-compose.yml、证书文件与 README 说明结构上区分 client、server、models、plugins、rule 等模块便于按功能定位代码。目前已有 2623 人学习下载。读者可从中获得完整的代理抓取链路、数据解析与入库逻辑、Redis 缓存与 MongoDB 存储实现以及证书配置和容器化部署的参考思路适合作为微信数据采集与代理调试的学习范例。1. 微信爬虫实战从公众号历史链接到阅读点赞评论的完整拆解做公众号内容分析的人多半遇到过这个场景想复盘某个号半年的选题规律手动翻历史消息翻到手指发酸阅读量、点赞数、评论还得一条条点开截图。wechat_spider这个资源就是冲着这个痛点来的——它把公众号历史文章链接、正文内容、阅读量、点赞量、评论这几类数据串成一条采集链路用 JavaScript 写核心逻辑适合做内容运营分析、竞品监测、选题库沉淀的从业者。需要先说明的是这类工具拿到的数据颗粒度取决于入口形态历史链接列表、单篇正文、互动指标往往来自不同页面采集策略也不一样。下面按「它怎么组织 → 怎么跑起来 → 哪里会翻车 → 怎么稳住」的顺序拆新手能照着复现熟手能直接看参数边界。2. 拆解 wechat_spider 的采集链路历史链接、正文、互动指标怎么串起来2.1 三类数据的来源差异决定了采集顺序很多人一上来就想「一个请求拿全部」结果发现拿不到。公众号的数据天然分散在几个位置历史文章列表通常出现在公众号主页的消息列表接口里返回的是分页的文章标题、链接、发布时间正文内容在文章详情页的 HTML 里阅读量、点赞量、评论则在详情页加载后的动态区域。这三者的获取时机和请求方式都不同所以合理的顺序是「先拿历史链接列表 → 再逐篇进详情页 → 最后补互动指标」。wechat_spider的设计思路基本遵循这条链路。历史链接是入口没有它后面都无从谈起正文是主体决定你后续能不能做全文检索和选题聚类互动指标是权重用来判断哪篇值得深挖。把顺序理清楚后面写代码时就不会把请求逻辑搅成一团。2.2 历史链接列表的分页与去重逻辑历史链接列表一般按时间倒序分页返回每页条数固定。采集时要处理两个问题一是翻页终止条件二是重复链接过滤。常见做法是用一个seen集合记录已抓取的链接每次解析出新链接先查重再入库。// 历史链接采集核心逻辑示意 const seen new Set(); let offset 0; const pageSize 20; async function fetchHistory(biz) { while (true) { // biz 是公众号唯一标识offset 控制分页 const res await requestHistoryApi(biz, offset, pageSize); const list res.article_list || []; if (list.length 0) break; // 没有新数据就停 for (const item of list) { const url item.link; if (seen.has(url)) continue; // 去重避免重复入库 seen.add(url); await saveArticleLink({ title: item.title, url, publishTime: item.update_time, }); } offset pageSize; await sleep(1500); // 控制频率别把请求打满 } }这段逻辑里biz是公众号的稳定标识比用名称去匹配可靠得多offset和pageSize决定翻页节奏pageSize一般不要超过接口默认上限否则会被截断sleep是必须的频率控制直接关系到后面会不会被限流。去重放在入库前而不是入库后能省掉一次数据库查询。2.3 正文与互动指标的抓取时机拿到链接后进详情页正文通常在初始 HTML 里就能解析出来用选择器定位文章容器即可。但阅读量、点赞量、评论这几项往往是异步加载的需要等页面渲染完成或单独请求对应接口。wechat_spider里这部分一般用无头浏览器或带 cookie 的请求来补。// 详情页正文 互动指标采集示意 async function fetchDetail(url) { const page await openPage(url); await page.waitForSelector(.rich_media_content); // 等正文渲染 const content await page.$eval(.rich_media_content, el el.innerText); const readCount await page.$eval(#js_read_area, el el.innerText).catch(() 0); const likeCount await page.$eval(#js_like_num, el el.innerText).catch(() 0); return { url, content, readCount, likeCount }; }waitForSelector是关键不等渲染直接取会拿到空值catch(() 0)是兜底某些文章没有点赞区域不兜底会直接抛错中断整批任务。评论通常要单独请求接口参数里带文章 id 和分页游标逻辑和历史列表类似。2.4 数据落库的字段设计采集完不落库等于白干。建议至少保留这些字段文章标题、链接、发布时间、正文、阅读量、点赞量、评论数、采集时间。链接做主键或唯一索引采集时间用来判断数据新鲜度。正文如果很长考虑单独存一张表或用文本字段别和指标混在一起否则查询会变慢。3. 把 wechat_spider 跑起来环境、参数与最小可复现流程3.1 环境准备与依赖安装这个资源核心是 JavaScript运行环境用 Node.js。常见做法是先确认 Node 版本再装依赖。无头浏览器部分如果用到 Puppeteer 或 Playwright首次安装会下载浏览器内核网络不稳时容易卡住可以配置国内镜像源。# 确认 Node 版本建议 16 以上 node -v # 初始化并安装依赖 npm init -y npm install puppeteer axios cheerio # 如果浏览器内核下载慢指定镜像 npm config set puppeteer_download_host https://npmmirror.com/mirrorspuppeteer负责渲染动态页面axios发接口请求cheerio解析静态 HTML。三者分工明确别用 axios 去抓需要渲染的互动指标也别用 puppeteer 去发纯接口请求那样又慢又费资源。3.2 关键参数怎么设参数设错是新手最容易翻车的地方。下面这张表把几个核心参数和调整方向列清楚参数作用建议值调整方向pageSize历史列表每页条数20超过接口上限会被截断sleep请求间隔毫秒1500被限流就加大timeout页面加载超时30000网络差适当加长retry单篇失败重试次数2别设太高避免死循环concurrency并发数1新手先单线程跑通sleep和concurrency是最影响稳定性的两个。并发调到 5 以上短时间请求量上去很容易触发限流表现就是返回空数据或跳验证。我一般先单线程跑通全流程再考虑小幅度提并发。3.3 最小可复现流程把上面的模块串起来一个最小流程是这样的// 主流程历史链接 - 逐篇详情 - 落库 async function main(biz) { const links await fetchHistory(biz); // 第一步拿历史链接 console.log(共获取 ${links.length} 篇文章链接); for (const link of links) { try { const detail await fetchDetail(link.url); // 第二步进详情页 await saveArticle({ ...link, ...detail }); // 第三步落库 console.log(已采集${link.title}); } catch (e) { console.error(失败${link.url}, e.message); // 单篇失败不影响整体 } await sleep(1500); } }这段代码的重点在try/catch包住单篇采集任何一篇失败都不该中断整批任务。console.log保留进度输出跑长任务时能判断卡在哪一篇。落库函数saveArticle里做唯一索引冲突处理重复链接直接跳过。3.4 验证采集结果跑完后别急着分析先验证数据完整性。检查三件事链接总数和预期是否接近、正文为空的文章占比、互动指标是否大量为 0。正文为空可能是选择器失效指标为 0 可能是没等渲染或接口变了。验证通过再进入分析环节否则后面全是脏数据。4. 避坑与排查微信爬虫最常见的五类翻车现场4.1 现象跑几十篇后返回空列表原因请求频率过高触发限流接口返回空数据或错误码。 解决把sleep从 1500 毫秒加到 3000 以上并发降到 1跑一段时间再观察。别想着靠换 IP 硬扛频率控制才是根本。4.2 现象正文抓到了阅读量全是 0原因互动指标是异步加载的没等渲染完成就取值。 解决在取指标前加waitForSelector或固定等待确认对应 DOM 节点出现再读。如果接口已变改用抓包定位新的指标接口。4.3 现象部分文章链接重复入库原因历史列表分页时边界重叠或翻页逻辑没做去重。 解决入库前用链接做唯一索引代码里维护seen集合。数据库层面加唯一约束是最后一道防线。4.4 现象无头浏览器启动就报错原因浏览器内核没下载成功或系统缺少依赖库。 解决检查 Puppeteer 缓存目录重新安装并指定镜像源Linux 环境下补装字体和依赖库报错信息里通常会提示缺哪个。4.5 现象评论抓不全只有前几条原因评论接口分页没处理只取了第一页。 解决评论接口一般带游标或页码参数循环请求直到返回空。注意评论的排序方式按时间还是按热度参数不同结果不同。5. 进阶技巧用增量采集和字段校验把数据质量稳住跑通全流程只是开始真正省心的是把增量采集做起来。每次跑之前先查库里已有的最新发布时间历史列表翻到早于这个时间就可以停不用每次全量重跑。这样既省请求也降低被限流的概率。// 增量采集翻到已采集时间就停 async function fetchHistoryIncremental(biz, lastTime) { let offset 0; while (true) { const list await requestHistoryApi(biz, offset, 20); if (!list.length) break; for (const item of list) { if (item.update_time lastTime) return; // 遇到旧数据直接结束 await saveArticleLink(item); } offset 20; await sleep(1500); } }lastTime从数据库里查最新一条的发布时间传入这样每次只抓新增部分。字段校验也值得加一道正文长度小于某个阈值、阅读量为负、发布时间格式不对都标记为异常单独存别混进正常数据里。我一般会在落库前加一个validate函数异常数据进article_error表方便回头排查。还有一个容易被忽略的点是正文里的图片和外链。如果后续要做知识库沉淀图片地址和外链需要单独提取否则正文只剩文字参考价值打折。提取逻辑不复杂正则或选择器都能做但要在采集阶段就处理别等入库后再补。从那以后我每次跑这类采集任务都强制先单线程跑 20 篇验证数据质量确认正文、指标、去重都正常再放开批量。这个习惯帮我省掉了无数次重跑。希望帮到你。本文还有配套的精品资源点击获取
返回列表