爬蟲與反爬蟲就好像是安全領域的破解與反破解同樣,相互矛盾,相互剋制,同時也相互促進。html
網站的構建技術從簡單的靜態網站發展到動態網站,信息的傳遞從用戶單向接收發展到雙向交互,內容的產生從站長集中生成發展到全民參與生成。java
Web技術的發展對網絡爬蟲構成了極大的挑戰,咱們以Nutch爲例來講明難在哪裏:web
一、靜態網站(簡單)算法
二、動態網站(無陷阱)(難)apache
三、動態網站(有陷阱)(很是難)安全
對於靜態網站,頁面數量有限,不管頁面之間如何構造連接,不管頁面內容是什麼,都能在一個有限的時間內抓取完畢。對於靜態網站來講,咱們假設網站無陷阱(不會有程序來動態生成無窮無盡的靜態頁面),內容質量高(不會爲了提升搜索結果排名進行關鍵詞堆砌,不會大量靜態頁面都是同樣的內容或近似的內容等)。這樣的靜態網站,就是爬蟲理想的抓取對象!服務器
對於無陷阱的動態網站,用戶須要和服務器交互,服務器根據用戶指定的參數動態返回結果。爬蟲要抓取這樣的網站,就須要枚舉完全部可用的參數,而不少時候,爬蟲是沒法枚舉完全部可用的參數的。網絡
假如咱們要想抓取淘寶上面的全部商品,咱們經過他的搜索入口去抓是沒法抓完的,由於咱們沒法枚舉全部的商品;那麼咱們還能夠經過分類欄目做爲入口,一頁一頁地日後抓,這雖然可行,可是沒法抓全,淘寶會對分頁進行限制,如100頁,每頁96個商品,也纔不到一萬件商品,而淘寶一個分類欄目下可能有幾百萬甚至幾千萬的商品,召回率只有百分之一甚至千分之一。架構
對於有陷阱的動態網站,那就更復雜了,下面舉一個例子,一個簡單的動態頁面就可讓爬蟲永遠也爬不完,弱智的爬蟲就會進入死循環,Nutch固然是不會了。jsp
構造一個動態JSP頁面,內容以下:
<%@page contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>APDPlat應用級產品開發平臺</title> </head> <body> <p>APDPlat是Application Product Development Platform(應用級產品開發平臺)的縮寫,做者是楊尚川。APDPlat提供了應用容器、多模塊架構、代碼生成、安裝程序、認證受權、備份恢復、數據字典、web service、系統監控、操做審計、統計圖、報表、機器綁定、防止破解、數據安全、內置搜索、數據轉換、maven支持、WEB組件、內容管理、工做流、Web資源優化等功能。</p> <a href="circle.jsp?time=<%=System.nanoTime()%>">APDPlat</a> <a href="circle.jsp">APDPlat Home</a> </body> </html>
這個頁面有2個指向本身的連接,一個是固定的,一個是會變化的,爬蟲在訪問這個頁面的時候,會解析這2個連接,因爲其中1個連接帶了1個查詢參數,這個參數的值每次訪問頁面的時候都會變化,所以每一次解析出來的都是一個新連接,儘管都是指向本身。雖然頁面的可視文字內容相同,但因爲連接參數的不一樣,因此頁面的「指紋」也不一樣,對於不一樣網頁之間重複內容去重來講,就不可以簡單地比較頁面的「指紋」來判重。
這個頁面引出了爬蟲抓取頁面時候的兩個挑戰:
一、連接陷阱
二、內容去重
連接陷阱不必定會致使死循環(就看你如何設計爬蟲),可是必定會致使爬蟲永遠也爬不完。
內容去重分三種狀況,一是內容徹底同樣,這種狀況不多;二是類似度極高,像上面的例子,只有一個連接的參數time的值不同,其餘內容徹底同樣;三是有必定的類似度,在一樣的文檔(1)和徹底不一樣的文檔(0)之間分佈;所以,一個適合實際應用的網頁內容類似度算法和判斷重複的閾值就很關鍵了。
下面配置Nutch來抓取上面構造的頁面,看看狀況如何:
一、下載Nutch1.7的二進制版本解壓並切換到本地運行目錄:
wget http://pan.baidu.com/s/1nt2oJBN unzip apache-nutch-1.7-bin.zip -d nutch1.7 cd nutch1.7/runtime/local
二、準備注入URL文件:
mkdir urls echo 'http://localhost:8080/circle.jsp' > urls/url
三、修改URL過濾文件conf/regex-urlfilter.txt限制抓取範圍
#-[?*!@=] +^http://localhost:8080/ -.
四、運行爬蟲,參數爲:
bin/nutch crawl urls -dir data -solr http://localhost:8983/solr/collection1 -depth 30 &
五、查看抓取下來的URL及其狀態,經過分析發現,這個頁面是抓不完的,抓完一個URL又會產生一個新的URL,無休無止,永遠有一個新的未抓取的URL。同時,經過查看segments裏面的內容發現,每一個頁面的簽名不同,由於每一個頁面的輸出連接的參數不同,哪怕其餘的都如出一轍:
http://localhost:8080/circle.jsp (db_fetched) http://localhost:8080/circle.jsp?time=123907953954240 (db_fetched) http://localhost:8080/circle.jsp?time=123930321590561 (db_fetched) http://localhost:8080/circle.jsp?time=123944319760709 (db_fetched) http://localhost:8080/circle.jsp?time=123951830890558 (db_fetched) http://localhost:8080/circle.jsp?time=123959814878130 (db_fetched) http://localhost:8080/circle.jsp?time=123967551109864 (db_fetched) http://localhost:8080/circle.jsp?time=123976440281803 (db_fetched) http://localhost:8080/circle.jsp?time=123984079586038 (db_fetched) http://localhost:8080/circle.jsp?time=123991682817130 (db_fetched) http://localhost:8080/circle.jsp?time=123999276416373 (db_fetched) http://localhost:8080/circle.jsp?time=124006908945776 (db_fetched) http://localhost:8080/circle.jsp?time=124015015509583 (db_fetched) http://localhost:8080/circle.jsp?time=124024925839499 (db_fetched) http://localhost:8080/circle.jsp?time=124034102389505 (db_fetched) http://localhost:8080/circle.jsp?time=124041764064461 (db_fetched) http://localhost:8080/circle.jsp?time=124049395271718 (db_fetched) http://localhost:8080/circle.jsp?time=124056979467640 (db_fetched) http://localhost:8080/circle.jsp?time=124064870330856 (db_fetched) http://localhost:8080/circle.jsp?time=124072499230132 (db_fetched) http://localhost:8080/circle.jsp?time=124080080885493 (db_fetched) http://localhost:8080/circle.jsp?time=124087617811162 (db_fetched) http://localhost:8080/circle.jsp?time=124095117258073 (db_fetched) http://localhost:8080/circle.jsp?time=124102663093132 (db_fetched) http://localhost:8080/circle.jsp?time=124110288582706 (db_fetched) http://localhost:8080/circle.jsp?time=124117843855932 (db_fetched) http://localhost:8080/circle.jsp?time=124125433893931 (db_fetched) http://localhost:8080/circle.jsp?time=124133061938250 (db_fetched) http://localhost:8080/circle.jsp?time=124140496939575 (db_fetched) http://localhost:8080/circle.jsp?time=124148039993387 (db_fetched) http://localhost:8080/circle.jsp?time=124155897999884 (db_unfetched)
六、查看提交給Solr的索引,發現索引文檔數爲30,言下之意就是Nutch並無內容去重(不一樣的URL有相同或99.99%近似的內容)功能,固然了,Nutch有對同一個URL的去重功能,由於同一個URL會有多個版本嘛。
Num Docs:30 Max Doc:30
七、也許你可能會以爲很奇怪,沒事搞這種指向自身的連接循環抓取幹什麼,難道有什麼好處?沒錯,確實有好處!咱們知道PageRank對搜索引擎結果排名的重要性,下面咱們看看Nutch抓了30次以後每一個頁面的分值狀況,circle.jsp的分值已經從注入時默認的1.0變爲2.0了,隨着抓取的次數愈來愈大,circle.jsp的分值就會愈來愈高!不過這種方法的分值提升仍是頗有限的,由於新發現的連接的分值=當前頁面的分值除以當前頁面的輸出連接數,因此新發現的URL的分值會愈來愈小(折半)。爲了讓效果更好,咱們能夠構造不少連接,讓他們之間相互引用,這樣效果就會好得多,這也叫作「連接農場」。
http://localhost:8080/circle.jsp (Score: 2.0) http://localhost:8080/circle.jsp?time=134316762995966 (Score: 1.0) http://localhost:8080/circle.jsp?time=134326310205035 (Score: 0.5) http://localhost:8080/circle.jsp?time=134333900156323 (Score: 0.25) http://localhost:8080/circle.jsp?time=134341614881614 (Score: 0.125) http://localhost:8080/circle.jsp?time=134349238025525 (Score: 0.0625) http://localhost:8080/circle.jsp?time=134356824616950 (Score: 0.03125) http://localhost:8080/circle.jsp?time=134364502496801 (Score: 0.015625) http://localhost:8080/circle.jsp?time=134372113078909 (Score: 0.0078125) http://localhost:8080/circle.jsp?time=134379790766293 (Score: 0.00390625) http://localhost:8080/circle.jsp?time=134387649892340 (Score: 0.001953125) http://localhost:8080/circle.jsp?time=134395940369325 (Score: 9.765625E-4) http://localhost:8080/circle.jsp?time=134405766166198 (Score: 4.8828125E-4) http://localhost:8080/circle.jsp?time=134415907784492 (Score: 2.4414062E-4) http://localhost:8080/circle.jsp?time=134423612474766 (Score: 1.2207031E-4) http://localhost:8080/circle.jsp?time=134433400896206 (Score: 6.1035156E-5) http://localhost:8080/circle.jsp?time=134440922627127 (Score: 3.0517578E-5) http://localhost:8080/circle.jsp?time=134448441822753 (Score: 1.5258789E-5) http://localhost:8080/circle.jsp?time=134456076637041 (Score: 7.6293945E-6) http://localhost:8080/circle.jsp?time=134463676417913 (Score: 3.8146973E-6) http://localhost:8080/circle.jsp?time=134471189704200 (Score: 1.9073486E-6) http://localhost:8080/circle.jsp?time=134479013725922 (Score: 9.536743E-7) http://localhost:8080/circle.jsp?time=134486694863121 (Score: 4.7683716E-7) http://localhost:8080/circle.jsp?time=134494120468014 (Score: 2.3841858E-7) http://localhost:8080/circle.jsp?time=134501673767138 (Score: 1.1920929E-7) http://localhost:8080/circle.jsp?time=134509163792495 (Score: 5.9604645E-8) http://localhost:8080/circle.jsp?time=134516640328157 (Score: 2.9802322E-8) http://localhost:8080/circle.jsp?time=134524359639021 (Score: 1.4901161E-8) http://localhost:8080/circle.jsp?time=134531631412690 (Score: 7.4505806E-9) http://localhost:8080/circle.jsp?time=134539151699502 (Score: 3.7252903E-9) http://localhost:8080/circle.jsp?time=134546846151757 (Score: 1.8626451E-9)