PYTHON HTML.PARSER庫學習小結--轉載

前段時間,一朋友讓我作個小腳本,抓一下某C2C商城上競爭對手的銷售/價格數據,好讓他能夠實時調整本身的營銷策略。本身以前也有過寫爬蟲抓某寶數據的經歷,實現的問題不大,因而就答應了。初步想法是利用pyhton中的urllib.request和re兩個lib(本文示例用的是Pyhton 3.4 ,2.x的請自行切換),外加上其餘的統計分析功能的話,最多兩個晚上(白天要工做)能夠搞定。實際上作的過程當中,遇到了兩個主要困難:
(1)電商網站對於交易數據的保護很好。小爬蟲動不動就會被ban掉或者採用一些其餘的保護措施使得其沒法正常採集所需的數據,須要添加額外的代碼處理各類虐心的狀況;
(2)正則表達式實在是難寫,並且很複雜和很難維護。因而本身也思考有沒有其餘的解決方案——本文就是對其中一解決方案的初步介紹。
 
一開始想到的固然是著名的第三方庫 Beautifulsoup(做爲一個廣東男人,我習慣把它稱爲」靚湯「)。這個庫很強大,但正由於它強大,須要一點學習時間而我須要快點上手,因而只好往後再學(到時再寫一篇Beautifulsoup學習總結)。權衡之後,最後目光轉向了Python Standard Library中的html.parser。
 
html.parser是一個很是簡單和實用的庫,它的核心是HTMLParser類。從源碼來看,它內部封裝了一系列regular expression。工做的流程是:當你feed給它一個相似HTML格式的字符串時,它會調用goahead方法向前迭代各個標籤,並調用對應的parse_xxxx方法提取start_tag, tag, attrs data comment和end_tag等等標籤信息和數據,而後調用對應的方法對這些抽取出來的內容進行處理。整個HTMLParser的大體結構以下圖所示:
 
 
 
能夠發現,處理開始標籤(handle_starttag)、結束標籤(handle_endtag)和處理數據(handle_data)等處理函數在HTMLParser裏是沒有實現的(pass),這須要咱們繼承HTMLParser這個類的並覆蓋這些方法。詳細能夠參閱python文檔,這裏重點介紹幾個經常使用的方法:
 
  1. feed(data):主要用於接受帶html標籤的str,當調用這個方法時並提供相應的data時,整個實例(instance)開始執行,結束執行close()。
  2. handle_starttag(tag, attrs): 這個方法接收Parse_starttag返回的tag和attrs,並進行處理,處理方式一般由使用者進行覆蓋,自己爲空。例如,鏈接的start tag是<a>,那麼對應的參數tag=’a’(小寫)。attrs是start tag <>中的屬性,以元組形式(name, value)返回(全部這些內容都是小寫)。例如,對於<A HREF="http://www.baidu.com「>,那麼內部調用形式爲:handle_starttag(’a’,[(‘href’,’http://www.baidu.com)]).
  3. handle_endtag(tag):跟上述同樣,只是處理的是結束標籤,也就是以</開頭的標籤。
  4. handle_data(data):處理的是網頁的數據,也就是開始標籤和結束標籤之間的內容。例如:<script>...</script>的省略號內容
  5. reset():將實例重置,包括做爲參數輸入的數據進行清空。
 
舉個例子吧。例如咱們有如下一堆帶HTML標籤的數據,

     【金冠現貨/全色/頂配版】Xiaomi/小米 小米note移動聯通4G手機
   </h3>
   <p class=" tb-subtitle">
 【購機即送布丁套+高清貼膜+線控耳機+剪卡器+電影支架等等,套餐更多豪禮更優惠】    【購機即送布丁套+高清貼膜+線控耳機+剪卡器+電影支架等等,套餐更多豪禮更優惠】    【金冠信譽+順豐包郵+全國聯保---多重保障】
 </p>
   <div id=" J_TEditItem" class=" tb-editor-menu"></div>
 </div>
<h3 class=" tb-main-title" data-title=" 【現貨加強/標準】MIUI/小米 紅米手機2紅米2移動聯通電信4G雙卡">
     【現貨加強/標準】MIUI/小米 紅米手機2紅米2移動聯通電信4G雙卡
   </h3>
   <p class=" tb-subtitle">
 [紅米手機2代顏色版本較多,請親們閱讀購買說明按需選購---感謝光臨] 【金皇冠信譽小米手機集市銷量第一】【購買套餐送高清鋼化膜+線控通話耳機+ 剪卡器(含還原卡託)+ 防輻射貼+專用高清貼膜+ 擦機布+ 耳機繞線器+手機電影支架+ 一年延保服務+ 默認享受順豐包郵 !
 </p>
   <div id=" J_TEditItem" class=" tb-editor-menu"></div>
 </div>

很明顯,這裏麪包含了兩臺手機,咱們的目標是提取兩個手機的名字出來。
 
因爲當咱們feed這個html到HTMLParser中後,他們全部的標籤都迭代,若是須要它只提取咱們須要的數據時,咱們須要設置當handle_starttag遇到那個標籤和屬性時,才調用handle_data並print出咱們的結果,這個時候咱們可使用一個flg做爲斷定,代碼以下:
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#定義一個MyParser繼承自HTMLParser
class  MyParser(HTMLParser):
     re = [] #放置結果
     flg = 0 #標誌,用以標記是否找到咱們須要的標籤
     def  handle_starttag( self , tag, attrs):
         if  tag = = 'h3' : #目標標籤
             for  attr  in  attrs:
                 if  attr[ 0 ] = = 'class'  and  attr[ 1 ] = = 'tb-main-title' : #目標標籤具備的屬性
                     self .flg = 1 #符合條件則將標誌設置爲1
                     break
         else :
             pass
  
     def  handle_data( self , data):
         if  self .flg = = 1 :
             self .re.append(data.strip()) #若是標誌爲咱們須要的標誌,則將數據添加到列表中
             self .flg = 0 #重置標誌,進行下次迭代
         else :
             pass
 
 
my = MyParser()
my.feed(html)
 
運行結果以下,達到了咱們的預期:


 
上面只是HTMLParser一個很是簡單的應用,但卻能夠反應了HTMLParser這個類的一些特質。有了這些基本的認識後,咱們就能夠將相關功能進行擴展,從而造成一個標準的爬蟲了。下次,咱們將利用相關的知識,構建一個基本的網絡爬蟲,敬請期待哦。
 
--------------------------------------------------
本文爲做者原創文章,轉摘請註明出處:@Datazen
相關文章
相關標籤/搜索