搜索引擎與Web Spider原理詳解

 

網絡蜘蛛(Web Spider)程序的實現是一個比較複雜而且有一些技術難點的工作,通過一段時間對其的研究,以及對完成一些數據抓取的用例進行了歸納總結,現詳細說明給其實現原理及技術難點講解給大家。
任意給一個入口即鏈接,便可以訪問整個互聯網,這就是網絡蜘蛛(Web Spider)的最終目標,當然這對於像GOOGLE,BAIDU,yahoo等一些搜索引擎的蜘蛛來說,肯定是需要做到這一點的。
但對於我們目前的情況來說,不需要訪問整個互聯網,而我們只需要提取我們所需要的信息就可以了,那麼對於網絡蜘蛛(Web Spider)的關鍵點不是抓取網頁數據,而是分析網頁數據。
對於每個網頁五花八門的數據格式,要分析出所需要的數據則是一件令人頭痛的問題,接下來我們先說說整個實現流程,然後針對每一個步驟詳細來說明
一下其實現原理及方法。
二. 網絡蜘蛛基本原理
網絡蜘蛛即 Web Spider,是一個很形象的名字呵呵。
把互聯網比喻成一個蜘蛛網,那麼Spider就是在網上爬來爬去的蜘蛛。
網絡蜘.蛛是通過網頁的鏈接地址來尋找網頁,從網站某一個頁面(通常是首頁)開始爬入,讀取網頁的內容,找到在網頁中的其它鏈接地址 ,然後通過這些鏈接地址尋找下一個網頁,這樣一直循環下去,直到把這個網站所有的網頁都抓取完爲止。

網絡蜘.蛛是通過網頁的鏈接地址來尋找網頁,從網站某一個頁面(通常是首頁)開始爬入,讀取網頁的內容,找到在網頁中的其它鏈接地址 ,然後通過這些鏈接地址尋找下一個網頁,這樣一直循環下去,直到把這個網站所有的網頁都抓取完爲止。
如果把整個互聯網當成一 個網站,那麼網絡蜘蛛(Web Spider)就可以用這個原理把互聯網上所有的網頁都抓取下來。
網絡蜘蛛實現的流程圖如圖:

 

那好我繼續往下講從圖中所看的設計原理。

三:網絡蜘蛛實現的關鍵點

1.從上述流程圖中我們可以看到,我們需要給定一個入口的URL,蜘蛛纔開始工作。

這裏我們就需要幾個隊列,來保存不同狀態的鏈 接。

按照嚴格的分類,我們需要四個隊列,即運行隊列,等待隊列,完成隊列,異常隊列,但針對具體情況,因爲太多隊列調度複雜 ,我們只用了二個隊列,等待隊列跟運行隊列合併成爲運行隊列,完成隊列,由於我們只針對特定的網站,所以異常隊列的必要性不 是太大。

我們的線程一直從運行隊列中讀取最先寫入隊列的URL,如果存在,則往下執行,如果運行隊列中沒有數據了,則終止蜘蛛 的運行。

每處理完一個URL,則把其寫入完成隊列,防止重複訪問。同時對於每個頁面上合法並過濾後的鏈接都會寫入運行隊列。

對於一般的小程序,隊列基本上用內存取存就可以了,但對於大型數據量而言,用內存保存數據肯定是不可取的,那麼我們採取的是 用數據庫模擬隊列,即建了二個表,一爲(RUNQUEUE)(運行隊列),一爲(SUCQUEUE)(完成隊列)。

兩表的字段相同,包括,隊列ID ,用來判斷鏈接的順序,爲先進先出做依據,隊列URL 即鏈接內容,隊列深度,即該鏈接所處的深度,用來判斷在多少層終止數據抓 取。同時寫了兩個方法,一爲取得最先進入隊列的數據,二爲移除該數據。

因此基本上模擬了隊列的特徵,可以進行海量數據的抓取 ,同時還可以進行斷點續抓的功能。

2 超鏈接的獲取及處理

對於任何網站的抓取,都少不了一個核心的東西,就是超鏈接,它是各個頁面之間相互關聯的鈕帶,也就是因爲它,才把龐大的一個 互聯網緊密的聯繫起來,使得各個頁面之間不是孤立無助的。

對於超鏈接的獲取來說,還有一個比較重要的問題,就是對於一個網站有太多的鏈接了,有外部鏈接,內部鏈接,絕對鏈接,相對的 等等形式的,如果我們不做任何處理的保存下來,那麼我想這個蜘蛛就會永無止境的跑下去了,卻不一定能獲取得我們想要的數據, 因此這是不可取的。對於此問題,我們需要提供幾個解決方法:

首先就是控制抓取層數,因爲對於每一個鏈接,我們都給了它一個與之相對應的層數,如果這個層大於我們所給的層,那麼就終止程 序;

第二個方法就是過濾關鍵字,就是對鏈接中的字詞進行分析,過濾掉一些關鍵字,或保留相關關鍵字,這裏也有二種方法:

第一就是隻取得包含我們所給定的關鍵字的鏈接,比如說 (ITkafeiting) 我們只取得包含 (ITkafeiting) 這個詞的鏈接,不包含的 我們就丟掉,這樣所取的鏈接即爲內部鏈接,並且這樣的關鍵字是可以替加的,比如說我們要取得的鏈接中必須包含ITkafeiting 和 html 還是其它的都可以。

第二種方法就是取得不包含我們所給定的關鍵字的鏈接,同時該關鍵字也是可替加的,這樣一來,我們就很容易的對抓取鏈接進行篩 選,獲得我們需要的鏈接。

第三就是設置獲取鏈接的個數,超過這個數字就終止;.

