做蜘蛛池或站内 URL 發現时,很多人只盯着 HTML 里的連結有没有寫對,却忽略了响應头里的 Content-Type。入口頁返回的 Content-Type 如果不是 text/html,搜尋蜘蛛在决定“要不要把這頁当 HTML 解析、要不要提取里面的連結”时,判断逻辑會不一样。這不是非黑即白的問题,结果取决于声明類型、内容嗅探和抓取端的具体實現。
一、Content-Type 决定了用什么解析器讀這一頁
搜尋蜘蛛拿到一個 URL 後,第一步是讀响應头,根據 Content-Type 判断资源類型:是 HTML 文档、纯文本、图片、PDF,還是 JSON 接口。類型判断错了,後面“提取連結、進入發現队列”的流程可能根本不會啟動。
声明為 text/html 或干脆没有 Content-Type
這两種情况通常會被当成 HTML 處理。缺失 Content-Type 时,抓取端往往會做内容嗅探,比如看响應体開头有没有 <!DOCTYPE html> 或 <html> 标簽。如果确實是 HTML 结构,連結一般能正常提取。
声明為 text/plain
這是最常见的一個坑。就算你把一整段 HTML 源碼放進响應体,只要响應头寫着 text/plain,很多抓取端會按纯文本處理,不做标簽解析,<a href> 就只是一串字符。個別搜尋引擎會做兼容性嗅探,但把發現連結的期望建立在“它應该會宽容處理”上,風險很高。
声明為 application/xhtml+xml
XHTML 通常還是能被解析的,只是對文档格式要求更嚴格。标簽未閉合、命名空間寫错、编碼声明冲突,都可能让解析提前中断,導致後半部分的連結提取不到。
声明為 application/json、application/xml 等
JSON 里即使存了 URL 字符串,它也不是超連結,不會被当成可跟進的連結。XML 里的連結情况要看具体用途:RSS/Atom feed 和 XML 站点地图属于搜尋引擎专门支持的發現通道,里面的連結可能被识別;而普通接口返回的 XML,基本不會被当作頁面連結解析。
声明為下载類或二進制類型
图片、视频、PDF、压缩包等,蜘蛛一般只做资源抓取,不解析里面的“連結”。PDF 中提取出的 URL 属于另一套處理逻辑,不能和常規 HTML 連結發現混為一谈。
二、响應头與内容冲突时會怎样
有些服務器把 Content-Type 寫死成 text/html,有些又寫错成 application/octet-stream。這種冲突没有统一答案:
- 头類型與内容明顯矛盾时,部分抓取端以内容嗅探為准,部分會直接放弃解析;
- CDN 或缓存层可能改寫 Content-Type,你在本地测出来是對的,线上未必;
- 部分網關、防護组件會强制返回 text/plain 或 application/json,連結會静默消失,日誌里看不出报错。
三、可以照着做的自查步骤
- 用 curl -I 查看入口頁响應头里的 Content-Type 到底是什么;
- 用 curl -s 看响應体,確認是完整 HTML,而不是被轉义、被 JSON 包了一层;
- 對比本地、源站、CDN 三层返回是否一致,重点看缓存节点;
- 關閉 JavaScript 後查看連結是否仍在原始 HTML 源碼中;
- 在服務器日誌里確認蜘蛛是否請求了目标 URL,而不只是訪問了入口頁。
四、几種容易誤判的情况
- 浏览器能打開不等于可解析。浏览器容错能力强,會嗅探並强行渲染,蜘蛛不一定這样做。
- 入口頁被訪問,不等于里面的連結被發現。入口頁的訪問可能来自你手動提交、外鏈或舊记錄,和目标 URL 進入發現队列是两件事。
- 只看狀態碼會漏掉問题。200 加 text/plain,比 404 更容易让人誤以為一切正常。
- 把一次成功当成稳定。Content-Type 可能随环境、节点、配置變更而變化,需要定期复测。
Content-Type 属于抓取鏈路里的基础设施。它出問题的表現往往不是报错,而是安静地少抓了一批 URL,排查时又很难第一時間想到它。
如果入口頁的連結總是“寫了却像没寫”,在怀疑内容质量、外鏈數量之前,先花几分钟確認响應头里的類型声明。這一步成本很低,却能排除掉一整類方向性誤判。