由于最近在做一個項目,給了36個安全網站相關的博客網站,需要將其中的博客正文都抽取出來,而且需要滿足以后添加一個博客網站的鏈接,就可以自動完成正文的抽取工作。
以前寫過的爬蟲是正則或CSS選擇器(或xpath)的網頁抽取都基于屬于基于包裝器(wrapper)的網頁抽取,但是這類抽取算法有一個通病,對于不同結構的網頁,要制定不同的抽取規則。如果一個安全態勢感知系統需要獲取1000個異構網站的博客正文,就需要編寫并維護1000套抽取規則,這太惡心了,根本就是不想完成的任務。
從2000年左右就開始有人研究如何用機器學習的方法,讓程序在不需要人工制定規則的情況下從網頁中提取所需的信息。從目前的科研成果看,基于機器學習的網頁抽取的重心偏向于新聞網頁內容自動抽取,即輸入一個新聞網頁,程序可以自動輸出新聞的標題、正文、時間等信息。新聞、博客、百科類網站包含的結構化數據較為單一,基本都滿足{標題,時間,正文}這種結構,抽取目標很明確,機器學習算法也較好設計。
題外話:這種正文提取算法可以幫助提取安全博客網站的正文,但是一些電商、求職等類型的網頁中包含的結構化數據非常復雜,有些還有嵌套,并沒有統一的抽取目標,針對這類頁面設計機器學習抽取算法難度較大。
下面主要描述如何設計機器學習算法抽取新聞、博客、百科等網站中的正文信息,后面簡稱為網頁正文抽取(Content Extraction)。
基于機器學習的網頁抽取算法大致可以分為以下幾類:
- 基于啟發式規則和無監督學習的網頁抽取算法
- 基于分類器的網頁抽取算法
- 基于網頁模板自動生成的網頁抽取算法
三類算法中,第一類算法是最好實現的,也是效果最好的。
下面簡單描述一下三類算法,如果你只是希望在工程中使用這些算法,只要了解第一類算法即可。
下面會提到一些論文,但請不要根據論文里自己的實驗數據來判斷算法的好壞,很多算法面向早期網頁設計(即以表格為框架的網頁),還有一些算法的實驗數據集覆蓋面較窄。有條件最好自己對這些算法進行評測。
1. 基于啟發式規則和無監督學習的網頁抽取算法
基于啟發式規則和無監督學習的網頁抽取算法(第一類算法)是目前最簡單,也是效果最好的方法。且其具有較高的通用性,即算法往往在不同語種、不同結構的網頁上都有效。
早期的這類算法大多數沒有將網頁解析為DOM樹,而是將網頁解析為一個token序列,例如對于下面這段html源碼:
<body>
<div>廣告...(8字)</div>
<div class="main">正文...(500字)</div>
<div class="foot">頁腳...(6字)</div>
</body>
程序將其轉換為token序列:
標簽(body),標簽(div),文本,文本....(8次),標簽(/div),標簽(div),文本,文本...(500次),標簽(/div),標簽(div),文本,文本...(6次),標簽(/div),標簽(/body)
早期有一種MSS算法(Maximum Subsequence Segmentation)以token序列為基礎,算法有多個版本,其中一個版本為token序列中的每一個token賦予一個分數,打分規則如下:
- 一個標簽給 -3.25 分
- 一個文本給 +1 分
根據打分規則和上面的token序列,我們可以獲取一個分數序列:
-3.25,-3.25,1,1,1...(8次),-3.25,-3.25,1,1,1...(500次),-3.25,-3.25,1,1,1...(6次),-3.25,-3.25
-
MSS算法
MSS算法認為,找出token序列中的一個子序列,使得這個子序列中token對應的分數總和達到最大,則這個子序列就是網頁中的正文。從另一個角度來理解這個規則,即從html源碼字符串中找出一個子序列,這個子序列應該盡量包含較多的文本和較少的標簽,因為算法中給標簽賦予了絕對值較大的負分(-3.25),為文本賦予了較小的正分(1)。
如何從分數序列中找出總和最大的子序列可以用動態規劃很好地解決,這里就不給出詳細算法,有興趣可以參考《Extracting Article Text from the Web with Maximum Subsequence Segmentation》這篇論文,MSS算法的效果并不好,但本文認為它可以代表早期的很多算法。
MSS算法(樸素貝葉斯)
MSS還有其他的版本,我們上面說算法給標簽和文本分別賦予-3.25和1分,這是固定值,還有一個版本的MSS(也在論文中)利用樸素貝葉斯的方法為標簽和文本計算分數。雖然這個版本的MSS效果有一定的提升,但仍不理想。利用聚類的方法
無監督學習在第一類算法中也起到重要作用。很多算法利用聚類的方法,將網頁的正文和非正文自動分為2類。例如在《CETR - Content Extraction via Tag Ratios》算法中,網頁被切分為多行文本,算法為每行文本計算2個特征,分別是下圖中的橫軸和縱軸,紅色橢圓中的單元(行),大多數是網頁正文,而綠色橢圓中包含的單元(行),大多數是非正文,使用k-means等聚類方法,就可以很好地將正文和非正文分為兩類,然后再設計一些啟發式算法,即可區分兩類中哪一類是正文,哪一類是非正文。
-
使用DOM樹的Node作為特征計算的基本單元
早期的算法往往將token序列、字符序列作為計算特征的單元,從某種意義來說,這破壞了網頁的結構,也沒有充分利用網頁的特征。在后來的算法中,很多使用DOM樹的Node作為特征計算的基本單元,例如《Web news extraction via path ratios》、《Dom based content extraction via text density》,這些算法仍然是利用啟發式規則和無監督學習,由于使用DOM樹的Node作為特征計算的基本單元,使得算法可以獲取到更好、更多的特征,因此可以設計更好的啟發式規則和無監督學習算法,這些算法在抽取效果上,往往遠高于前面所述的算法。由于在抽取時使用DOM樹的Node作為單元,算法也可以較容易地保留正文的結構(主要是為了保持網頁中正文的排版)。
我們在WebCollector(1.12版本開始)中,實現了一種第一類算法,可以到官網直接下載源碼使用。
2. 基于分類器的網頁抽取算法(第二類機器學習抽取算法)
實現基于分類器的網頁抽取算法(第二類算法),大致流程如下:
- 找幾千個網頁作為訓練集,對網頁的正文和非正文(即需要抽取和不需要抽取的部分)進行人工標注。
- 設計特征。例如一些算法將DOM樹的標簽類型(div,p,body等)作為特征之一(當然這是一個不推薦使用的特征)。
- 選擇合適的分類器,利用特征進行訓練。
對于網頁抽取,特征的設計是第一位的,具體使用什么分類器有時候并不是那么重要。在使用相同特征的情況下,使用決策樹、SVM、神經網絡等不同的分類器不一定對抽取效果造成太大的影響。
從工程的角度來說,流程中的第一步和第二步都是較為困難的。訓練集的選擇也很有講究,要保證在選取的數據集中網頁結構的多樣性。例如現在比較流行的正文結構為:
<div>
<p>xxxx</p>
<p>xxxxxxxx</p>
<span>xxx</span>
<p>xxxxx</p>
<p>xxxx</p>
</div>
2.1 eager learning
基于分類器的網頁抽取算法,算法通過訓練集產生了模型(如決策樹模型、神經網絡模型等)
如果訓練集中只有五六個網站的頁面,很有可能這些網站的正文都是上面這種結構,而恰好在特征設計中,有兩個特征是:
- 節點標簽類型(div,p,body等)
- 孩子節點標簽類型頻數(即孩子節點中,div有幾個,p有幾個…)
假設使用決策樹作為分類器,最后的訓練出的模型很可能是:
如果一個節點的標簽類型為div,且其孩子節點中標簽為p的節點超過3個,則這個節點對應網頁的正文。
雖然這個模型在訓練數據集上可以達到較好的抽取效果,但顯而易見,有很多網站不滿足這個規則。因此訓練集的選擇,對抽取算法的效果有很大的影響。
網頁設計的風格一致在變,早期的網頁往往利用表格(table)構建整個網頁的框架,現在的網頁喜歡用div構建網頁的框架。如果希望抽取算法能夠覆蓋較長的時間段,在特征設計時,就要盡量選用那些不易變化的特征。標簽類型是一個很容易變化的特征,隨著網頁設計風格的變化而變化,因此前面提到,非常不建議使用標簽類型作為訓練特征。
2.2 lazy learning
事先不通過訓練集產生模型的算法,比較有名的KNN就是屬于lazy learning。
一些抽取算法借助KNN來選擇抽取算法,可能聽起來有些繞,這里解釋一下。假設有2種抽取算法A、B,有3個網站site1,site2,site3。2種算法在3個網站上的抽取效果(這里用0%-100%的一個數表示,越大說明越好)如下:
網站 | A算法抽取效果 | B算法抽取效果 |
---|---|---|
site1 | 90% | 70% |
site2 | 80% | 85% |
site3 | 60% | 87% |
可以看出來,在site1上,A算法的抽取效果比B好,在site2和site3上,B算法的抽取效果較好。在實際中,這種情況很常見。所以有些人就希望設計一個分類器,這個分類器不是用來分類正文和非正文,而是用來幫助選擇抽取算法。例如在這個例子中,分類器在我們對site1中網頁進行抽取時,應該告訴我們使用A算法可以獲得更好的效果。
舉個形象的例子,A算法在政府類網站上抽取效果較好,B算法在互聯網新聞網站上抽取效果較好。那么當我對政府類網站進行抽取時,分類器應該幫我選擇A算法。
這個分類器的實現,可以借助KNN算法。事先需要準備一個數據集,數據集中有多個站點的網頁,同時需要維護一張表,表中告訴我們在每個站點上,不同抽取算法的抽取效果(實際上只要知道在每個站點上,哪個算法抽取效果最好即可)。當遇到一個待抽取的網頁,我們將網頁和數據集中所有網頁對比(效率很低),找出最相似的K個網頁,然后看著K個網頁中,哪個站點的網頁最多(例如k=7,其中有6個網頁都是來自CSDN新聞),那么我們就選擇這個站點上效果最好的算法,對這個未知網頁進行抽取。
3. 基于網頁模板自動生成的網頁抽取算法
基于網頁模板自動生成的網頁抽取算法(第三類算法)有很多種。這里例舉一種。在《URL Tree: Efficient Unsupervised Content Extraction from Streams of Web Documents》中,用多個相同結構頁面(通過URL判斷)的對比,找出其中異同,頁面間的共性的部分是非正文,頁面間差別較大的部分有可能是正文。這個很好理解,例如在一些網站中,所有的網頁頁腳都相同,都是備案信息或者版權申明之類的,這是頁面之間的共性,因此算法認為這部分是非正文。而不同網頁的正文往往是不同的,因此算法識別出正文頁較容易。這種算法往往并不是針對單個網頁作正文抽取,而是收集大量同構網頁后,對多個網頁同時進行抽取。也就是說,并不是輸入一個網頁就可以實時進行抽取。