李健
(戰略支援部隊信息工程大學,洛陽471003)
網絡爬蟲是按照一定規則自動獲取Web信息資源的計算機程序[1-2]。根據目標資源的位置不同,網絡爬蟲可以分為淺層爬蟲和深層爬蟲。通過超鏈接能夠直接到達的為淺層數據,需要用戶登錄、提交表單、異步加載等操作才能獲得的為深層數據[3-4]。研究發現,Web中的深層數據量遠遠超過淺層數據[5-6],因此深層爬蟲就顯得十分重要。目前,異步加載技術廣泛使用,這給網絡爬蟲的開發帶來一些困難。對此,可采用模擬瀏覽器的方法進行采集——讓瀏覽器內核去處理那些復雜的技術細節,爬蟲只需要模擬用戶操作,等待目標數據返回[7-9]。在爬取過程中,可通過DOM路徑實現對元素的定位和數據的抽取[10-12]。
隨著人工智能技術的發展,機器翻譯的準確率也不斷提高,很多互聯網公司(如谷歌、百度、微軟等)都提供了在線翻譯服務。對于普通用戶來說,網頁翻譯是最主要的服務形式,而且是完全免費的。網頁翻譯雖然免費,但是往往會限制單次翻譯的字數。對于少量翻譯任務,我們可將原文復制到翻譯頁面就可以獲取翻譯結果;但對于較大規模的翻譯任務,若仍采用手動方式(逐段復制粘貼)則顯得十分低效。對此,可以采用“多次少取”的方式解決大規模語料的自動翻譯問題。本文將設計并實現一個基于Gecko瀏覽器內核的翻譯爬蟲——借助“谷歌翻譯頁面”實現自動批量翻譯。
網頁瀏覽器(Web Browser)簡稱瀏覽器,是一種用于檢索并展示萬維網信息資源的應用程序。用戶所看到的網頁都是經過瀏覽器解析、渲染后呈現出的結果,而并非原始網頁數據。瀏覽器的核心功能就是解析網頁,解析對象主要包括HTML、CSS和JavaScript,分別對應網頁的內容、樣式和行為。瀏覽器解析網頁的基本過程如圖1所示[13]。

圖1 瀏覽器解析網頁的過程
資源加載后,瀏覽器會將HTML數據解析成DOM樹,將CSS數據解析成CSS規則樹,還可以通過執行JavaScript代碼對它們進行操作。解析完成以上對象,瀏覽器引擎通過DOM樹和CSS規則樹來構造渲染樹(Render Tree),結合其他資源最終生成頁面展示效果。
瀏覽器內核是指瀏覽器的核心部件,主要包括頁面渲染器和JS解析器。頁面渲染器負責把數據轉換為用戶在屏幕所看到的樣式,JS解析器負責解釋和執行網頁中的JS代碼[14]。表1列出了常見瀏覽器內核[15-18]。

表1 常見瀏覽器內核
Trident是由微軟公司開發的瀏覽器內核,隨Internet Explorer 4.0首次發布(也稱IE內核)。Trident目前仍然是主流的瀏覽器內核之一,并被廣范應用于其他非IE瀏覽器。WebKit是由蘋果公司開發維護的開源瀏覽器內核,所包含的WebCore引擎和JSCore引擎都是從自由軟件衍生而來。Chrome和Opera瀏覽器早期也曾采用WebKit內核,由于某些原因Google公司從WebKit中分支出自己的Blink內核,隨后Opera公司也宣布將轉向Blink內核。Gecko是一個能夠跨平臺使用開源項目,該內核最早由Netscape公司開發,現在由Mozilla基金會維護[19]。
GeckoFx是對Gecko內核的.NET封裝,提供完善的編程接口,這使得.NET程序員可以在WinForm或WFP程序中方便地使用Gecko內核。在Visual Studio中通過NuGet包管理器可直接安裝GeckoFx。
在DOM標準下,HTML文檔中的每個成分都是節點:大到整個HTML文檔,小到每個HTML標簽,甚至底層的純文本都被看作一個結點[20]。GeckoFx核心類之間的關系如圖2所示。其中實線表示繼承關系,虛線表示包含關系。

