入口頁能不能被稳定抓到,除了 URL 本身和响應速度,還有一层经常被忽略的東西:HTTP 缓存头。很多人把它当成纯前端性能優化,實际上在蜘蛛池场景里,缓存配置會直接影响蜘蛛每次到訪看到的是 200 還是 304,以及這一次抓取有没有产生新的内容信号。
蜘蛛大体上怎么對待缓存
搜尋引擎爬虫不是浏览器,它通常不會像用戶那样長期复用本地缓存,也不带 Cookie 和會话狀態。但部分爬虫在重复訪問同一個 URL 时,會带上條件請求头,例如 If-Modified-Since 或 If-None-Match。這时候服務端的回答就分两種:内容變了返回 200 加新内容,内容没變返回 304。
304 並不等于抓取失敗。它只是告诉對方「你手上那份還是最新的」。但對于蜘蛛池入口頁来说,入口頁的價值就在内容變化上,如果長期只有 304,抓取動作發生了,新内容信号却没有产生。到底你的入口頁被問了几次條件請求、返回了多少 304,最靠谱的办法是翻訪問日誌里的狀態碼分布,而不是凭感觉。
几個缓存头各自在做什么
- Cache-Control:控制谁来缓存、缓存多久。no-store、no-cache、private、max-age 的含义差別很大,不要混用。max-age 设得過長,中間层可能一直吐舊内容给爬虫。
- ETag:内容的指纹,配合 If-None-Match 使用。多台後端如果各自生成,同一個 URL 可能每次指纹都不同。
- Last-Modified:内容最後修改時間,配合 If-Modified-Since 使用。它應该是真實的内容更新時間,而不是响應生成時間。
- Expires:老式寫法,優先級低于 Cache-Control,新舊混用时容易互相打架。
- Vary:告诉缓存哪些請求头會改變响應。寫错容易導致缓存命中混乱,出現同一個 URL 两種内容。
常见的几個坑
- 把 no-store 当成「防缓存能提高抓取」的手段。對爬虫来说這通常帮助不大,反而让每次請求都回源,白白增加服務器压力。
- 多节点部署时用預設 ETag 算法(通常基于文件属性和修改時間),同一份内容在不同机器上指纹不同,爬虫每次都被判為「變了」,于是反复拿到 200,消耗掉本可以省下的抓取次數。
- Last-Modified 用目前時間動態生成。结果是每次請求都是「刚更新」,條件請求永遠命中不了 304,爬虫看到的更新時間也全是假的。
- CDN 缓存了舊版本入口頁,回源策略没配好,爬虫長期抓到的是歷史内容,而你本地看到的是新版本,排查时容易誤判。
- 反向誤区:為了「顯得内容常新」而故意频繁改動時間戳。這種信号一旦和實际内容不符,長期看没有正面收益。
缓存头不會让蜘蛛多给你一次抓取,它只决定這一次抓取是否带来新的内容信号。省下来的预算,應该花在真正值得被抓的入口頁上。
比較稳的配置思路
- 静態入口頁:给一個較短的 max-age(例如几分钟到一小时),同时保留 ETag 和 Last-Modified,让條件請求有正确的判断依據。
- 動態入口頁:ETag 用内容哈希生成,保證多节点一致;Last-Modified 取自内容更新時間。
- 内容确實變了:URL 不變就更新 Last-Modified,或者干脆換新 URL 重新進入抓取队列,两種做法各有适用场景。
- 用 CDN 时,確認缓存键是否包含了會改變内容的請求头,並定期抽查回源响應头,別只看邊缘节点。
- 入口頁的分组、站点之間尽量统一缓存策略,避免同一批资源里有的 200 有的 304,日誌分析时會很乱。
一份随手可做的自查
- 用 curl 连續請求同一個入口頁两次,看第二次是否返回 304,以及 ETag 是否一致。
- 在多台後端上分別請求同一個 URL,對比 ETag 和 Last-Modified 是否相同。
- 翻日誌,統計入口頁的狀態碼分布,看 200、304、404、5xx 各占多少。
- 检查 CDN 回源响應头,確認邊缘节点和源站的内容版本一致。
- 改動缓存策略後,隔几天再看一次日誌,观察抓取行為有没有變化。
小结
缓存策略本质上是回答一個問题:当蜘蛛再一次来到這個入口頁时,你想让它看到什么。想清楚這一点,Cache-Control、ETag、Last-Modified 该怎么配,基本就有答案了。它不解决收錄,也不保證排名,但能让有限的抓取動作落在更有意义的地方。