李健
(戰(zhàn)略支援部隊(duì)信息工程大學(xué),洛陽(yáng)471003)
網(wǎng)絡(luò)爬蟲(chóng)是按照一定規(guī)則自動(dòng)獲取Web信息資源的計(jì)算機(jī)程序[1-2]。根據(jù)目標(biāo)資源的位置不同,網(wǎng)絡(luò)爬蟲(chóng)可以分為淺層爬蟲(chóng)和深層爬蟲(chóng)。通過(guò)超鏈接能夠直接到達(dá)的為淺層數(shù)據(jù),需要用戶登錄、提交表單、異步加載等操作才能獲得的為深層數(shù)據(jù)[3-4]。研究發(fā)現(xiàn),Web中的深層數(shù)據(jù)量遠(yuǎn)遠(yuǎn)超過(guò)淺層數(shù)據(jù)[5-6],因此深層爬蟲(chóng)就顯得十分重要。目前,異步加載技術(shù)廣泛使用,這給網(wǎng)絡(luò)爬蟲(chóng)的開(kāi)發(fā)帶來(lái)一些困難。對(duì)此,可采用模擬瀏覽器的方法進(jìn)行采集——讓瀏覽器內(nèi)核去處理那些復(fù)雜的技術(shù)細(xì)節(jié),爬蟲(chóng)只需要模擬用戶操作,等待目標(biāo)數(shù)據(jù)返回[7-9]。在爬取過(guò)程中,可通過(guò)DOM路徑實(shí)現(xiàn)對(duì)元素的定位和數(shù)據(jù)的抽取[10-12]。
隨著人工智能技術(shù)的發(fā)展,機(jī)器翻譯的準(zhǔn)確率也不斷提高,很多互聯(lián)網(wǎng)公司(如谷歌、百度、微軟等)都提供了在線翻譯服務(wù)。對(duì)于普通用戶來(lái)說(shuō),網(wǎng)頁(yè)翻譯是最主要的服務(wù)形式,而且是完全免費(fèi)的。網(wǎng)頁(yè)翻譯雖然免費(fèi),但是往往會(huì)限制單次翻譯的字?jǐn)?shù)。對(duì)于少量翻譯任務(wù),我們可將原文復(fù)制到翻譯頁(yè)面就可以獲取翻譯結(jié)果;但對(duì)于較大規(guī)模的翻譯任務(wù),若仍采用手動(dòng)方式(逐段復(fù)制粘貼)則顯得十分低效。對(duì)此,可以采用“多次少取”的方式解決大規(guī)模語(yǔ)料的自動(dòng)翻譯問(wèn)題。本文將設(shè)計(jì)并實(shí)現(xiàn)一個(gè)基于Gecko瀏覽器內(nèi)核的翻譯爬蟲(chóng)——借助“谷歌翻譯頁(yè)面”實(shí)現(xiàn)自動(dòng)批量翻譯。
網(wǎng)頁(yè)瀏覽器(Web Browser)簡(jiǎn)稱瀏覽器,是一種用于檢索并展示萬(wàn)維網(wǎng)信息資源的應(yīng)用程序。用戶所看到的網(wǎng)頁(yè)都是經(jīng)過(guò)瀏覽器解析、渲染后呈現(xiàn)出的結(jié)果,而并非原始網(wǎng)頁(yè)數(shù)據(jù)。瀏覽器的核心功能就是解析網(wǎng)頁(yè),解析對(duì)象主要包括HTML、CSS和JavaScript,分別對(duì)應(yīng)網(wǎng)頁(yè)的內(nèi)容、樣式和行為。瀏覽器解析網(wǎng)頁(yè)的基本過(guò)程如圖1所示[13]。
圖1 瀏覽器解析網(wǎng)頁(yè)的過(guò)程
資源加載后,瀏覽器會(huì)將HTML數(shù)據(jù)解析成DOM樹(shù),將CSS數(shù)據(jù)解析成CSS規(guī)則樹(shù),還可以通過(guò)執(zhí)行JavaScript代碼對(duì)它們進(jìn)行操作。解析完成以上對(duì)象,瀏覽器引擎通過(guò)DOM樹(shù)和CSS規(guī)則樹(shù)來(lái)構(gòu)造渲染樹(shù)(Render Tree),結(jié)合其他資源最終生成頁(yè)面展示效果。
瀏覽器內(nèi)核是指瀏覽器的核心部件,主要包括頁(yè)面渲染器和JS解析器。頁(yè)面渲染器負(fù)責(zé)把數(shù)據(jù)轉(zhuǎn)換為用戶在屏幕所看到的樣式,JS解析器負(fù)責(zé)解釋和執(zhí)行網(wǎng)頁(yè)中的JS代碼[14]。表1列出了常見(jiàn)瀏覽器內(nèi)核[15-18]。
表1 常見(jiàn)瀏覽器內(nèi)核
Trident是由微軟公司開(kāi)發(fā)的瀏覽器內(nèi)核,隨Internet Explorer 4.0首次發(fā)布(也稱IE內(nèi)核)。Trident目前仍然是主流的瀏覽器內(nèi)核之一,并被廣范應(yīng)用于其他非IE瀏覽器。WebKit是由蘋果公司開(kāi)發(fā)維護(hù)的開(kāi)源瀏覽器內(nèi)核,所包含的WebCore引擎和JSCore引擎都是從自由軟件衍生而來(lái)。Chrome和Opera瀏覽器早期也曾采用WebKit內(nèi)核,由于某些原因Google公司從WebKit中分支出自己的Blink內(nèi)核,隨后Opera公司也宣布將轉(zhuǎn)向Blink內(nèi)核。Gecko是一個(gè)能夠跨平臺(tái)使用開(kāi)源項(xiàng)目,該內(nèi)核最早由Netscape公司開(kāi)發(fā),現(xiàn)在由Mozilla基金會(huì)維護(hù)[19]。
GeckoFx是對(duì)Gecko內(nèi)核的.NET封裝,提供完善的編程接口,這使得.NET程序員可以在WinForm或WFP程序中方便地使用Gecko內(nèi)核。在Visual Studio中通過(guò)NuGet包管理器可直接安裝GeckoFx。
在DOM標(biāo)準(zhǔn)下,HTML文檔中的每個(gè)成分都是節(jié)點(diǎn):大到整個(gè)HTML文檔,小到每個(gè)HTML標(biāo)簽,甚至底層的純文本都被看作一個(gè)結(jié)點(diǎn)[20]。GeckoFx核心類之間的關(guān)系如圖2所示。其中實(shí)線表示繼承關(guān)系,虛線表示包含關(guān)系。
圖2 GeckoFx核心類
在GeckoFx框架中,GeckoNode表示所有DOM結(jié)點(diǎn)的基類,GeckoDomDocument用于描述DOM文檔,GeckoDocument用于描述Html文檔,Gecko Element用于描述DOM元素,Gecko Html Element用于描述HTML標(biāo)簽元素。Gecko Web Browser是一個(gè)Web瀏覽器控件(可直接顯示在WinForm窗體中),其DomDocument和Document屬性分別屬于GeckoDomDocument和Gecko Document類型。通過(guò)上述對(duì)象,可以實(shí)現(xiàn)頁(yè)面的加載和導(dǎo)航,元素的查詢和修改。
為了便于描述,我們將任務(wù)簡(jiǎn)化為對(duì)中文詞表的翻譯,每次提交一個(gè)詞條進(jìn)行翻譯,翻譯完成后可導(dǎo)出雙語(yǔ)詞表。并具體規(guī)定如下:中文詞表按行存放于文本文件中(對(duì)應(yīng)全部翻譯任務(wù)),每次提交一行文本進(jìn)行翻譯(對(duì)應(yīng)單次翻譯任務(wù)),翻譯結(jié)果以Excel格式導(dǎo)出。翻譯爬蟲(chóng)的總體架構(gòu)如圖3所示。
圖3 翻譯爬蟲(chóng)架構(gòu)
根據(jù)上述思路,爬蟲(chóng)工作流程如圖4所示:首先使用瀏覽器控件加載翻譯頁(yè)面;然后提示用戶選擇并導(dǎo)入中文詞表;每次從待翻譯詞表中取出一個(gè)詞條,復(fù)制到翻譯網(wǎng)頁(yè)的原文輸入框,等待翻譯結(jié)果返回,從譯文輸出框讀取結(jié)果;若翻譯任務(wù)全部完成則導(dǎo)出結(jié)果,否則繼續(xù)翻譯下一詞條。
圖4 翻譯爬蟲(chóng)工作流程
爬蟲(chóng)界面如圖5所示:使用分隔容器(SplitContain?er)將主窗體分為左右兩個(gè)區(qū)域,左側(cè)為用戶操作區(qū),包括兩個(gè)按鈕(導(dǎo)入、導(dǎo)出)和一個(gè)DataGridView控件;右側(cè)是翻譯頁(yè)面加載區(qū),GeckoWebBrowser控件充滿整個(gè)區(qū)域。
圖5 翻譯爬蟲(chóng)主界面
我們?cè)?NET平臺(tái)下使用C#語(yǔ)言編寫程序,實(shí)現(xiàn)了谷歌翻譯爬蟲(chóng)的全部功能。下面將介紹關(guān)鍵模塊的實(shí)現(xiàn)。
爬蟲(chóng)啟動(dòng)后,首先需要初始化Gecko運(yùn)行環(huán)境,才能使用GeckoWebBrowser控件加載頁(yè)面。其主要代碼如下:
上述代碼定義了一個(gè)GeckoWebBrowser類型的成員變量(browser),表示Gecko瀏覽器控件;頁(yè)面跳轉(zhuǎn)后為瀏覽器控件添加Document Completed事件,以保證網(wǎng)頁(yè)加載完畢才能導(dǎo)入詞表。
翻譯爬蟲(chóng)的關(guān)鍵步驟就是要模擬用戶操作,在瀏覽器頁(yè)面中完成原文的輸入和譯文的讀取。通過(guò)Firefox開(kāi)發(fā)者工具箱查看頁(yè)面元素(如圖6圖所示),可以發(fā)現(xiàn)Google翻譯頁(yè)面的原文輸入框?yàn)橐粋€(gè)
圖6 查看網(wǎng)頁(yè)元素(輸入框)
同理,我們也可以找出“譯文輸出框”的定位:一個(gè)class屬性值為“tlid-translation translation”的元素。調(diào)用Gecko Dom Document.Get Elements By Class?Name()方法可獲取具有該class屬性值的元素列表。測(cè)試發(fā)現(xiàn):該網(wǎng)頁(yè)中具有上述class屬性值的元素是唯一的(僅表示輸入框),這將使程序處理變得簡(jiǎn)單?!皩懭朐摹焙汀白x取譯文”的主要代碼如下:
本研究發(fā)現(xiàn),石河子大學(xué)本科生學(xué)習(xí)動(dòng)機(jī)居中等程度。經(jīng)過(guò)對(duì)數(shù)據(jù)的進(jìn)一步分析發(fā)現(xiàn),總平均分小于臨界的比例相當(dāng)大,共96人,即有52.17%的大學(xué)生學(xué)習(xí)動(dòng)機(jī)水平不高;總平均分高于4分的(學(xué)習(xí)動(dòng)機(jī)較強(qiáng))僅4人,占總?cè)藬?shù)的2.17%。從總體上看,本研究證實(shí)了當(dāng)今大學(xué)生學(xué)習(xí)動(dòng)機(jī)偏低,只有在能力追求維度上得分接近4分,其余均不到3分。因此,需要在教育教學(xué)中重視石河子大學(xué)本科生的學(xué)習(xí)動(dòng)機(jī)。
在上述代碼中,Translate函數(shù)被聲明為async(異步的),并在函數(shù)中使用了await語(yǔ)句。借助await語(yǔ)句可采用同步編程風(fēng)格實(shí)現(xiàn)異步功能,當(dāng)程序執(zhí)行到await語(yǔ)句時(shí)并不會(huì)引起中主線程(UI線程)的阻塞,而是將之后的代碼動(dòng)態(tài)封裝成一個(gè)回調(diào)函數(shù),待任務(wù)結(jié)束后自動(dòng)調(diào)用。這樣既能控制翻譯任務(wù)的執(zhí)行步驟,又不會(huì)造成窗體假死(無(wú)法響應(yīng)用戶操作)。需要說(shuō)明的是,網(wǎng)頁(yè)結(jié)構(gòu)并非固定不變,若谷歌翻譯頁(yè)面改版,則需要重新定位輸入、輸出框位置。
當(dāng)點(diǎn)擊“導(dǎo)入中文詞表”按鈕時(shí),會(huì)提示用戶選擇詞表文件,并將其讀入列表中;然后調(diào)用BatchTranslate方法完成批量翻譯,原文列表將作為參數(shù)傳入。主要代碼如下:
在爬蟲(chóng)程序中,我們借助一個(gè)bool類型的變量(stopTag)來(lái)控制翻譯任務(wù)的啟停。初始狀態(tài)下stop?Tag默認(rèn)為false(表示不停止),按鈕文本為“導(dǎo)入中文詞表”;若此時(shí)按下按鈕則啟動(dòng)翻譯任務(wù),并將按鈕文本改變?yōu)椤巴V埂保蝿?wù)完成后文本自動(dòng)恢復(fù);若用戶在任務(wù)執(zhí)行過(guò)程中按下“停止”按鈕,stopTag將被置為true(表示停止),程序檢測(cè)到stopTag的變化則停止當(dāng)前任務(wù)。由于在BatchTranslate方法中使用了await語(yǔ)句等待翻譯結(jié)果,因此該方法也被聲明為async。批量翻譯的執(zhí)行過(guò)程如圖7所示。
圖7 程序運(yùn)行效果
待全部翻譯任務(wù)完成后,單擊“導(dǎo)出雙語(yǔ)詞表”按鈕可將翻譯結(jié)果以Excel格式導(dǎo)出,具體實(shí)現(xiàn)代碼這里不再列出。
分析發(fā)現(xiàn),爬蟲(chóng)執(zhí)行過(guò)程中最耗時(shí)的步驟就是等待翻譯結(jié)果,而且每次翻譯需要等待的時(shí)間并不固定,這受原文長(zhǎng)度、網(wǎng)絡(luò)條件、服務(wù)器負(fù)載等因素的影響。因此,設(shè)置一個(gè)適當(dāng)?shù)牡却龝r(shí)間十分重要:若時(shí)間太短則翻譯尚未完成,若時(shí)間太長(zhǎng)則影響爬蟲(chóng)效率。此前的程序每次固定等待2秒,一般情況下這個(gè)時(shí)間足夠長(zhǎng)但效率偏低。我們希望能夠在譯文返回后盡快讀取結(jié)果,在改進(jìn)方案中采用“輪詢檢測(cè)法”判斷翻譯結(jié)果是否返回。改進(jìn)后的代碼如下:
上述代碼中的Clear Dest Text方法用于清空譯文(具體代碼從略),在寫入原文之前先調(diào)用此函數(shù),以避免上次翻譯結(jié)果干擾到本次判斷。為驗(yàn)證“輪詢檢測(cè)法”的性能,我們將其與“定時(shí)等待法”進(jìn)行對(duì)比測(cè)試。
圖8 “定時(shí)等待法”性能統(tǒng)計(jì)
對(duì)于“輪詢檢測(cè)法”,我們統(tǒng)計(jì)了采用不同“輪詢間隔”對(duì)程序性能的影響(如圖9所示)。統(tǒng)計(jì)結(jié)果表明:此方法總能保證100%的“采準(zhǔn)率”,平均翻譯時(shí)長(zhǎng)也明顯優(yōu)于“定時(shí)等待法”。同時(shí),我們發(fā)現(xiàn)輪詢間隔并非越小越好(設(shè)定在0.1秒左右較為合適),因?yàn)殚g隔時(shí)間越小就意味著輪詢次數(shù)越多,而輪詢本身也需要消耗系統(tǒng)資源。
圖9 “間隔輪詢法”性能統(tǒng)計(jì)
為了進(jìn)一步說(shuō)明“定時(shí)等待法”難以兼顧準(zhǔn)度和效率,我們采用“間隔輪詢”法對(duì)同一組詞條(共13個(gè))進(jìn)行5次翻譯測(cè)試,并將用時(shí)分布情況繪制成“箱線圖”(如圖10所示)。
圖10 翻譯等待時(shí)間分布
統(tǒng)計(jì)結(jié)果顯示:雖然平均翻譯時(shí)間都在1秒左右,但每次總有幾個(gè)詞條偏離平均值較遠(yuǎn)。翻譯等待時(shí)間的不穩(wěn)定性正是“定時(shí)等待法”效率不高原因。
本文所介紹的“谷歌翻譯爬蟲(chóng)”不僅實(shí)現(xiàn)了既定功能,達(dá)到了預(yù)期效果;而且進(jìn)行了算法優(yōu)化,提高了采集效率。測(cè)試表明:本文所提出的方案是行之有效的,可以為同類爬蟲(chóng)的開(kāi)發(fā)提供技術(shù)參考。筆者在項(xiàng)目實(shí)踐中發(fā)現(xiàn),越來(lái)越多的網(wǎng)頁(yè)采用異步加載技術(shù),傳統(tǒng)的網(wǎng)絡(luò)爬蟲(chóng)難以發(fā)揮作用。模擬瀏覽器的方式可以屏蔽內(nèi)部技術(shù)細(xì)節(jié),減化爬蟲(chóng)開(kāi)發(fā)的復(fù)雜度。其中,如何模擬用戶操作(如輸入文本、選擇列表、點(diǎn)擊按鈕、滾動(dòng)頁(yè)面等),是實(shí)現(xiàn)爬蟲(chóng)功能的基礎(chǔ);如何判斷目標(biāo)數(shù)據(jù)返回,是提高爬蟲(chóng)效率的關(guān)鍵。