后台列表永远只给你第一页:一次 79 个假缺口和两个真事故

后台列表永远只给你第一页:一次 79 个假缺口和两个真事故

我做了一件很自然的事:写脚本打开各平台的「我的文章」列表,抓标题,跟本地稿库比对,算出「哪些稿子还没发到这个平台」。

第一次跑出来,缺口79 个。

我差点就照着这个清单去补发了。幸好补发前手贱看了一眼作者主页——上面写着「21 篇」,而我的清单里该平台只有 8 篇。

8 篇里算出来的 12 个缺口,有 11 个是假的。

一、79 个缺口是怎么算出来的

逻辑毫无问题:

缺口 = 稿库 20 篇 − 平台上已发的标题集合

问题出在「平台上已发的标题集合」这一步。我打开的是后台列表页,抓的是页面上出现的所有标题。而后台列表页一页只显示 8 条,我没有翻页。

所以每个平台我只看到了最早的 8 篇,剩下 13 篇在我的视野之外,于是被算成「没发过」。

八个平台 × 平均每平台只看到 8 条 = 79 个缺口里,绝大多数是这么来的。

教训不是「记得翻页」,而是:一个没验证过完整性的数据源,算出来的任何数字都是假的。我当时甚至没觉得需要验证——列表页有分页控件,我默认它是对的。

二、分页控件为什么点不动

发现清单不对之后,我去补翻页。然后发现:三个平台的后台分页控件都点不动。

不是没找到元素。我用的是真实鼠标事件(CDP 的Input.dispatchMouseEvent),坐标取自getBoundingClientRect的中心点,点之前还用elementFromPoint验证过该坐标上没有别的元素遮挡。

点击确实命中了「下一页」,页面就是不换。

排查下来,原因是这一类:

命中元素: DIV.pagination-wrap (宽 640, 高 32) 期望命中: A.page-next (宽 30, 高 24)

我用文本匹配「下一页」去找元素,命中的是包裹整个分页区的容器 div——因为容器的innerText里当然也包含「下一页」这三个字。点容器的中心点,落在两个页码之间的空隙上,什么也没触发。

修正办法很土但有效:

// 只取叶子节点:没有子元素、或者子元素里不含同样文本的那个constisLeaf=e.children.length===0;// 并且优先 A / BUTTON 标签constisClickable=/^(A|BUTTON)$/.test(e.tagName);// 并且先滚到底(分页控件常在视口外,视口外的元素点不到)window.scrollTo(0,document.body.scrollHeight);

改完之后,51CTO 能翻了,博客园还是不行(它的分页是异步加载,点完要等 3 秒,而且翻页后 DOM 复用,URL 不变,脚本判断不出「翻成功了没有」)。腾讯云根本没找到分页控件——它的后台压根只给一页。

于是我放弃了「点分页」这条路。

三、三条能拿到全量的路

路一:站内接口(最干净)

多数平台的列表页其实是调接口的。开着网络面板点一次列表页,就能看到它请求的接口和返回的字段。

这条路我拿下了 CSDN、掘金、知乎、简书四个平台。好处不只是「全量」,还有:返回的是结构化数据,标题、ID、状态、发布时间都有,不用从 HTML 里抠。

举个实际收益:接口里有个status字段,能直接区分「已发布」「审核中」「未通过」「草稿」。这是页面上要一个个点进去才看得到的东西。

路二:归档页(最稳)

博客园有按月归档页,一个月的文章一页列完,没有分页。

https://www.cnblogs.com/<用户名>/archive/2026/10.html

我 10 月发了 19 篇,打开这个页面,19 条全在。一篇不落,还带日期。

这条路的好处是它不依赖登录态和接口签名,是个纯粹的静态页。坏处是只有部分平台提供归档页,而且按月切,跨月要拼好几次。

路三:作者主页加后缀(最容易忽略)

腾讯云这个卡了我最久。我打开作者主页,只看到几条「动态」,根本不是文章列表。

后来发现腾讯云的作者主页分 tab,默认停在「动态」,文章列表在另一个 tab 上,而且这个 tab 是有独立 URL 的:

