通常的網頁內容抽取須要針對特定的網站進行特定的檢查定位正文標籤,指定抽取規則。可是若是須要抽取100個不一樣內容結構的網站正文,須要的就是100個不一樣的規則。
有沒有一種通用的內容抽取呢。能夠只基於網頁正文內容的變化而變化的規則f(x).
本文實現的是針對於通常的長文本正文類網站(博客、新聞、小說類)實現的通用正文內容抽取。像那種須要抽取的正文內容C長度與網頁內容W長度比例C/W<0.5的可能會出現不適用的狀況。(好比正文是一句話幾個字,整個頁面內容的文字長度超過了正文的2倍,那最好使用DOM標籤規則抽取)python
如下的「網頁」均指長文本類型的網頁
通常的網頁正文都是屬於段落類型的文本,所屬標籤不一,其餘的無用信息(如網頁版權、站點通知、導航內容等)也佔據了必定的頁面內容,若是單純的把網頁內容文字所有抽取出來,
這很簡單,可是會夾雜不少的無用內容,干擾太大,因此針對正文抽取獲得頁面的真正有用信息是主要目的。能夠利用正文內容進行網頁類似度的計算。git
抽取正文要找到正文的分佈特徵,將爬取到的網頁去除全部標籤,獲得每一行的內容後,能夠根據(行號,字符數)製做圖表查看二者的關聯:
下圖是騰訊新聞一則新聞頁面的行號-行字數關係圖表:
github
下圖是CSDN的兩則博文正文行號-行字數關係圖表:算法
《中文編碼相關,python處理gbk編碼的xml文件方法》:
《python抓取gb2312gbk編碼網頁亂碼問題》:
下圖是segmentfault的一篇博文正文行號-行字數關係圖表:segmentfault
《解決 ScriptError的另類思路》:
能夠看到,正文的內容通常是連續行的塊,所以咱們能夠設置閾值來過濾一些非正文的干擾行,可是針對某些連續行並非有效正文的狀況,就須要看這個連續行組成的塊的總字符數。
若是字數少於一個閾值,就不屬於正文,也就是正文的字符密度,因而可知,正文能夠基於連續行字符密度來進行提取。網站
假設咱們已經爬取了網頁內容WebContent,而且將W的全部標籤去除獲得了純文本保留行格式的文字內容LinesContent.接下來:編碼
#三個可控變量,自由調整使抽取達到理想效果 #連續行閾值:連續多少行則認爲是一個正文內容塊 threshold = 5 #正文內空行閾值:容許正文內容 段落或正文行 之間有多少空行 gap = 3 #正文字符密度閾值:每一行的字符數達到多少則認爲屬於正文內容 density = 45 #********初始化設置#******** #保留抽取結果字典,格式:{<連續塊字符總數>:<塊文字內容>,...} results={} #已經達到先後連續的次數 comobo_num =0 #當前連續塊的總字符數 combo_len = 0 #當前連續空行數 combo_null=0 #當前連續塊的文字內容 combo_text = '' #當前行/前一行的字符數 pre_len = 0 for i in LinesContent: #當前行非空 if i.strip(): pre_len = len(i) comobo_num += 1 combo_null = 0 combo_len += pre_len #疊加非空行內容到連續內容中 combo_text = combo_text+i+ os.linesep #針對單行文本狀況 if len(a)==1 and pre_len >= density*threshold: results[pre_len]=combo_text else: combo_null +=1 #若是前一行非空 if pre_len: #連續空行閾值判斷 if combo_null > gap: #連續塊判斷 if combo_len >= density*threshold \ and comobo_num >= threshold: results[combo_len]=combo_text else: continue #非正文連續塊則所有參數復位 comobo_num = 0 combo_len = 0 if combo_null > gap else combo_len pre_len = 0 combo_text = '' if combo_null > gap else combo_text
通過對多個長文本類型網站的抓取抽取,正文抽取成功率達到了90%以上。spa
源碼地址:GitHubcode