席文強(qiáng)
摘 要 當(dāng)今開(kāi)源瀏覽器引擎中,Web Kit與gecko平分秋色,但對(duì)于代碼結(jié)構(gòu)框架,Web Kit似乎要清晰很多,因此,對(duì)于網(wǎng)絡(luò)爬蟲(chóng)研究來(lái)說(shuō),Web Kit的移植研究顯得尤為重要。本文通過(guò)對(duì)Web Kit瀏覽器內(nèi)核移植目的的闡述,分析了移植過(guò)程中的各個(gè)步驟以及問(wèn)題改進(jìn)方法,對(duì)獲取網(wǎng)頁(yè)鏈接節(jié)點(diǎn)和實(shí)現(xiàn)步驟做了分析和研究。
關(guān)鍵詞 Web Kit;JS;Web Core;網(wǎng)絡(luò)爬蟲(chóng)
引言
1移植的目的
引擎的爬蟲(chóng)需要從給定的url中抽出盡可能多的正確鏈接,這不僅需要獲取到頁(yè)面源碼中顯式的url,還需要解析js,模擬一些事件來(lái)得到那些“隱藏”的鏈接。Web Kit可以滿(mǎn)足這個(gè)需要。并且,為了更方便地為引擎所用,減少引擎的體積,采用了自己移植的方式。
Web Kit的移植可以分為:組建工程,實(shí)現(xiàn)接口,封裝接口。對(duì)于不基于任何一個(gè)移植(如qt,gtk等)的移植,要做的工作非常多。但對(duì)于現(xiàn)在的需求,很多功能都是不需要的,這就簡(jiǎn)化了很多的工作量。對(duì)于必須要實(shí)現(xiàn)的接口,也都做的盡量簡(jiǎn)單[1]。
2移植工程
在移植的很多時(shí)候要參考別的平臺(tái)的移植,要把每個(gè)平臺(tái)的都看一下,每一個(gè)地方可能要參考不同的平臺(tái)。這個(gè)地方可以參考efl的。
在各個(gè)相應(yīng)的目錄下建立PlatformXXX.cmake或OptionXXX.cmake。OptionXXX.cmake里包含了編譯之前需要的一些信息,如編譯選項(xiàng)的打開(kāi)關(guān)閉等。在移植中,可以先把所有的關(guān)閉,通過(guò)字面意思看出需要打開(kāi)的先打開(kāi),在運(yùn)行時(shí)遇到問(wèn)題時(shí),要記住這邊的選擇,排查問(wèn)題時(shí)不要忘記這邊的影響。
PlatformXXX.cmake里包含要編譯的源文件,依賴(lài)的庫(kù)等。依賴(lài)的庫(kù)先選最小集,需要時(shí)添加。源文件參考其他移植,對(duì)于平臺(tái)相關(guān)的源文件,先不要加入。
這個(gè)步驟并不是一步完成的,實(shí)際上各個(gè)步驟都是穿插的,后面編譯或運(yùn)行時(shí)遇到的問(wèn)題,都可能要回到這里修改配置文件。
2.1 實(shí)現(xiàn)平臺(tái)相關(guān)的接口
在編譯時(shí),根據(jù)錯(cuò)誤建立相應(yīng)的目錄和文件,并在PlatformXXX.cmake中添加新建的源文件。這里必須要注意的一點(diǎn)是,接口先定義成空實(shí)現(xiàn),并在里面打印相應(yīng)的信息。這樣可以先通過(guò)編譯,但在后面運(yùn)行時(shí)可能會(huì)報(bào)錯(cuò)。而報(bào)錯(cuò)時(shí)就可以根據(jù)打印的信息確定是什么原因?qū)е?,從而?shí)現(xiàn)相應(yīng)的接口以使運(yùn)行正常。
這些接口Web Kit之所以空出,目的就是方便各個(gè)平臺(tái)的移植。對(duì)于一些平臺(tái)相關(guān)的接口,Web Kit采用的方式是建立一個(gè)托管類(lèi),這個(gè)托管類(lèi)中都是一些純虛函數(shù)。這樣,各個(gè)平臺(tái)在做自己的移植時(shí),就可以建立子類(lèi)繼承這個(gè)托管類(lèi),并實(shí)現(xiàn)其中的純虛函數(shù)。還有另外一種方式,就是空出未實(shí)現(xiàn)的接口,由移植時(shí)實(shí)現(xiàn)。
FrameLoaderClientXXX.cpp中有很多函數(shù)會(huì)在加載的過(guò)程中被調(diào)用,在其中完成一些與外界的交互后,再返過(guò)去調(diào)回到Web Core內(nèi)部。如果在程序執(zhí)行時(shí)某個(gè)函數(shù)內(nèi)中斷,可以參考其他移植如qt,明確接口的含義,以及需要回調(diào)的函數(shù),再具體實(shí)現(xiàn)[2]。
2.2 調(diào)用并封裝接口
調(diào)用內(nèi)部的接口使Web Kit運(yùn)行起來(lái)。如初始化、加載頁(yè)面、執(zhí)行動(dòng)作等。首先要定義Web View和Web Frame,Web View對(duì)應(yīng)Web Core內(nèi)的Page,在其中完成構(gòu)造,初始化等,以及與外界的交互(提供供python調(diào)用的類(lèi)和接口)。Web Frame對(duì)應(yīng)Web Core內(nèi)的Frame類(lèi),在這里開(kāi)始頁(yè)面的加載,數(shù)據(jù),配置的傳入等。
另外,對(duì)于傳給Web Kit的數(shù)據(jù)和配置,以及Web Kit報(bào)出的信息,由于需要在Web Core內(nèi)使用,則要在WTF內(nèi)定義。
3各模塊移植時(shí)的改動(dòng)
Web Kit移植時(shí)需要對(duì)各個(gè)瀏覽器內(nèi)核模塊進(jìn)行修改,以便于節(jié)省計(jì)算資源,對(duì)無(wú)用模塊進(jìn)行裁剪,同時(shí)添加回調(diào)空函數(shù)以保證有效性和可用性。
3.1 WTF模塊
WTF模塊這里放的都是Web Kit內(nèi)部定義的一些庫(kù)供其他模塊使用,算是最下層的,編譯的時(shí)候當(dāng)然也是最先編譯。里面有智能指針,各種容器,hashmap,內(nèi)存分配,線(xiàn)程等管理的接口。其中有Platform.h文件,里面是一些宏的定義,移植的時(shí)候需要稍作修改。
一些需要傳給Web Kit的配置信息,以及與外部與Web Kit交互的數(shù)據(jù),其類(lèi)的定義也要在這個(gè)模塊下。因?yàn)閃TF是最先編譯的,而Web Core和Web Kit都有可能會(huì)用到那些結(jié)構(gòu)。
3.2 Javascript Core模塊
JS引擎在移植的時(shí)候幾乎不需要?jiǎng)?。但有部分?nèi)存是分配在Heap中的,jscore中的垃圾回收,如果想實(shí)時(shí)回收,則需要在這里實(shí)現(xiàn)那些基于定時(shí)器的接口。如果要求不高,可以在外部通過(guò)調(diào)用Web Core內(nèi)提供的接口回收,GCController中的garbage CollectNow()等,但這個(gè)起的作用非常有限[3]。
3.3 Web Core模塊
這部分最需要說(shuō)的是定時(shí)器Timer。Web Kit中Timer實(shí)現(xiàn)的基本思想是:每個(gè)線(xiàn)程維護(hù)一個(gè)虛擬Timer的優(yōu)先級(jí)隊(duì)列,每次啟動(dòng)或停止一個(gè)虛擬Timer時(shí),都會(huì)設(shè)置該Timer的下次觸發(fā)時(shí)間(“next fire time”)。當(dāng)虛擬Timer的觸發(fā)時(shí)間變化時(shí),需要調(diào)整其在優(yōu)先級(jí)隊(duì)列的位置,以保證隊(duì)列的有效性。當(dāng)虛擬Timer啟動(dòng)或者先前的系統(tǒng)Timer觸發(fā)的時(shí)候,會(huì)調(diào)用由具體平臺(tái)實(shí)現(xiàn)的set Shared Timer Fire Time函數(shù),去設(shè)置系統(tǒng)Timer的等待時(shí)間,開(kāi)始新一輪的超時(shí)等待。
其中,Timer是個(gè)模板類(lèi),繼承于Timer Base,它就是所謂的虛擬定時(shí)器,提供了具體平臺(tái)的系統(tǒng)Timer觸發(fā)時(shí)的回調(diào)接口,以及啟動(dòng)和停止定時(shí)器的相關(guān)接口。另一方面,Timer Base提供了優(yōu)先級(jí)隊(duì)列(由堆結(jié)構(gòu)實(shí)現(xiàn))的訪(fǎng)問(wèn)接口,例如:heap Decrease Key用于調(diào)整堆,以保證當(dāng)前定時(shí)器的下次觸發(fā)時(shí)間縮短后優(yōu)先級(jí)仍然有效;heap Delete從優(yōu)先級(jí)隊(duì)列中刪除當(dāng)前定時(shí)器;heap Insert向優(yōu)先級(jí)隊(duì)列插入定時(shí)器。Timer Base中提供的優(yōu)先級(jí)訪(fǎng)問(wèn)接口直接操縱的是Thread Timers的m_timerheap成員。
因此定時(shí)器Timer一定要實(shí)現(xiàn)一個(gè)符合要求的。簡(jiǎn)單的定時(shí)器,比如基于時(shí)鐘的信號(hào),表面上能正常工作,但是會(huì)隱藏很多問(wèn)題。比如多線(xiàn)程,一些段錯(cuò)誤,還有內(nèi)存泄漏。
3.4 Web Kit接口層
在這里,要構(gòu)造兩個(gè)重要的對(duì)象,Page和Frame,以及相關(guān)的一些對(duì)象。要進(jìn)行一些必要的初始化,可以根據(jù)錯(cuò)誤提示進(jìn)行,也可以參考其他的移植[4]。
3.5 段錯(cuò)誤問(wèn)題
基于源碼移植的Web Kit,跑起來(lái)肯定會(huì)有很多段錯(cuò)誤??梢杂胓db調(diào)試。例如ASSERT FAILED:這類(lèi)段錯(cuò)誤比較常見(jiàn)。Web Kit為了方便排查問(wèn)題,盡量在錯(cuò)誤犯下之后最早的時(shí)候通過(guò)這種方式給出提示。也就是說(shuō),這個(gè)段錯(cuò)誤是Web Kit故意造成的,但造成的原因是Web Kit發(fā)現(xiàn)了異常的東西。未初始化:如果提示cannot access memory at 0x….,那有可能是這個(gè)原因。這時(shí)要考慮是不是在Web Kit移植層,該創(chuàng)建的對(duì)象沒(méi)有創(chuàng)建。
參考文獻(xiàn)
[1] 詹恒飛,楊岳湘,方宏.Nutch分布式網(wǎng)絡(luò)爬蟲(chóng)研究與優(yōu)化[J].計(jì)算機(jī)科學(xué)與探索,2011,5(1):68-74.
[2] 胡戎,馮仲科,蔣君志偉.基于CheerIO的MEAN Stack氣象數(shù)據(jù)網(wǎng)絡(luò)爬蟲(chóng)研究[J].農(nóng)業(yè)機(jī)械學(xué)報(bào),2016(6):275-282.
[3] 劉高軍,夏景隆.基于Heritrix的網(wǎng)絡(luò)爬蟲(chóng)研究與應(yīng)用[J].軟件導(dǎo)刊,2013,12(5):123-125.
[4] 賈海軍.基于URL及上下文的主題網(wǎng)絡(luò)爬蟲(chóng)研究[D].上海:上海師范大學(xué),2014.