陸亮 李東
摘要:分析了Web2.0網絡的網絡爬蟲面臨的新挑戰,對目前學術界出現的多種實現方案和策略進行了全面的綜述,提出了AJAX爬蟲的設計并加以實現,最后進行了實驗驗證,驗證了這種AJAX Crawler能夠很好地獲取AJAX的動態頁面,并與普通的爬蟲在下載速度方面進行了對比。
關鍵詞:動態網頁; AJAX; Web2.0; 網絡爬蟲
中圖分類號:TP393 文獻標識碼:A文章編號:2095-2163(2013)06-0057-04
0引言
Web2.0是相對Web1.0的新一代互聯網應用的統一名稱。Web1.0的重要特征是用戶通過使用瀏覽器獲取靜態的網絡信息。Web2.0則側重于用戶與用戶之間的交流和溝通,用戶不僅作為網頁內容的查看者,同時也是網頁內容的創造者。所說的網頁內容的創造者是指互聯網上的所有用戶不再只是互聯網內容的讀者,同時也成為了互聯網內容的作者;不再僅是沖浪于互聯網海洋之中,同時也是海洋波浪的制造者;在模式上由純粹的“只讀”變為“讀寫”進而發展成為“共同建設”;由簡單被動地接收互聯網信息轉變為主動創造互聯網信息,從而增加了互動,更加符合用戶的使用習慣。
近年來,隨著Web2.0的興起,在Web開發中運用AJAX技術的網站越來越多,這些技術的應用帶來了更好的用戶體驗、很多新概念和WebUI設計,同時,由于AJAX技術可以動態改變頁面內容,改造了傳統Web頁面的結構,導致單純抓取靜態Web頁面的網絡爬蟲抓取的內容少于頁面呈現的內容,這些動態內容給網絡爬蟲的設計帶來極大挑戰,使得爬蟲不能獲取到網頁頁面所呈現的全部文本。
本文研究能夠支持AJAX的網絡爬蟲的原理,實現一個支持AJAX且能夠進行定制任務的網絡爬蟲,高效率地對網頁信息進行采集。第1節介紹國內外對AJAX頁面的抓取研究情況,第2節介紹支持AJAX的爬蟲的設計及具體實現,第3節通過實驗驗證了支持AJAX的爬蟲的可行性。
1相關工作
現階段,主流的搜索引擎,例如:Yahoo!和Google等,都無法對AJAX動態網頁建立索引,也就是說不能利用現有的搜索引擎來查詢動態網頁的內容。而能夠支持AJAX的搜索引擎還處于研究階段,羅兵使用基于協議的動態頁面抓取方法,獲取AJAX網頁內包含的JavaScript代碼片段,通過設計腳本語言解釋器直接分析腳本代碼,仿照瀏覽器功能順序執行腳本文件,用來模擬頁面的狀態轉換[1],肖卓磊在之后的研究中也采用了類似的處理方法[2];曾偉輝、李淼利用切片算法構造了程序層次模型,解決了有序執行JavaScript腳本的問題[3];Frey[4]和Matter[5]改進了開源的JavaScript解釋器Rhino[6],用來實現狀態轉換和腳本執行。實現全部功能的腳本解釋器較為困難,即便是已開發多年的Rhino項目,依舊有很多的腳本代碼不能正常執行,于是,更多的研究人員將研究重點落定于嵌入式瀏覽器組件,運用組件來模擬AJAX頁面的渲染并實現腳本的執行,以達到自動轉換狀態的目的;在國內,采用類似方法研究的是王映[7]和金曉鷗[8],研究對使用網絡爬蟲分析腳本語言的技術進行了一些研究,前者使用的是開源的JavaScript引擎SpiderMonkey,而后者利用的是Rhino。因其均解析了包含JavaScript腳本代碼的動態頁面,從頁面中抓取了JavaScript代碼,由此獲得了網頁上的URL,并實現了內容爬取。Frey和Matter擴展了Cobra工具集[9],完成了動態解析和加載HTML代碼,然后在內部形成DOM結構樹,并通過DOM樹獲取狀態包含的內容。類似于狀態轉換問題,為了最大限度地利用現有的技術,多數的狀態內容獲得方式是采用嵌入瀏覽器組件作為運行AJAX容器,并使用瀏覽器的外部接口實現和DOM樹的數據交互,由此而獲得完整的內容[10-13]。
在控制轉換方面,較為常用的方式是采用事件過濾機制,對已經過濾后的事件逐一進行觸發。為了提高執行效率,Xia[12]和Duda[14]均提出讓用戶能夠自定義過濾規則,也就是加入拒絕規則和接收規則,如此即使得只有在符合規則的集合里才能進行狀態轉換;Mesbah等采用面向領域的手工配置、HTML元素注解和全自動掃描三種方式來對狀態轉換進行控制[10];Matter則提出了一種啟發式的爬行策略,盡量避免從不同路徑進入相同的頁面狀態[5]。
2AJAXCrawler爬蟲設計方案及實現
由于Web 2.0的流行,使用AJAX技術的網站越來越多,本文采用了Rhino引擎對AJAX進行了支持。
2.1 JavaScript引擎Rhino
Rhino采用Java語言實現的JavaScript腳本引擎。Rhino用在Java程序中,為最終用戶提供腳本化能力。Rhino包含JavaScript編譯器、JavaScript解析器、JavaScript調試等模塊。下面即對腳本編譯模塊和腳本解釋模塊進行全面分析。
2.1.1腳本編譯模塊
編譯器的輸入是JavaScript代碼,輸出是JavaScript數據對象。JavaScript結構中包含了字節碼、注釋、string池、數據以及標識符。JavaScript中還包含Objects,函數等。其中,函數也是一段嵌套的JavaScript代碼。編譯器由以下三部分組成:隨機邏輯(randomlogic)的詞法掃描器,用來創建AST的遞歸下降分析器,tree‐walking代碼生成器。編譯過程是由函數Main.processSource()來完成的,將輸入的字符串或者JavaScript代碼轉化成流文件進行編譯。在編譯過程中,所有的變量,符號以及命令等都由詞法分析器進行解析,再利用內部特定的符號標識,放入對應的數據棧中,最后將得到的數據用樹形結構返回,便于Rhino引擎編譯。在少分號或者是可賦值表達式等情況下,用語義和詞法的反饋(feedback)機制來消除歧義。編譯器沒有錯誤校正,因此,只要遇到錯誤,就立即停止。另外,編譯器還在編譯完成的script結構中加入sourcenotes信息,以便用戶調用toSource()函數進行反編譯時使用。
2.1.2腳本解釋模塊
類似大多數的JavaScript引擎,Rhino的interpreter是一個單線程的大型循環函數,該函數每次解釋bytecode的一個指令。在這個大型函數中,采用的是switch語句,即根據所要執行的bytecode的不同,跳轉到不同的執行代碼段中。大多數情況下,如果一段JavaScript代碼調用另一段JavaScript代碼,則引擎只會使用JavaScript的??臻g,interpreter也是順序執行的。但如果JavaScript代碼調用了java代碼,再由java代碼調用JavaScript代碼,就會引起interpreter的重入問題。需要一提的是,這個大型函數是可重入的。對于interpreter所需要的各種狀態都是通過參數的形式在interpreter函數進入時完成傳遞的。絕大多數的狀態都保存在數據結構Context中。因此,在Rhino里,所有的公共API接口以及大部分的函數接口中,第一位參數均是一個Context的指針。
2.2 AJAX爬蟲架構設計
爬蟲系統分為兩部分,第一部分是預處理階段,這個階段實現URL凈化,并去除不必要抓取的URL,類似于過濾器的功能。第二部分是網頁真正抓取的部分,由于網頁下載比較耗時,為了充分利用資源,此處采用了多線程。抓取階段獲得網頁,析出網頁內部的鏈接,而后進行預處理。并不是每個網頁內部的鏈接都是需要抓取的,網頁內部的鏈接可能包含以前抓取過的重復URL,Robots協議禁止抓取的URl等。CleanURLs是經過凈化后的URL庫,里面存放的都是需要抓取的URL。爬蟲的架構如圖1所示。
2.3AJAX引擎設計
AJAX引擎提供對網頁中AJAX的支持,能夠對網頁中的js代碼進行解析、執行,由此得到網頁動態內容。AJAX引擎架構如圖2所示。
由圖2中可見,AJAX引擎主要有三個組成部分。對AJAX頁面的解析按照下面的順序進行。
(1)Crawler通過HTTP請求,獲取需要抓取的頁面。此時的頁面是一個含有AJAX代碼的頁面,其中沒有真正的內容;
(2)DOMBuilder對頁面進行分析,建立DOM樹,提取出其中的JS代碼,觸發相應的事件;
(3)將AJAX代碼送入JavaScript引擎執行,在執行的過程中,同時根據JS對象與HTML對象映射修改HTML對象;
(4)將執行結果重新組合生成新的頁面內容,返回給Crawler。
3實驗數據結果
實驗基于Java平臺,開發環境采用Eclipse,Java虛擬機版本為JDK1.6.0,Rhino版本為1.7R2,實現AJAXCrawler。本文主要對AJAXCrawler進行了吞吐量的測試,并與普通的爬蟲進行下載速度的對比。
3.1吞吐量實驗
吞吐量實驗是測試AJAXCrawler數量以及每個AJAXCrawler啟動線程數與下載速度的關系。若啟動的AJAXCrawler或者每個AJAXCrawler中的線程數太少,則系統不能完全利用計算機的資源,反之則會因為帶寬、數據競爭等而降低效率。測試機器為一臺普通PC機,硬件配置以及軟件配置如表1所示。
表1服務器配置表
Tab.1 Server configuration listCPU2 * AMD Athlon(tm)ⅡX2 215 Processor 2.70GHz網卡100Mbps內存2.00GB操作系統Windows 7JAVA環境JRE 1.6.0_24
AJAXCrawler測試任務為天涯博客,通過改變AJAXCrawler以及每個AJAXCrawler內線程的數目,測得的數據如表2所示,繪制成折線圖,如圖3所示(單位:頁面數/10分鐘)。
由表2和圖3可以看出,在當前的計算環境和網絡環境下,當選取任務數為3,每個任務內有3個線程的時候,系統運行效率達到較優,平均每10分鐘能夠下載網頁1 679頁。
3.2AJAXCrawler與普通爬蟲比較實驗
此實驗以網易的評論為測試對象,分析AJAXCrawler的效率。由于普通爬蟲無法抓取到動態內容,此處的量化指標不再以頁面數/10分鐘作為單位,而是選擇Kb/second作為單位。測試結果如表3所示,繪制成折線圖如圖4所示。
由表3和圖4可以看到,AJAXCrawler無論是幾個任務并發執行,都相應地比普通的WebCrawler下載速度慢。除去實驗環境偶然因素外,最主要的影響因素應該是AJAXCrawler對AJAX腳本的解析和DOM樹的更新操作。因為AJAXCrawler在關閉掉動態頁面支持時,速度跟普通WebCrawler相差不大。圖4中的兩條線幾近平行,表明兩種爬蟲此時的加速比也相差不多。而AJAXCrawler的加速上升趨勢已開始走緩,這就說明AJAXCrawler需要更多的資源。另外,若對比下載的頁面數,兩者相差了十余倍,而下載速度卻相對不是很大,進一步說明了動態網頁包含的內容豐富。
4結束語
本文設計的能夠抓取支持AJAX動態網頁的網絡爬蟲,在抓取動態網頁方面,取得了良好的結果。與普通爬蟲相比,AJAXCrawler的下載速度稍慢,主要是對AJAX腳本的解析和DOM樹的更新會相對浪費時間。不過,下載的頁面數與普通爬蟲相比,數量卻多出了十余倍,抓取的內容會比普通爬蟲的內容要豐富很多。
參考文獻:
[1]羅兵.支持AJAX的互聯網搜索引擎爬蟲設計與實現[D].杭州:浙江大學,2007.
[2]肖卓磊.基于AJAX技術的搜索引擎研究[D].武漢:武漢理工大學,2009.
[3]曾偉輝,李淼.基于JavaScript切片的AJAX框架網絡爬蟲技術研究[J].北京:計算機系統應用,2009,18(7):169-171.
[4]FREYG.Indexing AJAX Web Applications. Zurich:Swiss Federal Institute of Technology Zurich,2007.
[5]MATTERR.AJAXCrawl:Making AJAX Applications Searchable. Zurich:Swiss Federal Institute of Technology Zurich,2008.
[6]MOZILLA.Rhino:JavaScript for Java.[2009-03-22].
[7]http://www.mozilla.org/rhino/.
[8]王映,于滿泉,李盛韜.JavaScript引擎在動態網頁采集技術中的應用[J].計算機應用,2004,24(2):33-36.
[9]金曉鷗,鐘寶燕,李翔.基于Rhino的JavaScript動態頁面解析研究與實現[J].計算機技術與發展,2008,18(2).
[10]COBRA.JavaHTMLRenderer&Parser.[2009-01-19].
[11]http://lobobrowser.org/cobra.jsp.
[12]MESBAHA,BOZDAGE,VANDEURSENA.Crawling AJAX by inferring user interface state changes[C]//Proceedings of the 8th International Conferenceon Web Engineering, YorktownHeights,NJ.Washington,DC,USA:IEEE Computer Society,2008:122-134.
[13]郭浩,陸余良,劉金紅.一種基于狀態轉換圖的AJAX爬行算法[J].計算機應用研究,2009,26(11):4266-4269.
[14]XIAT. Extracting structured data from AJAX site[C]//Proceedings of 2009 International IEEE Work shop on Database Technology and Applications, Wuhan, China.2009:259-262.