第四就是設置運行時間,一旦到時間就終止。因此現在只是採取了第一和第二種方法,對於每個頁面上的鏈接的獲得的方法有二種, 第一種就是用正則表達式,但這種方法我個人覺得不是太好,如果鏈接的格式不同,或者javascript 中的鏈接就不一定能抓得下來 ;第二種方法,就是用JAVA自帶的解釋HTML 的包HTMLEditorKit,這種方法我覺得不會漏掉任何的鏈接,不管是相對的還是絕對的, 同時效率比用正則表達式高,因此,我們基本上是採用這種方式。

對於鏈接的形式的不同,因爲有相對的,絕對的,還有其它各種情況的,針對此問題,我特別寫了一個方法,把所有的鏈接全部轉換 成絕對的鏈接。這樣那麼就不會漏掉任何有用的數據。

對於鏈接過濾主要涉及兩個數組,第一個數組即是必須存在的關鍵字組,這一數組中,可以根據具體的網站頁面鏈接情況進行配置, 同時其數組的個數是無限制的,分析鏈接時,鏈接中必須存在這個數組中所有的關鍵字,如果有任何一個不存在,則都會丟棄該鏈接 。

如:該數組中有關鍵字,“http”, “ITkafeiting”, “html”,那麼只有包含這些關鍵字的鏈接纔有效,  http://www.itkafeiting.com/index.html該鏈接則是有效的,而 http://www.itkafeiting.com/index.asp這樣的鏈接則會被丟棄, 並且該數組一定要配置;第二個數組則爲不需要存在的關鍵字組,這一數組中,也是根據具體的網站頁面鏈接情況進行配置的,同時 其數組個數也是無限制的,分析鏈接時,鏈接中必須不存在這個數組中的任何一個關鍵字,如果有任何一個存在,則會丟棄該鏈接。

如:該數組中有關鍵字,“asp”,那麼 http://www.itkafeiting.com/index.asp則會被丟棄,該數組的配置是可選的,根據實際情 況可不配置,兩個數組是同時使用的,進一步保證了鏈接的高過濾性。
21:01:14
爲了避免死循環,防止重複抓取頁面,除了上述過濾鏈接外,還需要判斷,我們需要入庫的鏈接是否存在,因此需要把該鏈接與數據 庫中的隊列表中的數據進行判斷(運行隊列和完成隊列都要判斷),如存在則丟棄,不存在則寫入運行隊列。


通過上述方法,就可以很好的,很方便,很靈活的提取我們需要的相關鏈接進行處理,從而避免了太多無用鏈接的麻煩。

(呵呵講到這裏有點累了,還是堅持一下,我繼續往下講.下面說一下頁面內容抓取.)
通過從運行隊列中取得的鏈接,則可以抓取該頁面的所有源代碼內容。這裏主要應用到了 SUN 公司提供的NET 包。首先把鏈接先成  URL 實例,通過HTTPConnection 方法打開該鏈接,然後獲得其頁面內容的信息流。
再把該信息流轉換成我們需要的字符串,這裏面 有個問題是流只能應用一次,而在我們通過HTML 解析器獲取其超鏈接的時候用的是流,因此沒辦法用二次流,經過思考先統一轉成 字符串,然後在需要的時候,再把字符串轉成流,從而達到我們的要求。

4.如何解析HTML 內容

當頁面的內容抓取下來以後,那麼接下來的事情就是解析 HTML 內容,並根據我們的需要提取相關的數據內容入庫。

因爲每個網站的風格各異,頁面格式也各異,因此想做成一個通用的能解析所有網頁的程序是不太可能的,那麼這一部分就是比較靈 活的,需要我們根據不同的網站,以及我們所需的不同的內容進行靈活方便的配置,或者做小部分改動即可應用就很不錯了。

因爲 HTML 語言的特殊性,解析它是個非常麻煩的問題,通過比較發現採用正則表達式來分析HTML 是非常好的一種方式。因爲在我 們的蜘蛛程序中,所有的解析都是採用正則表達式實現的。
通過對很多網站的內容進行分析以後,我們發現,解析後形成的結果無非 就是四種情況,借用表的形式來說明比較直觀,即,單行單列,單行多列,多行單列,多行多列,因此,我們針對這四種情況分析寫 了四個不同的方法,返回不同的結果及類型,同時針對不同的頁面,可能出現這四種類型的嵌套,循環等形式,需要根據實際情況來 定。

同時根據網站不同,所取數據的不同,需要寫一個或多個正則表達式。對於正則表達式的解析,我們採用開源項目組裏的一個正則表 達式包,功能比較強大。同時基本上與微軟的正則表達式的規則區別不是太大,因此,使用起來更方便。

5.數據入庫

通過對頁面內容的解析,就會提取到我們需要的數據,然後對數據進行優化,比如把全角轉成半角,去掉其兩邊空格,
或對一些日期等進行格式化以後,基本上就入庫了。入庫的時候還需要針對不同的字段進行判斷,該記錄是否存在,如存在,
則放棄,儘可能提高入庫數據的唯一性。

6 線程的實現意義及方法

對於網絡蜘蛛而言,必須採用線程進行循環,因爲這樣可以提高效率,避免死循環,週期性運行而無需人工干預,易於
控制,易於採用多線程等。

當然採用線程也會有一些弊端,如網絡阻塞的話,那麼整個線程一直處於等待狀態而導致死亡。

那麼這裏我們採用了一種線程監控的方法,就是說有二個線程在運行,一個是主線程,另一個是監控線程,監控線程每隔一段時間就去訪問主線種與其共享的變量,一旦發現超時,即認爲網絡阻塞,於時殺掉線程,重新啓動該線程。

避免了由於網絡阻塞而線程一直等待的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章