最近發現有些搜尋引擎爬蟲在抓取資料的時候,先是通過一個HEAD 請求擷取response的header 資訊,然後再通過GET 請求擷取response 的body資訊(即頁面的內容)——先發送HEAD 請求是為了獲得頁面的更新時間(即response header 中的Last-Modified 域),用於判斷自從上一次該頁面被收入索引庫以後有沒有被更新過,如果判斷頁面沒有被更新過就忽略該頁面,否則就再用GET 方法擷取一次最新的內容並更新到索引庫中。
在頁面更新頻率比較低或者緩衝設定的時間比較長的情況下,這樣做可以避免在網路上傳送體積比較大的body 域、降低網路消耗,而且還也可以縮短索引的更新時間。但在頁面更新頻率比較高,或者頁面緩衝時間比較短的情況下效果卻是相反的:
如果被抓取的頁面在緩衝中,情況會稍微好一些,快取服務器(如安裝了expires_module 的Apache)在接收到HEAD 請求時會把緩衝後的response 的header 域返回給爬蟲,在接下來的GET 請求時再把緩衝後的整個response (包括header 域和body 域)都返回給爬蟲;
如果被抓取的頁面不在緩衝中,而程式中又缺少專門針對HEAD 請求的處理方法,那麼就會導致該頁面被產生兩次——在處理HEAD請求的時候,因為沒有專門的方法,於是一般用於處理GET 請求的方法就會被執行,程式執行後產生了完整的response,快取服務器接收到該response,但只會把它的header 資訊返回給爬蟲,並不會對該response 進行緩衝;在處理接下來的GET 請求的時候,因為沒有緩衝所以程式還要再產生一遍完整的response,並由快取服務器轉交給爬蟲,這時快取服務器才會把response 緩衝起來。這樣程式就被執行了兩次,第一次執行很大程式上來說是一種浪費。
解決問題的一種方法就是在程式中加入對HEAD 請求的處理。在處理HEAD 請求的時候一般只要設定response header 中Content-Type 和Content-Length 就可以了,如: 在servlet 可以通過重載doHead(HttpServletRequest request, HttpServletResponse response) 的方法實現:
public void doHead(HttpServletRequest req, HttpServletResponse resp) throws IOException { // Set the content length and type resp.setContentType("text/html; charset=GB2312"); resp.setContentLength(30000);}
而在jsp 中則可以仿照下面的方式:
<%/* handle the HEAD request */if(request.getMethod().equals("HEAD")) { response.setDateHeader("Last-Modified", System.currentTimeMillis()); /* 設定Last-Modified */ response.setContentType("text/html; charset=GB2312"); /* 設定Content-Type */ response.setContentLength(30000); /* 設定 Content-Length */ return;}%>
下面是log 中的一個片斷,顯示了IP為202.108.1.4 的某個使用者/爬蟲/Proxy 伺服器(奇怪的UserAgent 項)的訪問日誌:
202.108.1.4 - - [06/Mar/2005:11:21:03 +0800] "HEAD /2001-03-07/28456.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:03 +0800] "GET /2001-03-07/28456.htm HTTP/1.1" 200 32182 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:09 +0800] "HEAD /2003-06-26/169417.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:09 +0800] "GET /2003-06-26/169417.htm HTTP/1.1" 200 34693 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:11 +0800] "HEAD /2005-1-5/361944.htm HTTP/1.1" 200 0 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
202.108.1.4 - - [06/Mar/2005:11:21:11 +0800] "GET /2005-1-5/361944.htm HTTP/1.1" 200 36761 "-" "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"
另,目前只有較少的老式搜尋引擎爬蟲在採用這種方式抓取頁面,如AOL 的爬蟲,而大部分搜尋引擎爬蟲都在採用另外一種方式:即在GET 請求的header 中加入If-Modified-Since 項,交由伺服器判斷頁面是否被更新過。
參見:
- All About Search Indexing Robots and Spiders http://www.searchtools.com/robots/
- Stealth bots. How to detect them? http://www.webmasterworld.com/forum11/2562.htm
- 超文字傳輸通訊協定 (HTTP) -- HTTP/1.0 (Hyptertext Transfer Protocol - HTTP/1.0) http://www.delphidevelopers.com/technical/RFC/RFCs/RFC1945.txt