bigywater.tech
爬虫工程 · 56

等待策略:固定等待、元素等待、网络空闲

动态页面的数据什么时候到齐?固定 sleep 多久都不对:短了拿不到,长了浪费。这篇在一个延迟随机、有分阶段加载、还挂着长连接的本机页面上,比较固定等待、轮询元素、等元素数量到位和等网络空闲几种做法的成功率与多等的时间。

5 / 12 与 916 ms
固定等待 0.5 秒的成功次数,与固定等待 1.5 秒平均多等的时间
0 / 12
分两阶段加载的页面上,“出现第一个元素就继续”拿到完整数据的次数
6035 ms
页面有长连接时,“等网络空闲”的平均耗时——一直等到我设的 6 秒上限

固定等待

实测 · 本机执行输出
  等待策略                                     拿到完整 20 条      平均耗时      平均多等
  固定等待 0.5 秒                             5 / 12     521 ms     -82 ms
  固定等待 1.5 秒                            12 / 12    1519 ms     916 ms
  轮询:出现第一个 .item 就继续                    12 / 12     647 ms      44 ms
  轮询:等到 20 个 .item                      12 / 12     645 ms      43 ms
  等网络空闲(0.3 秒内无请求,最长 6 秒)               12 / 12     932 ms     330 ms
  ("平均多等" = 平均耗时减去数据实际到齐所需的时间)

数据到达时间随机时,固定 sleep 是一个糟糕的折中:0.5 秒只有 5 / 12 次够,1.5 秒才全部够,但平均多等 916 ms。要覆盖最慢的情形,就得为大多数情形多等很久。

轮询元素

实测 · 本机执行输出
  等待策略                                     拿到完整 20 条      平均耗时      平均多等
  固定等待 0.5 秒                             0 / 12     519 ms    -613 ms
  固定等待 1.5 秒                            11 / 12    1520 ms     387 ms
  轮询:出现第一个 .item 就继续                     0 / 12     592 ms    -540 ms
  轮询:等到 20 个 .item                      12 / 12    1187 ms      54 ms
  等网络空闲(0.3 秒内无请求,最长 6 秒)               12 / 12    1471 ms     338 ms
  ("平均多等" = 平均耗时减去数据实际到齐所需的时间)

每 50 ms 检查一次期望的元素是否出现,耗时只比数据到齐多约 40 ms。但“出现第一个元素”不够:分两阶段加载时它在只有 5 条时就继续了(0 / 12);要等到期望的数量或某个“加载完成”的标志。

网络空闲

实测 · 本机执行输出
  等待策略                                     拿到完整 20 条      平均耗时      平均多等
  固定等待 0.5 秒                             7 / 12     520 ms      38 ms
  固定等待 1.5 秒                            12 / 12    1518 ms    1036 ms
  轮询:出现第一个 .item 就继续                    12 / 12     523 ms      41 ms
  轮询:等到 20 个 .item                      12 / 12     528 ms      45 ms
  等网络空闲(0.3 秒内无请求,最长 6 秒)               12 / 12    6035 ms    5552 ms
  ("平均多等" = 平均耗时减去数据实际到齐所需的时间)

等“没有在途请求并且 0.3 秒内没有新请求”对分阶段加载有效(12 / 12),但平均多等 300 多毫秒(静默期本身);页面有长连接、轮询或推送时网络永远不空闲,只能等到超时上限(6035 ms)。

分步演示

等待策略
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / requests 2.34.2 / aiohttp 3.14.3 / lxml 6.1.1(系统 Python);所有请求只发给本机自己起的测试服务器(127.0.0.1,端口 9960 以上,不访问任何真实网站);服务器可以按实验需要制造延迟、断连、压缩、重定向等行为,并记录收到的原始请求;计时用 time.perf_counter,数字每次运行会有小幅抖动。页面由本机服务器提供:页面 JS 用 fetch 请求 /data(服务器按参数延迟 0.05–1.1 秒),单次渲染 20 条,或分两次渲染 5 条和 15 条;页面 C 另外挂一个 15 秒的 fetch(放在另一个端口的服务器上);Chrome 154 通过 pcdp.py 控制,Network.enable 后收集 requestWillBeSent / loadingFinished / loadingFailed 事件判断网络空闲;每个策略 12 次加载,延迟序列相同(固定种子 55);“平均多等”=平均耗时减去数据实际到齐所需的时间(负数表示提前结束,拿到的数据不全)
    • 没有验证:真实站点上这些策略的表现;MutationObserver 判断 DOM 稳定;等待某个特定接口响应(Network.responseReceived)再取数据;骨架屏、懒加载、滚动才触发的内容;页面使用 WebSocket 时的网络空闲判定;Playwright/Selenium 内置等待的实现和默认超时;等待期间页面被反爬挑战拦截时的情形
    京ICP备2026067502号-1京公网安备11010502063487号