https://cloud.tencent.com/developer/user/<uid> → 动态 https://cloud.tencent.com/developer/user/<uid>/articles → 文章列表(全量)

带不带/articles后缀,看到的是两个完全不同的页面。我前面几次抓取全用了不带后缀的那个,所以永远只有 5 条。

51CTO 也是同一个路子:直接访问u_17794761看到的是「动态 + 近期文章」,要点开「博客」这个 tab 才是全量列表。

四、假缺口的代价:我把发过的稿子又发了一遍

上面这些都是技术问题,真正让我肉疼的是后果。

在拿到全量之前,我的清单说「51CTO 缺 5 篇」。其中有一篇叫《把 1242 条法规做成离线可核查的知识库》,我记得早期发过,但清单里没有(因为它排在第一页之外),我就信了清单,重新发了一遍。

结果:未通过,原因「重复提交」。

平台侧的查重不是比标题,是比内容。我换个标题(原标题带了「10 部环境法一夜废止之后」的前缀,新标题没有)没用,正文 90% 相同,照样判重。

那一刻我意识到「假缺口」不只是浪费时间,它会造成真实的负资产:一条未通过记录、一个失败草稿、以及平台对你账号的重复提交计数。

五、现在我的流程

改完之后,算缺口的流程变成这样:

1. 取全量(接口 → 归档页 → 主页后缀,三选一,必须验证总数) 2. 验证总数:抓到的条数 ≥ 平台上显示的「N 篇文章」? 不达标就换路子,不许带着残缺数据往下走 3. 比对:用标题的「指纹」(去标点、去空格、取前 12 字)做包含匹配, 不用全等——各平台对标题里的书名号、引号处理不一样 4. 输出清单时同时输出「已发条数」,让人一眼能看出数据是不是全的

第 2 步是关键。以前我觉得「抓到什么算什么」,现在这一步是硬性卡点:抓到的条数和平台自己声明的总数对不上,脚本直接报错退出,不许继续。

顺便说,第 3 步的指纹匹配也救过我一次。同一篇稿子在 CSDN 上标题末尾多了个空格,在掘金上书名号被转成了直角引号,全等匹配两边都判成「没发过」,用前 12 字包含匹配就对了。

六、为什么值得单独写一篇

因为这是一个安静的错误。

脚本没崩,退出码 0,日志里该有的都有,输出的清单甚至格式漂亮、字段齐全。唯一的问题是数字错了,而且是往「显得还有好多活儿干」的方向错——这正是我最愿意相信的方向。

当时我看到 79 个缺口的感觉是「哇,还有这么多可以发」,而不是「等等,这数字对吗」。

一个错误如果朝着你希望的方向偏,你不会去怀疑它。

所以现在我给所有「统计类」脚本加了一条:输出里必须带上一个能独立验证的基准数字。抓文章就带「平台声明的总数」,抓评论就带「页面上显示的计数」。有这个数字在旁边,偏差自己会跳出来。


本篇提到的三个坑(分页控件命中的是容器、归档页、主页后缀)都不是什么高深技术,加起来我花了大概四十分钟才摸清。但如果不是先看到「21 篇」那个数字,我可能至今还在信那 79 个缺口。

相关新闻

基于PaddlePaddle的虚拟主播制作:从语音合成到口型同步实战

基于PaddlePaddle的虚拟主播制作:从语音合成到口型同步实战

简介&#xff1a;基于飞桨PaddlePaddle深度学习框架&#xff0c;集成PaddleSpeech语音合成与PaddleGAN图像生成等套件的虚拟主播项目源码&#xff0c;面向有深度学习基础、正在进行毕业设计或课程设计的学生&#xff0c;也适合想要快速落地虚拟人应用的开发者。项目仅需提供一张…

2026/10/20 10:42:34 阅读更多 →
AI Agent真实水位:从概念到落地,避坑学习指南

AI Agent真实水位:从概念到落地,避坑学习指南

最近总有新人私信我同一个问题&#xff1a;“Agent怎么学&#xff1f;现在转Agent还来得及吗&#xff1f;”我说句真话&#xff1a;这一波冲进来的人&#xff0c;一半会在三个月内离开&#xff0c;剩下的一半会在半年后开始怀疑人生。不是Agent没价值&#xff0c;而是这个赛道的…

