python模塊之HTMLParser簡介
html.parser是一個非常簡單和實用的庫,它的核心是HTMLParser類。
工作的流程是:當你feed給它一個類似HTML格式的字符串時,它會調用goahead方法向前叠代各個標簽,並調用對應的parse_xxxx方法提取start_tag, tag, attrs data comment和end_tag等等標簽信息和數據,然後調用對應的方法對這些抽取出來的內容進行處理。整個HTMLParser的大致結構如下圖所示:
可以發現,處理開始標簽(handle_starttag)、結束標簽(handle_endtag)和處理數據(handle_data)等處理函數在HTMLParser裏是沒有實現的(pass),這需要我們繼承HTMLParser這個類的並覆蓋這些方法。詳細可以參閱python文檔,https://docs.python.org/3/library/html.parser.html?highlight=htmlparser
一、常用方法介紹
l feed(data):主要用於接受帶html標簽的str,當調用這個方法時並提供相應的data時,整個實例(instance)開始執行,結束執行close()。
l 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)]).
l handle_endtag(tag):跟上述一樣,只是處理的是結束標簽,也就是以</開頭的標簽。
l handle_data(data):處理的是網頁的數據,也就是開始標簽和結束標簽之間的內容。例如:<script>...</script>的省略號內容
l handle_comment(data) ,處理註釋,<!-- -->之間的文本
l reset():將實例重置,包括作為參數輸入的數據進行清空。
二、基本使用from html.parser import
以上是根據python手冊寫的基本使用,解析了一個簡單的html。可以運行看看,主要用於了解各個函數負責解析的部分,以及解析順序
Encountered a start tag: html Encountered a start tag: head Encountered a start tag: title Encountered some data : Test Encountered an end tag : title Encountered an end tag : head Encountered a start tag: body Encountered a start tag: h1 Encountered some data : Parse me! Encountered an end tag : h1 Encountered startendtag : img Encountered comment : comment Encountered an end tag : body Encountered an end tag : html
三、實用案例
以下的實用案例均在上面的代碼中修改對應函數,每個實例都是單獨的。
解析的html如下
<html> <head> <title>Test</title> </head> <body> <h1>Parse me!</h1> <img src = "" /> <p class=‘123‘>A paragraph.</p> <p class = "p_font">A paragraph with class.</p> <!-- comment --> <div> <p>A paragraph in div.</p> </div> </body> </html>
1.獲取所有p標簽的文本,最簡單方法只修改handle_data
def handle_data(self, data): if self.lasttag == ‘p‘: print("Encountered p data :", data)
2.獲取css樣式(class)為p_font的p標簽的文本,使用了案例1,增加一個實例屬性作為標誌,選取需要的標簽
def __init__(self): HTMLParser.__init__(self) self.flag = False def handle_starttag(self, tag, attrs): for attr in attrs: if tag == ‘p‘ and attr[1]==‘"p_font": self.flag = True def handle_data(self, data): if self.flag == True: print("Encountered p data :", data)
3.獲取p標簽的屬性列表
def handle_starttag(self, tag, attrs): if tag == ‘p‘: print("Encountered p attrs :", attrs)
4.獲取p標簽的class屬性
def handle_starttag(self, tag, attrs): for attr in attrs: If tag == ‘p‘ and attr[0]= ‘class‘): print("Encountered p class :", attr[1])
5.獲取div下的p標簽的文本
def __init__(self): HTMLParser.__init__(self) self.in_div = False def handle_starttag(self, tag, attrs): if tag == ‘div‘: self.in_div = True def handle_data(self, data): if self.in_div == True and self.lasttag == ‘p‘: print("Encountered p data :", data) self.in_div = False
6.處理註釋中的標簽,若需要的數據在註釋中,使用一般函數解析不到
處理方法為,寫兩個類,繼承HTMLParser。在其中一個類的handle_comment裏實例化解析類,和其他標簽一樣解析
def __init__(self): HTMLParser.__init__(self) def handle_comment(self,data): print(("Encountered comment:",data)
完整實例
例如:我們有以下一堆帶HTML標簽的數據
html = ‘‘‘<h3 class="tb-main-title" data-title="Xiaomi/小米"> 【金冠現貨/全色/頂配版】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/小米"> 【現貨增強/標準】MIUI/小米 紅米手機2紅米2移動聯通電信4G雙卡 </h3> <p class="tb-subtitle"> [紅米手機2代顏色版本較多,請親們閱讀購買說明按需選購---感謝光臨] <div id="J_TEditItem" class="tb-editor-menu"></div> </div>‘‘‘
很明顯,這裏面包含了兩臺手機,我們的目標是提取兩個手機的名字出來。
由於當我們feed這個html到HTMLParser中後,他們所有的標簽都叠代,如果需要它只提取我們需要的數據時,我們需要設置當handle_starttag遇到那個標簽和屬性時,才調用handle_data並print出我們的結果,這個時候我們可以使用一個flag作為判定,代碼如下:
#定義一個MyParser繼承自HTMLParser class MyParser(HTMLParser): re=[]#放置結果 flag=0#標誌,用以標記是否找到我們需要的標簽 def handle_starttag(self, tag, attrs): if tag==‘p‘:#目標標簽 for attr in attrs: if attr[0]==‘class‘ and attr[1]==‘tb-subtitle‘:#目標標簽具有的屬性 self.flag=1#符合條件則將標誌設置為1 break else: pass def handle_data(self, data): if self.flag==1: self.re.append(data.strip())#如果標誌為我們設置的,則將數據添加到列表中 self.flag=0#重置標誌,進行下次叠代 else: pass my=MyParser() my.feed(html) my.re
運行結果如下,達到了我們的預期:
[‘【購機即送布丁套+高清貼膜+線控耳機+剪卡器+電影支架等等,套餐更多豪禮更優惠】‘,
‘[紅米手機2代顏色版本較多,請親們閱讀購買說明按需選購---感謝光臨]‘]
python模塊之HTMLParser簡介