(本文含 AI 辅助创作内容)
一个每天跑的读数脚本,连续 40 天正常,
今天突然报「页面打开了,但没解析出数据——结构可能变了」。
下意识反应:平台改版了,选择器要重写。
差点就去重写选择器。实际根因是我等的时间不够。
脚本的等待逻辑是这样写的:
while waited < 16:
time.sleep(2)
waited += 2
if js("document.readyState") == "complete":
time.sleep(2)
break
body = js("document.body.innerText || ''")readyState === "complete",再等 2 秒,然后读文本。
打出来的 body 长度:1378 字。
里面有侧边栏、有账号概览、有「发布图文笔记」——
就是没有那块数据区。
按 readyState 的判断,页面确实"加载完成"了。
但页面是单页应用:框架壳加载完就算 complete,
数据区是后来才水合进来的。
不改任何选择器,只把等待时间拉长,
在同一个页面、同一个账号、同一段 URL 上重跑:
BEFORE: .../new/home
CLICK: CLICKED:2
AFTER: .../new/home
LEN 1393 → 出现「笔记数据总览 / 统计周期 10-10 至 10-16 / 曝光数 1.3万 / 观看数 1,384」选择器一个字没改。
原来不是结构变了,是我读得太早。
把固定的 sleep 换成对目标内容的轮询:
# 先等文档 complete,再等目标区块出现,最多 24 秒
body = ""
for _ in range(8):
body = js("document.body.innerText || ''")
if "笔记数据总览" in body:
break
time.sleep(3)三条经验:
1. readyState 只说明"框架壳到了",不说明"数据到了"。
异步渲染的页面,用它做判据一定会偶发读空。
2. 判据要落在"你要的那块内容"上,不是落在页面状态上。
页面状态是代理指标,内容是终点指标。代理指标永远会骗你。
3. 轮询要设上限,并且失败时把「等不到」和「结构变了」分开报。
原来的报错文案是"结构可能变了"——这句话把一个时序问题
伪装成了一次结构变更,把我往重写选择器的方向带。
现在改成"24 秒内该区块始终没出现(改版/未登录/网络慢)",
三种可能并列,不预设结论。
同一天还发现另一个同类问题:
一份自动归因报告,结论写的是"点击率 0.46%",
而当天后台实读是"0.59%"。
查下来,报告读的是手工维护的旧台账(停在 5 条),
而当天后台已经有 10 条读数。
两个数都没错,错的是报告用了哪一条。
改法:报告优先取当天实读,实读缺失才回退旧台账,
并在报告里打印数据源("今日后台回读·本页 10 条/后台共 17 条")。
至少下次看报告时,知道这个数是从哪儿来的。
readyState 当数据就绪的判据有时候不是系统坏了,
是你读得太早,或者你读的那份不是最新的那份。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。