張 倩, 林安成, 廖秀秀
(廣東技術(shù)師范學(xué)院 計(jì)算機(jī)科學(xué)學(xué)院, 廣州 510665)
爬蟲技術(shù)的目標(biāo)是對(duì)海量的分散的互聯(lián)網(wǎng)數(shù)據(jù)進(jìn)行采集, 是搜索引擎系統(tǒng)的基礎(chǔ). 大數(shù)據(jù)近年來(lái)發(fā)展快速, 不僅是數(shù)據(jù)容量的巨大, 更是強(qiáng)調(diào)對(duì)樣本數(shù)據(jù)的分析. 互聯(lián)網(wǎng)中的數(shù)據(jù)包含大量有價(jià)值但異構(gòu)的信息, 需要被提取出來(lái)并以一種結(jié)構(gòu)化的形式來(lái)表示, 作為大數(shù)據(jù)的數(shù)據(jù)來(lái)源[1,2].主題爬蟲垂直于某一領(lǐng)域, 相比于通用爬蟲, 增加了對(duì)有價(jià)值數(shù)據(jù)的組織和歸類. 從一些主題爬蟲的實(shí)踐發(fā)現(xiàn), 他們通常手工編寫結(jié)構(gòu)化代碼來(lái)分析某一個(gè)目標(biāo)站點(diǎn)[3], 很多情況下需要獲得多個(gè)源站的結(jié)構(gòu)化數(shù)據(jù), 就不得不分別編寫相關(guān)代碼, 所付出的時(shí)間和人力代價(jià)是不小的. 而且, 爬蟲系統(tǒng)的編寫是在前人的經(jīng)驗(yàn)基礎(chǔ)之上, 大多是重復(fù)性的勞動(dòng), 特別是垂直于同類網(wǎng)站的主題爬蟲, 分別編寫規(guī)則更顯得繁瑣和沒有建設(shè)性, 那么尋找一個(gè)相對(duì)自動(dòng)化的方案就顯得十分有意義. 前人對(duì)自動(dòng)化爬蟲的研究還不能夠很好地適應(yīng)上文提到的場(chǎng)景, 比如基于主題語(yǔ)義的信息采集, 無(wú)法做到具體字段的結(jié)構(gòu)化[4]; 而使用概率模型來(lái)采集最優(yōu)數(shù)據(jù)[5], 其可靠性和最終的數(shù)據(jù)量不符合實(shí)際工程應(yīng)用上的要求. 為了得到一個(gè)可靠而高效的自動(dòng)結(jié)構(gòu)化爬蟲, 本文選擇從電商網(wǎng)站切入研究, 其具有一些特點(diǎn): 層次分布穩(wěn)定, 有價(jià)值數(shù)據(jù)比較密集, 標(biāo)簽、數(shù)據(jù)變化快, 采用了一些主流反爬機(jī)制. 基于這些特點(diǎn), 電商網(wǎng)站成為合適的樣本. 本文將從研究源站的統(tǒng)一性開始, 設(shè)計(jì)和采用一些抓取的方法和技巧, 實(shí)現(xiàn)自動(dòng)結(jié)構(gòu)化的目的. 同時(shí), 為了追求效率和工程化, 補(bǔ)充了在實(shí)際使用的解決方案.
電商網(wǎng)站的層次分布是穩(wěn)定的, 調(diào)研了國(guó)內(nèi)幾家大型電商網(wǎng)站(淘寶、蘇寧、京東)和一些小型商戶使用的開源商城程序(ECSHOP、ShopN、HiShop), 為了讓用戶更容易適應(yīng)頁(yè)面操作和商品入口, 這些網(wǎng)站一般被組織為如圖1所示的結(jié)構(gòu).
圖1 電商網(wǎng)站組織結(jié)構(gòu)
對(duì)用戶來(lái)說(shuō), 可通過(guò)商品分類和搜索匹配兩種方式進(jìn)入列表頁(yè)面, 列表頁(yè)面即是眾多商品的入口, 也是信息的主要通道. 爬蟲系統(tǒng)采用的路線是“分類-列表-詳情”, 原因有三點(diǎn): 1) 商品分類本身也是有價(jià)值數(shù)據(jù);2) 分類和商品的關(guān)聯(lián)性更是隱式的重要信息; 3) 從這條路線走下來(lái), 理論上可以抓取整站而不遺漏, 具有確定性.
確定網(wǎng)站結(jié)構(gòu)的層級(jí)是很有意義的, 它可以確定當(dāng)前抓取和下一層抓取的是哪種頁(yè)面類型, 這樣就可以給不同類型做抓取策略上的匹配, 而不用通過(guò)語(yǔ)義層面來(lái)標(biāo)識(shí)[6], 降低了系統(tǒng)復(fù)雜度, 提升了效率和精準(zhǔn)度.
頁(yè)面有靜態(tài)和動(dòng)態(tài)之分, 這影響了爬蟲系統(tǒng)的抓取行為:
(1) 大多數(shù)情況下, 每個(gè)url對(duì)應(yīng)的是靜態(tài)頁(yè)面, 瀏覽器直接解析請(qǐng)求url后響應(yīng)的html.
(2) 動(dòng)態(tài)頁(yè)面的情況是比較特殊的, 網(wǎng)頁(yè)的數(shù)據(jù)采用異步加載, 即站點(diǎn)服務(wù)器初次響應(yīng)的數(shù)據(jù)僅僅是頁(yè)面結(jié)構(gòu)框架和異步執(zhí)行的代碼, 加載完畢后, 再次請(qǐng)求服務(wù)器拿到數(shù)據(jù), 通過(guò)JavaScript操作Dom組合成完整頁(yè)面.
特別在近年來(lái), 前端應(yīng)用引擎諸如React、AngularJS和國(guó)產(chǎn)的vue日益盛行, 模板化和異步加載的方式更是應(yīng)用廣泛, 導(dǎo)致上面所述第二種情況出現(xiàn)的幾率不低. 所幸爬蟲領(lǐng)域也有足夠多的方案去適配它, 有人通過(guò)模擬它的JS行為獲得數(shù)據(jù)[7], 更通用的方法是應(yīng)用各平臺(tái)的前端渲染支持庫(kù)(HtmlUtil、PhantomJS), 它們帶有JS引擎, 就好像真正在瀏覽器加載頁(yè)面等待渲染完畢一樣, 有人應(yīng)用這些支持庫(kù)實(shí)現(xiàn)了比較優(yōu)秀的系統(tǒng)[8], 甚至形成了稱為AjaxCrawler的體系[9].
電商網(wǎng)站也是一樣, 兩種頁(yè)面經(jīng)常是共存的, 為了提高普適度, 本文對(duì)動(dòng)態(tài)頁(yè)面采取了應(yīng)用前端渲染支持庫(kù)的做法. 那么如何標(biāo)識(shí)出當(dāng)前頁(yè)面是屬于哪一種類型呢?本文提出一種“預(yù)抓取-比較判斷-標(biāo)識(shí)”的方法, 其頁(yè)面類型判斷流程如圖2所示.
圖2中的“比較”過(guò)程參考了一種基于網(wǎng)頁(yè)正文結(jié)構(gòu)和特征串的相似網(wǎng)頁(yè)去重算法[10], 如圖3所示.
首先進(jìn)行網(wǎng)頁(yè)正文的抽取, 過(guò)濾掉網(wǎng)頁(yè)中的噪聲(例如導(dǎo)航條、廣告條、超鏈接和網(wǎng)站底部說(shuō)明), 利用網(wǎng)頁(yè)正文生成樹算法得到一棵結(jié)構(gòu)樹, 然后用Bloom Filter算法計(jì)算每一層次標(biāo)簽特征串的指紋, 用頁(yè)面所有元素的指紋值直接拼接進(jìn)行網(wǎng)頁(yè)相似度的判斷. 當(dāng)相似度達(dá)到預(yù)定的閾值, 就認(rèn)為靜態(tài)抓取和前端渲染得到的頁(yè)面數(shù)據(jù)是等價(jià)的, 此時(shí)可以斷定該層級(jí)頁(yè)面是靜態(tài)的, 否則認(rèn)為是存在異步獲取過(guò)程的動(dòng)態(tài)頁(yè)面.由于經(jīng)歷了正文抽取、噪聲過(guò)濾和文本樹生成, 所有節(jié)點(diǎn)的指紋都是相對(duì)穩(wěn)定的, 這就意味著兩個(gè)頁(yè)面的指紋相似度應(yīng)該稍高一些, 本文測(cè)試環(huán)境使用的閾值為0.8.
圖2 頁(yè)面類型判斷流程
圖3 相似頁(yè)面判斷算法
電商網(wǎng)站層級(jí)嚴(yán)謹(jǐn), 基于此相同層級(jí)的頁(yè)面, 自然采取了同樣的頁(yè)面類型, 所以圖2最后一步中標(biāo)記的是某一層級(jí)而不是某個(gè)URL, 后面的抓取都沿用本層級(jí)已經(jīng)確定下來(lái)的策略即可.
主題爬蟲的特點(diǎn)除了上文所述穩(wěn)定的層次分布,更重要的是, 其垂直領(lǐng)域的語(yǔ)料和高頻度用詞都是可預(yù)見的, 而在技術(shù)角度, 描述不同業(yè)務(wù)數(shù)據(jù)的標(biāo)識(shí)符也是有差異的. 依舊以電商為例, 商鋪(shop/mall)、商品(product/commodity)、價(jià)格(price)、快遞 (express)、訂單(order)等是其行業(yè)用語(yǔ), 再具體到頁(yè)面, title/describe/comment/list/sort等的語(yǔ)義十分明顯, 不同電商網(wǎng)站的用詞基本上是同一套. HTML標(biāo)簽對(duì)于數(shù)據(jù)的展示也是規(guī)范的, 比如標(biāo)題用<h>和<p>標(biāo)簽, 列表用多個(gè)被大<div>塊包含的<li>標(biāo)簽描述.
綜上可見, 只要提供合適的語(yǔ)料和技術(shù)上的規(guī)范,制定匹配的策略, 就可以找到目標(biāo), 提取、組合出結(jié)構(gòu)化的數(shù)據(jù). 理論上使用機(jī)器訓(xùn)練似乎更加勝任這些預(yù)測(cè)工作[11], 但是因?yàn)橹黝}爬蟲的前提下, 人工加權(quán)是可以實(shí)現(xiàn)的, 而且會(huì)比為了支撐機(jī)器訓(xùn)練而忙于制造訓(xùn)練數(shù)據(jù)省力得多.
本文所討論的自動(dòng)結(jié)構(gòu)化的關(guān)鍵點(diǎn), 在于如何實(shí)現(xiàn)較為精準(zhǔn)的標(biāo)簽匹配, 這里可以通過(guò)以下兩種方式實(shí)現(xiàn).
3.2.1 列表的匹配
圖4 站點(diǎn)結(jié)構(gòu)舉例
此項(xiàng)用來(lái)分辨類別、商品列表的數(shù)據(jù)是在頁(yè)面的哪一部分. 本文分析多個(gè)站點(diǎn)的結(jié)構(gòu), 如圖4是比較典型的一種.依據(jù)圖4網(wǎng)頁(yè)中列表的特征: 結(jié)構(gòu)一致、覆蓋此頁(yè)大部分、多用div/ul/li標(biāo)簽, 制定了如圖5所示的流程.
同樣的, 先去除不關(guān)網(wǎng)頁(yè)結(jié)構(gòu)但占據(jù)很多篇幅的代碼和文字, 僅僅留下body標(biāo)簽的內(nèi)容并生成結(jié)構(gòu)樹,其中還要把標(biāo)簽文本去除, 來(lái)減少文檔體積以提高后期分析效率. 在標(biāo)識(shí)重復(fù)相似節(jié)點(diǎn)時(shí), 參考了一種基于節(jié)點(diǎn)加權(quán)的XML檢測(cè)算法[12]和加權(quán)頻繁子樹相似度的算法[13], 并作出一定改進(jìn), 其算法描述如下:
(1) 將HTML文檔用SAX (Simple API for XML)轉(zhuǎn)化為一棵帶權(quán)樹, 其中class、name、type等屬性應(yīng)該設(shè)置較高的權(quán)值, 注意應(yīng)將相同根節(jié)點(diǎn)的同一層次節(jié)點(diǎn)的權(quán)值之和等于1.
(2) 任意兩棵樹進(jìn)行相似性的粗略匹配, 將屬性值相等的節(jié)點(diǎn)計(jì)算相似度: 帶權(quán)樹Ta、Tb,N代表兩棵樹的節(jié)點(diǎn)數(shù),a1–an和b1–bn代表節(jié)點(diǎn)權(quán)值, 相似度計(jì)算公式:計(jì)算得到的相似度如果大于預(yù)設(shè)的α, 認(rèn)為相似.
(3) 將(2)得到的相似節(jié)點(diǎn)對(duì)使用樹編輯距離算法, 計(jì)算后的距離值小于給定的閾值β, 便最終確認(rèn)其節(jié)點(diǎn)對(duì)是相似重復(fù)節(jié)點(diǎn).
“判斷標(biāo)簽名”這一步是為了解決在網(wǎng)頁(yè)中發(fā)現(xiàn)多片區(qū)域出現(xiàn)相似重復(fù)節(jié)點(diǎn)的情況, 這時(shí)應(yīng)當(dāng)給ul/li較高優(yōu)先, 依次類推. 最后確定了列表的位置, 轉(zhuǎn)化為XPath(XML路徑語(yǔ)言)并存儲(chǔ), 供后續(xù)頁(yè)面解析進(jìn)行快速匹配.
3.2.2 匹配目標(biāo)字段的標(biāo)簽
工程項(xiàng)目竣工結(jié)算審計(jì)是對(duì)基本建設(shè)項(xiàng)目竣工結(jié)算編制,及有關(guān)經(jīng)濟(jì)活動(dòng)的真實(shí)性、合法性、效益性進(jìn)行審計(jì)監(jiān)督和評(píng)價(jià)的過(guò)程,工程審計(jì)是工程造價(jià)控制的重要環(huán)節(jié),是提高建筑項(xiàng)目管理水平的內(nèi)在動(dòng)力,是工程建設(shè)項(xiàng)目資金真實(shí)性、合法性、效益性的重要保障。
3.2.1節(jié)介紹的是如何鎖定目標(biāo)數(shù)據(jù)的范圍, 還有一個(gè)問(wèn)題就是如何抓取最終的有價(jià)值字段. 本文基于主題爬蟲的特點(diǎn), 提出一種屬性語(yǔ)義匹配的方案, 首先給每個(gè)字段建立一個(gè)用于預(yù)測(cè)的詞庫(kù), 然后進(jìn)行全部/局部匹配, 計(jì)算得到權(quán)值之后進(jìn)行比較以實(shí)現(xiàn)預(yù)測(cè).
假如要匹配商品名稱, 本文設(shè)定了詞庫(kù)和權(quán)值見表1.
表1 詞庫(kù)
因?yàn)榇a命名常采用縮寫, 當(dāng)標(biāo)簽的id屬性局部匹配(本文推薦50%)時(shí)即加上該權(quán)值, 一些用詞經(jīng)常是把縮寫也納入詞庫(kù), 并且權(quán)值應(yīng)該更高. 匹配計(jì)算過(guò)程如下:
因此可以得出結(jié)論: 描述商品名稱字段的是標(biāo)簽1.
還有一點(diǎn)需要注意的是, 標(biāo)簽描述屬性不只是id也可能是name, 還有的情況是自定義的屬性, 這就需要在原來(lái)的算法上加以延伸, 變成決策樹的模型, 這里不再展開討論.
上文提出了自動(dòng)結(jié)構(gòu)化的一些細(xì)節(jié)策略和算法,但一些加權(quán)規(guī)則和語(yǔ)料是需要人工輸入的. 為了實(shí)現(xiàn)系統(tǒng)和數(shù)據(jù)的分離, 提出一種稱為匹配模板的預(yù)設(shè)數(shù)據(jù), 其應(yīng)當(dāng)包含如下數(shù)據(jù):
(1) 列表結(jié)構(gòu)優(yōu)先匹配排序, 其包含數(shù)據(jù)如div/ul/li、div/p、p/p 等.
(2) 節(jié)點(diǎn)屬性相似度權(quán)值, 其包含數(shù)據(jù)如name(10),id(15), class(10)等.
(3) 目標(biāo)字段和匹配詞庫(kù), 其包含字段名和詞庫(kù)(用詞和權(quán)值).
圖6 預(yù)設(shè)匹配模板
4.1節(jié)所述的利用模板分析出目標(biāo)字段的匹配路徑, 實(shí)際上是主題爬蟲中對(duì)于多個(gè)源站的差異部分, 而剩下的爬蟲程序運(yùn)作是高度一致的, 無(wú)需重新組織代碼. 遇到一個(gè)陌生站點(diǎn), 只需在爬取前進(jìn)行模板分析,得到目標(biāo)字段的位置信息(本文采取XPath), 那么后續(xù)開啟的整個(gè)爬蟲程序只要沿用他們即可, 在性能上和與原爬蟲的協(xié)作設(shè)計(jì)上都不會(huì)有影響.
如果在后續(xù)還需要支持分時(shí)段和分布式, 那么結(jié)構(gòu)分析結(jié)果還應(yīng)該保存下來(lái), 實(shí)現(xiàn)不同時(shí)段、不同機(jī)器間的復(fù)用.
綜上所述, 本文實(shí)現(xiàn)了如圖7所示架構(gòu)的系統(tǒng).
圖7 系統(tǒng)架構(gòu)
系統(tǒng)簡(jiǎn)述:
(1) 使用者傳入一個(gè)入口地址觸發(fā)本系統(tǒng), 抓取工作同期開啟, 它等待主線程的任務(wù).
(2) 較于普通爬蟲系統(tǒng)新增了模板分析部分, 引擎會(huì)先進(jìn)行判斷, 如果是舊網(wǎng)站, 則使用以前分析產(chǎn)生的規(guī)則.
(3) 遇到新的站點(diǎn), 則交由結(jié)構(gòu)分析器, 根據(jù)預(yù)設(shè)的匹配模板, 逐步分析出列表數(shù)據(jù)、目標(biāo)字段的位置信息, 將產(chǎn)生的XPath存儲(chǔ)在分析器實(shí)例中.
(4) 開啟爬蟲的運(yùn)作流程, 根據(jù)層級(jí)提交給分析器解析出所需字段, 完成結(jié)構(gòu)化.
圖8 分析器實(shí)例XPath
選取了幾個(gè)主流的電商網(wǎng)站進(jìn)行爬取, 系統(tǒng)能夠正常運(yùn)行. 圖8為國(guó)美網(wǎng)站的分析器實(shí)例得到的XPath.為了方便展示, 將圖8的數(shù)據(jù)用一個(gè)腳本進(jìn)行樹形輸出, 并且僅選取幾個(gè)子節(jié)點(diǎn), 得到的結(jié)構(gòu)化數(shù)據(jù)如圖9所示.
圖9 結(jié)構(gòu)化數(shù)據(jù)展示
可以看到, 所實(shí)現(xiàn)的系統(tǒng)抓取到的數(shù)據(jù)已經(jīng)被結(jié)構(gòu)化, 且表現(xiàn)良好.
本文提出的多種匹配方案都包含了加權(quán)預(yù)測(cè)的過(guò)程, 會(huì)有一定的錯(cuò)誤率, 這個(gè)指標(biāo)是評(píng)價(jià)本套方案優(yōu)良的關(guān)鍵.
這里采取的測(cè)試手段是: 將抓取到的商品的價(jià)格進(jìn)行正確性判斷, 當(dāng)其為亂碼、空文本、非數(shù)字時(shí), 可以斷定結(jié)構(gòu)化出錯(cuò). 表2是多個(gè)站點(diǎn)的測(cè)試結(jié)果.
表2 錯(cuò)誤率測(cè)試
可以看到, 大型站點(diǎn)的錯(cuò)誤率較高, 而ECShop這類通用商城程序的結(jié)構(gòu)化效果很理想, 原因在其設(shè)計(jì)更加規(guī)范, 命名的可讀性較強(qiáng). 總的來(lái)說(shuō), 本文的方案表現(xiàn)良好, 在詞庫(kù)和權(quán)值參數(shù)的調(diào)優(yōu)上還有一定的進(jìn)步空間.
自動(dòng)結(jié)構(gòu)化抓取的意義在于, 能夠在更短的時(shí)間內(nèi)獲得更多的數(shù)據(jù). 本次實(shí)驗(yàn)進(jìn)行爬取速度的測(cè)試, 將提出的自動(dòng)結(jié)構(gòu)化爬蟲系統(tǒng)與手工編寫抓取規(guī)則的專用爬蟲系統(tǒng)進(jìn)行對(duì)比, 在同一時(shí)刻對(duì)京東數(shù)據(jù)進(jìn)行采集, 并實(shí)時(shí)統(tǒng)計(jì)抓取的商品數(shù)量. 運(yùn)行結(jié)果如圖10所示.
圖10 兩種爬蟲系統(tǒng)的爬取速度對(duì)比
結(jié)果表明, 專用爬蟲自系統(tǒng)啟動(dòng)就一直穩(wěn)定抓取,而自動(dòng)結(jié)構(gòu)化爬蟲會(huì)滯后一段時(shí)間, 隨后其曲線和專用爬蟲十分相近. 原因是顯而易見的, 自動(dòng)結(jié)構(gòu)化的系統(tǒng)需要進(jìn)行模板分析過(guò)程, 在分析之后會(huì)生成匹配規(guī)則, 為后續(xù)的頁(yè)面數(shù)據(jù)匹配過(guò)程所使用, 此時(shí)系統(tǒng)的運(yùn)行邏輯和專用爬蟲無(wú)異. 對(duì)于電商整站采集的總時(shí)間(可能長(zhǎng)達(dá)數(shù)小時(shí))來(lái)說(shuō), 一開始數(shù)秒的延后時(shí)間是可以據(jù)略不計(jì)的, 而其卻可以輕易遷移到別的站點(diǎn), 又省下了大量開發(fā)時(shí)間, 隨著源站需求的增加, 自動(dòng)結(jié)構(gòu)化系統(tǒng)的優(yōu)勢(shì)會(huì)更加明顯.
本文提出了一種針對(duì)電商網(wǎng)站可以自動(dòng)結(jié)構(gòu)化數(shù)據(jù)的主題爬蟲方案, 由于網(wǎng)站結(jié)構(gòu)嚴(yán)謹(jǐn)?shù)膶哟蝿澐趾途W(wǎng)頁(yè)代碼的命名規(guī)范性, 使得頁(yè)面類型、結(jié)構(gòu)分析和標(biāo)簽匹配的自動(dòng)化成為可能, 這里使用了相似重復(fù)判斷和目標(biāo)字段標(biāo)簽匹配的算法作為支撐, 實(shí)驗(yàn)證明提出的方案具有可行性和優(yōu)良性.
本文亦將方案進(jìn)行系統(tǒng)實(shí)現(xiàn), 其架構(gòu)是在普通爬蟲系統(tǒng)基礎(chǔ)上新增了模板分析的部分, 在初次爬取某一站點(diǎn)前, 分析得到所有目標(biāo)字段的匹配路徑, 剩下的工作跟普通爬蟲系統(tǒng)無(wú)異, 即性能和系統(tǒng)邏輯不會(huì)受到影響.
除電商網(wǎng)站外, 其他主題爬蟲亦可針對(duì)其領(lǐng)域進(jìn)行層次、結(jié)構(gòu)和字段語(yǔ)料的分析, 實(shí)現(xiàn)自動(dòng)結(jié)構(gòu)化以節(jié)省人工編碼成本.