圖2 GeckoFx核心類
在GeckoFx框架中,GeckoNode表示所有DOM結點的基類,GeckoDomDocument用于描述DOM文檔,GeckoDocument用于描述Html文檔,Gecko Element用于描述DOM元素,Gecko Html Element用于描述HTML標簽元素。Gecko Web Browser是一個Web瀏覽器控件(可直接顯示在WinForm窗體中),其DomDocument和Document屬性分別屬于GeckoDomDocument和Gecko Document類型。通過上述對象,可以實現頁面的加載和導航,元素的查詢和修改。
為了便于描述,我們將任務簡化為對中文詞表的翻譯,每次提交一個詞條進行翻譯,翻譯完成后可導出雙語詞表。并具體規定如下:中文詞表按行存放于文本文件中(對應全部翻譯任務),每次提交一行文本進行翻譯(對應單次翻譯任務),翻譯結果以Excel格式導出。翻譯爬蟲的總體架構如圖3所示。

圖3 翻譯爬蟲架構
根據上述思路,爬蟲工作流程如圖4所示:首先使用瀏覽器控件加載翻譯頁面;然后提示用戶選擇并導入中文詞表;每次從待翻譯詞表中取出一個詞條,復制到翻譯網頁的原文輸入框,等待翻譯結果返回,從譯文輸出框讀取結果;若翻譯任務全部完成則導出結果,否則繼續翻譯下一詞條。

圖4 翻譯爬蟲工作流程
爬蟲界面如圖5所示:使用分隔容器(SplitContain?er)將主窗體分為左右兩個區域,左側為用戶操作區,包括兩個按鈕(導入、導出)和一個DataGridView控件;右側是翻譯頁面加載區,GeckoWebBrowser控件充滿整個區域。

圖5 翻譯爬蟲主界面
我們在.NET平臺下使用C#語言編寫程序,實現了谷歌翻譯爬蟲的全部功能。下面將介紹關鍵模塊的實現。
爬蟲啟動后,首先需要初始化Gecko運行環境,才能使用GeckoWebBrowser控件加載頁面。其主要代碼如下:

上述代碼定義了一個GeckoWebBrowser類型的成員變量(browser),表示Gecko瀏覽器控件;頁面跳轉后為瀏覽器控件添加Document Completed事件,以保證網頁加載完畢才能導入詞表。
翻譯爬蟲的關鍵步驟就是要模擬用戶操作,在瀏覽器頁面中完成原文的輸入和譯文的讀取。通過Firefox開發者工具箱查看頁面元素(如圖6圖所示),可以發現Google翻譯頁面的原文輸入框為一個

圖6 查看網頁元素(輸入框)
同理,我們也可以找出“譯文輸出框”的定位:一個class屬性值為“tlid-translation translation”的元素。調用Gecko Dom Document.Get Elements By Class?Name()方法可獲取具有該class屬性值的元素列表。測試發現:該網頁中具有上述class屬性值的元素是唯一的(僅表示輸入框),這將使程序處理變得簡單。“寫入原文”和“讀取譯文”的主要代碼如下:
本研究發現,石河子大學本科生學習動機居中等程度。經過對數據的進一步分析發現,總平均分小于臨界的比例相當大,共96人,即有52.17%的大學生學習動機水平不高;總平均分高于4分的(學習動機較強)僅4人,占總人數的2.17%。從總體上看,本研究證實了當今大學生學習動機偏低,只有在能力追求維度上得分接近4分,其余均不到3分。因此,需要在教育教學中重視石河子大學本科生的學習動機。

