前一段時間,因公司需求需要爬取大量的新聞網站(2000多個新聞網址),做過爬蟲的小夥伴們,當聽到這個需求的時候,內心估計早已翻滾!!!起飛吧騷年。好了就不閒扯了,畢竟我們搞技術的,我們還是要回歸技術,用技術成就我們。
2000多個網址,可想而知,如果單純的使用 xpath 進行解析,那就只能是望洋興嘆,獨自掉下沒有憂愁的髮絲,工作量就太巨大了。
起初找到了自動化解析頁面的神庫 readbility 庫,起初使用這個庫還行,對於一些標準格式的html網頁,解析還是很不錯的,但是遇到一些不規則的html 網頁,解析率就不太友好了,嘗試二次開發,但效果不太理想,同時該演算法需要解析 DOM 樹,因此時間複雜度和空間複雜度較高,提取的網頁正文的時間比較長。果斷放棄。
經過一段時間的研究,在論文海中排查出了今天的主角–基於文字及符號密度的網頁正文提取方法,經過測試,準確率符合專案的實際開發需求。
進入正題:
現在大多數的網站的網頁除了主要的內容,還包含導航欄,廣告,版權等無關資訊。這些額外的,內容亦被稱為噪聲,通常與主題無關。
由於這些噪聲會妨礙搜尋引擎對 Web 資料的挖掘效能,所以需要過濾噪聲。在這個論文中,演算法是基於網頁文字密度與符號密度對網頁進行正文內容提取,這是一種快速,準確通用的網頁提取演算法,而且還可以保留原始結構。
該演算法的實現思路來源:
現在大多數正文內容一般在網頁的:
1. <body>標籤內的<p>標籤中;
2. <p>標籤一般都為<div>、<td>等標籤的子標籤,並不獨立存在。
同時,在分析的過程中也發現了一些問題:
1. 各個網站對標籤的 class,id 等屬性名稱命名不統一。
2. 網頁正文內容中可能有超連結,其可能是文字也可能是圖片,標籤<p>中 ,不一定就是內容,還可能還會其他標籤。
3. <p>標籤之間可能還會有 JS 指令碼或者是其他的 html 標籤。
4. <p>標籤的內容不全都是或不一定是正文內容等。網站的版權資訊一般也 是<p>標籤的內容,但這部分內容屬於噪聲。
通過文獻[基於塊密度加權標籤路徑特徵的 Web 新聞線上抽取[J]]。
我們知道可以用每行的文字密度來判斷這一行屬不屬於正文。我們把網頁解析成 Dom 樹,然後判斷每個節點屬於正文內容的可能性是多少。每個網頁都可以被解析成一顆 Dom 樹,所有的標籤都是節點,而文字和圖片等都是葉子節點。
通過這樣的思路得出了以下的演算法:
1. TDi = (Ti – LTi)/(TGi – LTGi)
2. SbDi = (Ti – LTi)/( Sbi + 1)
3. score = log(SD)*NDi* log10(PNumi + 2)* log(SbDi)
最終獲取 score 的最大值就是網頁正文內容。演算法實現在下面進行解釋。
該演算法程式實現的架構圖:
一:預處理去除網頁中的噪聲(如:script , style 等標籤)
經驗告訴你,這裡的預處理非常的重要,預處理對噪聲排除的好,格式化的內容就會越好。
程式碼實現思路:
1. 先將網頁內容轉化為 HtmlElement 物件(利用 lxml.html 的fromstring()方法)
2. 接下來就可以操作這個物件進行一系列的自定義操作,PS :
import requests
from lxml.html import fromstring
element = fromstring(requests.get(url))
#刪除script style標籤
etree.strip_elements(element, ["script","style"])
部分程式碼:
二:預處理後,進行函式計算:
計算每一個節點的要求的變數(進行對應的數學計算)
數學計算分為三步:
1.TDi計算
2.sbDi計算
3.score計算
1.計算文字密度TDI的值
TDI的作用:TDI是衡量一個網頁的每個結點文字密度,如果一個結點的純文字字數比帶連結的文字字數明顯多很多的時候,可通過TDI的值來判定該結點的文字密度就會很大,從而就可以很容易判斷該節點是不是正文的一部分。
公式:
TDi = (Ti – LTi) / (TGi – LTGi)
引數:
Ti–>節點i的字串數 即就是節點i的文字長度
LTi–>節點i帶連結的字串數 即就是節點i帶連結的文字的長度
TGi–>節點i的標籤數
LTGi–>節點i帶連結的標籤數
步驟:
1.得到節點
2.計算節點的文字長度
3.計算節點帶連結的文字長度
4.計算節點的標籤數
5.計算節點帶連結的標籤數
部分程式碼:
2. 計算文字中符號密度 sbdi 值
sbdi 是為文字數量與符號數量的比值,是為了下面的 score 數學模型做優化。
需要注意一個點如果sbdi為0時,需要設定為1, 後面取對數會報錯
公式:
sbdi = (ti – lti) / (sbi + 1)
引數:
sbi–>文字中符號的數量
部分程式碼:
3. 計算 score 的值
因為繁多的網頁採用的佈局各不相同,所以如果想要一個演算法可以通用提取不同的網頁,我們需要考慮的因素還有很多,於是我們建立了一個數學模型,這個模型就是 score。score 的作用就是在 tdi 的基礎上在做一步處理。
公式:
score = log(sd)*ndi*log10(pnumi + 2)*log(sbdi)
引數:
sd–>ndi的標準差
ndi–>文字密度
pnumi–>節點的p標籤數
部分程式碼:
最後通過演算法計算後得出最大的值及就是我們要的文字內容,可以輸出文字,也可以輸出html。
效果展示:
可以看到效果還是很明顯的。
近期文章:
APP爬蟲-雙向認證抓包的兩種方法
在猿人學公眾號後臺回覆:正文抽取,可獲得該正文抽取原始碼。
我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。
***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***