平常打開一個網頁,除了文章的正文內容,通常會有一大堆的導航,廣告和其他方面的資訊。本部落格的目的,在於說明如何從一個網頁中提取出文章的正文內容,而過渡掉其他無關的資訊。
本方法是基於文字密度的方法,最初的想法來自哈工大的《基於行塊分佈函數的通用網頁正文抽取演算法》,本文基於此進行一些小修改。
約定:
本文以網頁為基礎的不同行來進行統計,因此,假設網頁內容是沒有經過壓縮的,就是網頁有正常的換行的。
有些新聞網頁,可能新聞的文字內容比較短,但其中嵌入一個視訊文件,因此,我會給予影片較高的權重;這同樣適用於圖片,這裡有一個不足,應該是要根據圖片顯示的大小來決定權重的,但本文的方法未能實現這一點。
由於廣告,導航這些非正文內容通常以超連結的方式出現,因此文字將給予超連結的文字權重為零。
這裡假設正文的內容是連續的,中間不包含非正文的內容,因此實際上,提取正文內容,就是找出正文內容的開始和結束的位置。
步驟:
先清除網頁中CSS,Javascript,註釋,Meta,Ins這些標籤裡面的內容,清除空白行。
計算每行的經過處理的數值(1)
計算上面所得到的每行文字數的最大正子對於每一行,我們需要計算一個數值,這個數值的計算如下:
一個圖片標籤img,相當於出現長度為50字的文字 (給予的權重相當於出現長度為1000字元的文字, x2
使用中所有連結的標籤 a 的文字長度 x3 ,
每行的數值 = 50 * x1其出現次數 + 1000 * x2其出現次數 + x4 – 8
//說明, -8 因為我們要計算一個最大正子串,因此要減去一個正數,至於這個數應該多大,我想還是按經驗來吧。
完整程式碼
#coding:utf-8 import re def remove_js_css (content): """ remove the the javascript and the stylesheet and the comment content (<script>....</script> and <style>....</style> <!-- xxx -->) """ r = re.compile(r'''<script.*?</script>''',re.I|re.M|re.S) s = r.sub ('',content) r = re.compile(r'''<style.*?</style>''',re.I|re.M|re.S) s = r.sub ('', s) r = re.compile(r'''<!--.*?-->''', re.I|re.M|re.S) s = r.sub('',s) r = re.compile(r'''<meta.*?>''', re.I|re.M|re.S) s = r.sub('',s) r = re.compile(r'''<ins.*?</ins>''', re.I|re.M|re.S) s = r.sub('',s) return s def remove_empty_line (content): """remove multi space """ r = re.compile(r'''^\s+$''', re.M|re.S) s = r.sub ('', content) r = re.compile(r'''\n+''',re.M|re.S) s = r.sub('\n',s) return s def remove_any_tag (s): s = re.sub(r'''<[^>]+>''','',s) return s.strip() def remove_any_tag_but_a (s): text = re.findall (r'''<a[^r][^>]*>(.*?)</a>''',s,re.I|re.S|re.S) text_b = remove_any_tag (s) return len(''.join(text)),len(text_b) def remove_image (s,n=50): image = 'a' * n r = re.compile (r'''<img.*?>''',re.I|re.M|re.S) s = r.sub(image,s) return s def remove_video (s,n=1000): video = 'a' * n r = re.compile (r'''<embed.*?>''',re.I|re.M|re.S) s = r.sub(video,s) return s def sum_max (values): cur_max = values[0] glo_max = -999999 left,right = 0,0 for index,value in enumerate (values): cur_max += value if (cur_max > glo_max) : glo_max = cur_max right = index elif (cur_max < 0): cur_max = 0 for i in range(right, -1, -1): glo_max -= values[i] if abs(glo_max < 0.00001): left = i break return left,right+1 def method_1 (content, k=1): if not content: return None,None,None,None tmp = content.split('\n') group_value = [] for i in range(0,len(tmp),k): group = '\n'.join(tmp[i:i+k]) group = remove_image (group) group = remove_video (group) text_a,text_b= remove_any_tag_but_a (group) temp = (text_b - text_a) - 8 group_value.append (temp) left,right = sum_max (group_value) return left,right, len('\n'.join(tmp[:left])), len ('\n'.join(tmp[:right])) def extract (content): content = remove_empty_line(remove_js_css(content)) left,right,x,y = method_1 (content) return '\n'.join(content.split('\n')[left:right])
程式碼 從最後一個函數開始呼叫。