在上述代碼中,Translate函數被聲明為async(異步的),并在函數中使用了await語句。借助await語句可采用同步編程風格實現異步功能,當程序執行到await語句時并不會引起中主線程(UI線程)的阻塞,而是將之后的代碼動態封裝成一個回調函數,待任務結束后自動調用。這樣既能控制翻譯任務的執行步驟,又不會造成窗體假死(無法響應用戶操作)。需要說明的是,網頁結構并非固定不變,若谷歌翻譯頁面改版,則需要重新定位輸入、輸出框位置。
當點擊“導入中文詞表”按鈕時,會提示用戶選擇詞表文件,并將其讀入列表中;然后調用BatchTranslate方法完成批量翻譯,原文列表將作為參數傳入。主要代碼如下:


在爬蟲程序中,我們借助一個bool類型的變量(stopTag)來控制翻譯任務的啟停。初始狀態下stop?Tag默認為false(表示不停止),按鈕文本為“導入中文詞表”;若此時按下按鈕則啟動翻譯任務,并將按鈕文本改變為“停止”,任務完成后文本自動恢復;若用戶在任務執行過程中按下“停止”按鈕,stopTag將被置為true(表示停止),程序檢測到stopTag的變化則停止當前任務。由于在BatchTranslate方法中使用了await語句等待翻譯結果,因此該方法也被聲明為async。批量翻譯的執行過程如圖7所示。

圖7 程序運行效果
待全部翻譯任務完成后,單擊“導出雙語詞表”按鈕可將翻譯結果以Excel格式導出,具體實現代碼這里不再列出。
分析發現,爬蟲執行過程中最耗時的步驟就是等待翻譯結果,而且每次翻譯需要等待的時間并不固定,這受原文長度、網絡條件、服務器負載等因素的影響。因此,設置一個適當的等待時間十分重要:若時間太短則翻譯尚未完成,若時間太長則影響爬蟲效率。此前的程序每次固定等待2秒,一般情況下這個時間足夠長但效率偏低。我們希望能夠在譯文返回后盡快讀取結果,在改進方案中采用“輪詢檢測法”判斷翻譯結果是否返回。改進后的代碼如下:

上述代碼中的Clear Dest Text方法用于清空譯文(具體代碼從略),在寫入原文之前先調用此函數,以避免上次翻譯結果干擾到本次判斷。為驗證“輪詢檢測法”的性能,我們將其與“定時等待法”進行對比測試。

圖8 “定時等待法”性能統計
對于“輪詢檢測法”,我們統計了采用不同“輪詢間隔”對程序性能的影響(如圖9所示)。統計結果表明:此方法總能保證100%的“采準率”,平均翻譯時長也明顯優于“定時等待法”。同時,我們發現輪詢間隔并非越小越好(設定在0.1秒左右較為合適),因為間隔時間越小就意味著輪詢次數越多,而輪詢本身也需要消耗系統資源。

圖9 “間隔輪詢法”性能統計
為了進一步說明“定時等待法”難以兼顧準度和效率,我們采用“間隔輪詢”法對同一組詞條(共13個)進行5次翻譯測試,并將用時分布情況繪制成“箱線圖”(如圖10所示)。

圖10 翻譯等待時間分布
統計結果顯示:雖然平均翻譯時間都在1秒左右,但每次總有幾個詞條偏離平均值較遠。翻譯等待時間的不穩定性正是“定時等待法”效率不高原因。
本文所介紹的“谷歌翻譯爬蟲”不僅實現了既定功能,達到了預期效果;而且進行了算法優化,提高了采集效率。測試表明:本文所提出的方案是行之有效的,可以為同類爬蟲的開發提供技術參考。筆者在項目實踐中發現,越來越多的網頁采用異步加載技術,傳統的網絡爬蟲難以發揮作用。模擬瀏覽器的方式可以屏蔽內部技術細節,減化爬蟲開發的復雜度。其中,如何模擬用戶操作(如輸入文本、選擇列表、點擊按鈕、滾動頁面等),是實現爬蟲功能的基礎;如何判斷目標數據返回,是提高爬蟲效率的關鍵。