很多人以為蜘蛛抓一個 URL 就是一次動作:来、下载、走。實际情况更接近两次到訪——第一次只拿走 HTML 源碼,第二次才在另一條管线里执行 JavaScript。分不清這两步,就很容易把連結放在蜘蛛第一次看不到的地方。
第一次到訪:拿到的只是源碼
蜘蛛發起請求时,服務器返回的 HTML 响應体就是它第一眼看到的東西。這一刻,頁面還没有"執行":由 JS 注入的導航、列表、分頁連結、正文内容,全都不在里面。
這带来一個直接的後果:如果站内連結是脚本生成的,URL 的發現就被推迟到渲染阶段。而渲染不是每個 URL 都會做,也不是立刻做。有些頁面等到了,有些頁面一直没等到。
第二次到訪:渲染队列是另一條管线
渲染管线會执行頁面上的脚本、發起額外請求、构建最终的 DOM,再從里面提取連結和内容。它比單纯抓 HTML 贵得多:占资源、要排队、有超时,通常只對一部分頁面触發。
- 渲染有等待上限,第三方接口慢,頁面就可能渲染不全;
- 渲染通常在無头环境里跑,滚動、点击、登入態這類交互不會發生;
- 渲染产出會進缓存,但缓存什么时候刷新、是否刷新,站点無法直接控制。
換句话说,渲染是"补救",不是"預設"。把關键連結和内容押在渲染上,等于把抓取节奏交给了一條你不能直接調的队列。
哪些寫法會拖慢連結發現
- 用 div 或 span 加 onclick 跳轉,没有真正的 a 标簽和 href;
- 前端路由切換後,地址栏變了,但頁面里没有可爬的連結指向那些 URL;
- 無限滚動:内容靠滚動触發加载,渲染环境下不會滚;
- 分頁是按钮,實际 URL 不可直接訪問;
- 連結依赖第三方接口返回後才渲染出来。
這些做法對用戶体驗未必有問题,但對第一次到訪的蜘蛛来说,頁面里确實什么都没有。
让两條管线都省事的做法
- 導航、栏目、分頁、文章列表用真實 a 标簽,href 指向可訪問的 URL;
- 首屏關键内容和連結尽量由服務端輸出,SSR、SSG 或预渲染都可以;
- 分頁给出稳定的 URL 结构,让每個頁碼都能被直接請求;
- 必须用 JS 渲染的部分,也留一條 HTML 兜底路径,例如 noscript 中的連結或静態列表頁;
- 把重要 URL 同时放進 Sitemap,作為發現渠道的补充。
怎么驗證自己的站点
抓取工具里關閉 JavaScript,看剩下多少連結和内容;再打開 JavaScript 對比一次。两次差异越大,說明站点對渲染管线的依赖越重。服務器日誌里,如果出現大量 CSS、JS 等静態资源的請求,往往就是渲染管线的訪問痕迹,可以和纯抓取請求分開观察。
連結發現靠的是源碼可见性,渲染只是第二道保險。第一眼看不到的連結,抓取节奏就只能听天由命。
顺着這條思路检查一遍站点,通常能發現几處"只有渲染後才存在"的連結。把它們挪回 HTML 源碼,URL 發現的节奏會立刻稳定不少。