基於DBSCAN聚類演算法的通用論壇本文提取__演算法

來源:互聯網
上載者:User

通用論壇本文爬取

這是今年和隊友一起參加第五屆泰迪杯的賽題論文,雖然最終只獲得了一個三等獎。但是在這個過程中和隊友也一起學到了不少東西,特此記錄。

1、  簡單介紹

賽題的目的,是讓參賽者對於任意 BBS 類型的網頁,擷取其 HTML 常值內容,設計一個智能提取該頁面的主貼、所有回帖的演算法。

http://www.tipdm.org/jingsa/1030.jhtml?cName=ral_100#sHref賽題地址。

2、  前期準備

由於之前沒有接觸過爬蟲,我和隊友首先瞭解了目前主流的用於爬蟲的語言和架構,最終選擇了對初學者比較友好的python中bs4架構。之後便是學習了一些簡單的Python用於爬蟲的基本知識,Regex,url包等。

對於賽題,我們首先瞭解到爬蟲分為靜態網頁、動態網頁和web service,我們只對其中的靜態網頁進行了研究,對於動態網頁的比較複雜,由於時間比較緊張,沒有深入研究,對於一些網站的反扒,也沒有深入瞭解。所以接下來主要說在如何設計一個通用的靜態網頁爬蟲架構。(我想這也是我們失分的一部分吧)

思路:

         對於一個普通的網站,我們可能採用Regex來抓取我們想要的內容,但是做到通用性顯然有點強人所難。首先我們從剖析整個網頁結構也就是DOM樹,然後對DOM進行分析,得到主貼節點和回帖節點的特徵,對相似網頁的特徵進行聚類,其中聚類演算法選擇了DBSCAN(因為他可以自動分成幾類,不需要人為設定)。然後形成一個統一的模板,這樣就會減少了我們的工作量。

3、  整體流程

在官方給定的177個url的基礎上,我們自行爬取了736個論壇的url。然後使用736個網頁進行聚類,形成模板,使用177個url進行測試。

對爬取的736個url進行分析,得到以下結果。


可以看出,大多數論壇網站是由開源架構編寫,discuz佔多數。但是不同版本的開源架構,結構也會不同,因此不能使用同一個模板。

 

結構相似性計算:

   首先我們對網頁結構進行解析,得到主貼節點和回帖節點的XPATH值

單個網頁的XPTH特徵可以表述為: 
然後採用dbscan聚類演算法,其中兩個網頁距離的定義如下


 
其中 表示網頁i中特徵的個數, 表示網頁j中特徵的個數;overlap 表示兩個網頁相同的特徵的個數,當兩個網頁相同特徵個數越多時公式(2)的值越趨近於0。
註:在聚類之前,對每一個xpath進行的預先處理,去處了如數字、符號等無關特徵


內容相似性計算:
主要是對URL進行相似性計算。
     ,分析URL的後半部分。
整體網頁相似性計算:
 


其中S1,S2是網頁或簇中心, 是特徵i的權重, 是特徵i的相似性。通過DBSCAN聚類演算法得到初始簇之後,並根據以後的測試資料來不斷的更新特徵庫,從而能動態更新權重,獲得更好的聚類效果。


本文提取流程


通過URL和 XPath模板匹配,可以完成對論壇頁面的識別和過濾,進而對論壇中本文資訊進行識別和抽取。同時,我們可以看到當測試的不同網站越來越多時,XPath庫和模板庫將會越來越豐富,這是一個不斷學習的過程。

不同參數聚類結果:

E=0,minPts = 4

E=0,minPts =8

簇類別

比重

網頁類別

簇類別

比重

網頁類別

1

0.667

discuz

1

0.705

discuz

8

0.089

非開源

5

0.092

phpwind

5

0.0278

phpwind

2

0.041

dvbbs

2

0.0222

dvbbs

6

0.023

非開源

10

0.0222

非開源

10

0.023

非開源

        E=1,minPts = 4

        E=1,minPts = 8

簇類別

比重

網頁類別

簇類別

比重

網頁類別

1

0.630

Discuz

1

0.628

Discuz

3

0.205

非開源

3

0.129

非開源

9

0.123

非開源

2

0.087

dvbbs

4

0.0871

phpwind

4

0.051

phpwind

2

0.051

dvbbs

9

0.021

非開源





















不同參數得到的簇數量:

不同參數得到的簇數量:

參數

E=0,minPts = 4

E=0,minPts =8

E=1,minPts = 4

E=1,minPts = 8

簇個數

23

18

16

14

簇中論壇總數

173

173

194

194

離群點

23

23

10

10

 

測試結果:

論壇網站

測試文章

成功抽取

guba.sina.com.cn