2026/10/20 10:42:34 阅读更多 →
Agent工作流架构详解:增强型、链式与路由式模式选型与实践

Agent工作流架构详解:增强型、链式与路由式模式选型与实践

我最早接触 Agent 工作流的时候&#xff0c;想法特别单纯&#xff1a;不就是调大模型接口、给几个工具、写几句 Prompt 嘛。直到做一个稍微复杂点的活儿——让 Agent 自己查资料、分析数据、再生成一份报告——翻了车&#xff0c;才真正意识到问题不在模型聪明不聪明&#xff0…

2026/10/20 10:42:34 阅读更多 →

最新新闻

MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

简介&#xff1a;本资源是《MATLAB小波分析超级学习手册》配套的完整程序代码包&#xff0c;面向信号处理、图像分析及科研工程领域的MATLAB初学者与进阶用户&#xff0c;聚焦小波理论落地与工程实践能力提升。压缩包含119个文件&#xff08;113个.m函数脚本、4个.wav测试音频、…

2026/10/20 12:23:13 阅读更多 →
华为交换机LACP链路聚合配置实战:负载分担与故障排查

华为交换机LACP链路聚合配置实战:负载分担与故障排查

1. 从一个真实故障说起&#xff1a;为什么单根网线永远不够用很多刚入行的网络运维同行都有过这样的经历&#xff1a;机房搬迁&#xff0c;核心交换机到接入交换机的链路只有一根千兆网线&#xff0c;业务高峰期一到&#xff0c;监控大屏上那条链路的使用率直接顶到95%以上&…

2026/10/20 12:23:13 阅读更多 →
数据预处理全攻略:从数据清洗到缺失值处理,打好数据分析地基

数据预处理全攻略:从数据清洗到缺失值处理,打好数据分析地基

做数据分析这几年&#xff0c;我见过太多人把精力全扑在算法调参上&#xff0c;反复调了好几天&#xff0c;模型效果怎么都上不去&#xff0c;最后排查来排查去才发现&#xff0c;问题根本不在模型&#xff0c;而是喂给模型的数据本身就没洗干净。脏数据、缺失值、量纲悬殊、时…

2026/10/20 12:23:13 阅读更多 →
用 LangGraph 搭建带工具调用的多轮智能体:从状态机设计到流式输出实战

用 LangGraph 搭建带工具调用的多轮智能体:从状态机设计到流式输出实战

引言&#xff1a;能调工具的 Chatbot&#xff0c;离"可用"还有多远 过去一年&#xff0c;几乎每个团队都写过类似这样的代码&#xff1a;把工具 schema 丢给 LLM&#xff0c;拿回 tool_calls&#xff0c;for 循环里逐个执行&#xff0c;把结果拼回消息列表&#xff0…

2026/10/20 12:23:13 阅读更多 →
用 LangChain 和 Ollama 搭建本地 RAG 智能体问答系统

用 LangChain 和 Ollama 搭建本地 RAG 智能体问答系统

引言&#xff1a;本地 RAG 的真实驱动力 过去一年&#xff0c;我参与过几个企业内部知识库项目&#xff0c;几乎每一次技术选型会议都会出现同一个分歧&#xff1a;用云端大模型 API&#xff0c;还是全部本地化部署&#xff1f; 云端方案的优势很明确——模型能力强、开箱即用。…

2026/10/20 12:23:13 阅读更多 →
STM32F4实战:EC20 TCP透传模式与AT指令初始化流程详解

STM32F4实战:EC20 TCP透传模式与AT指令初始化流程详解

简介&#xff1a;针对EC20模块在STM32F4系列微控制器上实现TCP透传通信的场景&#xff0c;这份压缩包提供了一套完整的Keil工程源码&#xff0c;适合物联网开发者、嵌入式工程师以及学习STM32通信技术的读者参考。压缩包内共有174个文件&#xff0c;整体大小约4.06MB&#xff0…

2026/10/20 12:22:13 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →