用python解析html__html

來源:互聯網
上載者:User

       python中,有三個庫可以解析html文本,HTMLParser,sgmllib,htmllib。他們的實現方法不通,但功能差不多。這三個庫中提供解析html的類都是基類,本身並不做具體的工作。他們在發現的元件後(如標籤、注釋、聲名等),會調用相應的函數,這些函數必須重載,因為基類中不作處理。

 

比如:

"""<html><head><title>Advice</title></head><body>
<p>The <a href="http://ietf.org">IETF admonishes:
<i>Be strict in what you <b>send</b>.</i></a></p>
<form>
<input type=submit >  <input type=text name=start size=4></form>
</body></html>
"""

 

如果對這個資料做處理,當檢測到<html>標籤時,對於HTMLParser,會調用handle_starttag函數。

 

 

下面具體介紹下幾個庫 1、HTMLParser

#------------------ HTMLParser_stack.py ------------------# #-- coding: GBK -- import HTMLParser,sys,os,string html = """<html><head><title>Advice</title></head><body> <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: <i>Be strict in what you <b>send</b>.</i></a></p> <form> <input type=submit > <input type=text name=start size=4></form> </body></html> """ tagstack = [] class ShowStructure(HTMLParser.HTMLParser): def handle_starttag(self, tag, attrs): tagstack.append(tag) def handle_endtag(self, tag): tagstack.pop() def handle_data(self, data): if data.strip(): for tag in tagstack: sys.stdout.write('/'+tag) sys.stdout.write(' >> %s/n' % data[:40].strip()) ShowStructure().feed(html)

此函數的輸出:

/html/body/p >> The
/html/body/p/a >> IETF admonishes:
/html/body/p/a/i >> Be strict in what you
/html/body/p/a/i/b >> send
/html/body/p/a/i >> .

對於一些網頁,可能並沒有嚴格的開始結束標籤對,這時,我們可以去忽略一些標籤。可以自己寫個堆棧來處理這些標籤。

#*--------------- TagStack class example -----------------# class TagStack: def __init__(self, lst=[]): self.lst = lst def __getitem__(self, pos): return self.lst[pos] def append(self, tag): # Remove every paragraph-level tag if this is one if tag.lower() in ('p','blockquote'): self.lst = [t for t in self.lst if t not in ('p','blockquote')] self.lst.append(tag) def pop(self, tag): # "Pop" by tag from nearest pos, not only last item self.lst.reverse() try: pos = self.lst.index(tag) except ValueError: raise HTMLParser.HTMLParseError, "Tag not on stack" del self.lst[pos] self.lst.reverse() tagstack = TagStack()

 

 

HTMLParser有個bug,就是不能處理中文屬性,比如說,如果網頁裡有這麼一段:

<input type=submit value=跳轉到>

那麼解析到這一行時就會出錯。


錯誤原因還是Regex惹的禍。
 
attrfind = re.compile(
    r'/s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(/s*=/s*'
    r'(/'[^/']*/'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$/(/)_#=~@]*))?')
attrfind 沒有匹配中文字元。

可以更改這個匹配已修正這個錯誤。sgmllib則不存在這種錯誤。

  2、sgmllib


html格式為sgml格式的一個子集,所以sgml可以處理跟多的東西,下面通過一段代碼來樣本sgmllib的用法。

 

#------------------ HTMLParser_stack.py ------------------# #-- coding: GBK -- import sgmllib,sys,os,string html = """<lala><head><title>Advice</title></head><body> <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes: <i>Be strict in what you <b>send</b>.</i></a></p> <form> <input type=submit name='我'> 我 <input type=text name=start size=4></form> </body></lala> """ os.chdir('d://python') f=file('testboard.txt','r') contest=f.read() tagstack = [] class ShowStructure(sgmllib.SGMLParser): def handle_starttag(self, tag, method,attrs): tagstack.append(tag) def handle_endtag(self, tag): tagstack.pop() def handle_data(self, data): if data.strip(): for tag in tagstack: sys.stdout.write('/'+tag) sys.stdout.write(' >> %s/n' % data[:40].strip()) def unknown_starttag(self,tag,attrs): print 'start tag:<'+tag+'>' def unknown_endtag(self,tag): print 'end tag:</'+tag+'>' def start_lala(self,attr): print 'lala tag found' ShowStructure().feed(html)

 輸出:


start tag:<head>
start tag:<title>
/lala >> Advice
end tag:</title>
end tag:</head>
start tag:<body>
start tag:<p>
/lala >> The
start tag:<a>
/lala >> IETF admonishes:
start tag:<i>
/lala >> Be strict in what you
start tag:<b>
/lala >> send
end tag:</b>
/lala >> .
end tag:</i>
end tag:</a>
end tag:</p>
start tag:<form>
start tag:<input>
/lala >> ϒ
start tag:<input>
end tag:</form>
end tag:</body>
end tag:</lala>

 

和HTMLParser一樣,如果要用sgmllib解析html,則要繼承sgmllib.SGMLParser類,此類裡的函數都是空的,使用者需要重載它。這個類提供的功能是在特定情況下調用相應的函數。

比如當發現<html>標籤時,如果並沒有定義 start_html(self,attr)函數,則會調用unknown_starttag函數,具體怎麼處理則更具使用者。

sgml的標籤是可以自訂的,比如自己定義了一個start_lala函數,則就會處理<lala>標籤。

 

有個地方要說明下,如果定義了start_tagname函數,有定義了handle_starttag函數,則函數只會運行handle_starttag函數,start_tagname為空白函數都沒有問題,如果沒有定義handle_starttag函數,則遇到<tagname>標籤時,會運行start_tagname函數。如果沒有定義tagname的start函數,則此標籤為未知標籤,調用unknown_starttag函數

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.