聊抓取预算时,多数人第一反应是看服务器的响应时间,却容易忽略另一头:页面本身有多重。同样一条抓取线程,抓一个 20KB 的页面和抓一个 2MB 的页面,花掉的时间和带宽完全不是一个量级。当站点有几十万条 URL 时,这种差异会直接体现在「每天到底抓了多少页」上。
一次抓取要消耗哪些资源
蜘蛛访问一个 URL,大致经过几步:建立连接、发送请求、等待首字节、下载完整响应体、解析 HTML、从里面提取新链接放进待抓取队列。响应时间影响的是前几步,而后面下载与解析的耗时,主要由页面体积和 HTML 结构决定。
也就是说,即使你把 TTFB 压到 100 毫秒,只要每个页面都是 1.5MB 的庞然大物,抓取速率依然上不去。限额是按请求数或时间窗口算的,单页越重,单位时间里能走完的 URL 就越少。
HTML 变重的几个常见来源
- 内联的大段数据:为了省一次接口请求,把整份列表、配置项、多语言文案直接塞进 script 标签。首屏是快了,但每个 HTML 都跟着几百 KB 的文本。
- base64 内嵌的图片和字体:原图转码后体积通常会变大,而且它会随每一次 HTML 下载重复传输,缓存也帮不上忙。
- 层级很深、节点很多的 DOM:模板层层嵌套、包装元素一大串,解析和提取链接都要多花时间。
- 超长的链接列表:一页塞进几千条链接,常见于全站归档、标签云、历史文章汇总这类页面。
- 过长的 URL 与冗余参数:参数层层叠加,URL 本身就能写到几百字符,抓取记录里也不好看。
链接是不是越多越好
有些站点喜欢在一个页面里罗列所有入口,觉得这样能加快 URL 发现。实际情况是,一页几千条链接会带来两个副作用:一是解析成本上升,二是分配到单条链接上的关注度被稀释。蜘蛛需要判断先抓哪些、后抓哪些,列表太长反而让它难以取舍。
更稳妥的做法是分层:首页和栏目页放最重要的入口,归档页按时间或分类切分,每页控制在合理条数,靠翻页和分类目录把长尾 URL 一层层展开。这样每条链接都处在相对明确的上下文里,发现路径也更清晰。
传输层能省的部分
开启 gzip 或 brotli 压缩,对文本型 HTML 的效果通常很明显,很多时候能把体积压掉六七成。使用 HTTP/2 可以让同一站点的多次请求复用连接,减少握手的开销。静态资源则尽量走 CDN 并设置合理的缓存头,避免蜘蛛每次抓页都要连带拉一遍重复内容。
还有一点常被忽略:如果页面依赖 JS 渲染后才出现正文和链接,蜘蛛需要经历「先拿 HTML、再排队渲染」两段时间,整体成本会更高。能在服务端直出的内容,尽量直出。
可以动手做的调整
- 检查几个代表性页面的 HTML 体积,尤其是列表页和详情页,看看排在前面的「重量级选手」是谁。
- 把内联的大段 JSON 挪到独立接口,或用按需加载的方式拆分。
- 图片、字体改用外链资源,配合缓存策略,不要长期用 base64 内嵌。
- 精简模板嵌套,去掉只为样式服务的多余包装层。
- 归档页、标签页设置分页,每页链接数量控制在几十到一两百条。
- 确认服务器已开启压缩,并检查压缩是否对 HTML 类型生效。
抓取效率是「响应速度」和「页面重量」共同决定的。只优化其中一头,效果往往有限。
这些调整不会立刻带来可见变化,但它们影响的是长期成本:同样一份抓取额度,轻量页面能覆盖更多 URL,新内容的发现也就更及时。与其反复猜测蜘蛛的偏好,不如先把每个页面做得更利落一点。