13

13

club.autohome.com.cn

11

11

club.qingdaonews.com

9

9

bbs.tianya.cn

8

8

bbs.360.cn

5

5

bbs1.people.com.cn

5

0

bbs.pcauto.com.cn

5

5

bbs.dospy.com

4

5

bbs.hsw.cn

4

4

itbbs.pconline.com.cn

4

4

www.dddzs.com

4

4

bbs.hupu.com

4

4

bbs.ent.qq.com

3

0

bbs.e23.cn

3

3

bbs.lady.163.com

1

0

www.099t.com

1

0

部分抽取結果:

總結:用的方法比較傳統,只能做到大部分論壇抽取,但是隨著數量的積累,效果越好。沒有用的現在比較火的nlp(應該有同學會用到了),對結果沒有進行過多的過濾。只對本文和發帖時間,主從貼進行細分,對發帖人沒有得到有效解決方案。需要學習的地方還很多。如有錯誤,歡迎指正。

DBSCAN代碼:

 
#encoding:utf-8'''Created on 2017年4月12日'''from collections import defaultdict  import re   '''function to calculate distance  use define formula,(len(i)*len(j)+1)/(overlap*overlap+1)-1parameter url1{url,xpath,feanum}url2{url,xpath,feanum}split /t maybe have counter with /table '''def dist(url1, url2):      values1=url1.split('\t')    values2=url2.split('\t')    #得到xpath    xpath_val1=values1[1][2:].split('/')    xpath_val2=values2[1][2:].split('/')    #得到兩個xpath特徵個數最小的一個    size = len(xpath_val1) if len(xpath_val1) < len(xpath_val2) else len(xpath_val2)    #得到overlap    overlap=0        for i in range(size):        x1=re.sub(r'\[+\]','',re.sub(r'((\d+))','',xpath_val1[i]))        x2=re.sub(r'\[+\]','',re.sub(r'((\d+))','',xpath_val2[i]))        if( x1==x2):            overlap+=1    return ((len(xpath_val1)*len(xpath_val2)+1)/(overlap**2+1)-1)  #將所有的樣本裝入 all_points中 def init_sample(path):    all_points=[]      lines = open(path)    for i in lines:           a=[]        a.append(i)        all_points.append(a)      return all_pointsall_points=init_sample('../../train_bbs_urls.txt')'''take radius = 8 and min.points = 8  '''E = 0  minPts = 8      #find out the core points  other_points =[]  core_points=[]  plotted_points=[]  for point in all_points:      point.append(0)  # assign initial level 0      total = 0    for otherPoint in all_points:          distance = dist(otherPoint[0],point[0])          if distance<=E:              total+=1           if total > minPts:          core_points.append(point)          plotted_points.append(point)      else:          other_points.append(point)  #find border points  border_points=[]  for core in core_points:      for other in other_points:          if dist(core[0],other[0])<=E:              border_points.append(other)              plotted_points.append(other)              other_points.remove(other)        #implement the algorithm  cluster_label=0  print len(core_points)     a=0for point in core_points:      if point[1]==0:          cluster_label +=1          point[1]=cluster_label             for point2 in plotted_points:          distance = dist(point2[0],point[0])          if point2[1] ==0 and distance<=E:  #             print (point, point2 )             point2[1] =point[1]           for i in plotted_points:    print i[0],'    ',i[1]    output=i[0].replace('\n','')+'\t'+str(i[1]).strip()    open('dbscan.txt','a+').write('\n'+output.encode('utf-8'))         #after the points are asssigned correnponding labels, we group them  cluster_list = {}for point in plotted_points:      va=point[0].split('\t')    start=va[0].find('//')    stop=va[0].find('/',start+2)    name=va[0][start+2:stop]        if name not in cluster_list:        cluster_list[name] =point[1]#     else:#         core=cluster_list.get(point[1]).split('\t')#         if name!=core[len(core)-1]:#             cluster_list[point[1]] =cluster_list.get(point[1])+'\t'+nameother_list = {}for point in other_points:      print 'aaaa'    va=point[0].split('\t')    start=va[0].find('//')    stop=va[0].find('/',start+2)    name=va[0][start+2:stop]        if name not in other_list:        print name        other_list[name] =point[1]        # for i in cluster_list.keys():#     print 'i=',i#     output=str(i)+'\t'+str(cluster_list.get(i))#     print output#     open('dbscantype.txt','a+').write('\n'+output.encode('utf-8')) # # for i in other_list.keys():#     print 'i=',i#     output=str(i)+'\t'+str(cluster_list.get(i))#     print output#     open('other_list.txt','a+').write('\n'+output.encode('utf-8')) 


 

 






聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.