html.parser --- 簡單的 HTML 和 XHTML 解析器?
源代碼: Lib/html/parser.py
這個模塊定義了一個 HTMLParser 類,為 HTML(超文本標記語言)和 XHTML 文本文件解析提供基礎。
-
class
html.parser.HTMLParser(*, convert_charrefs=True)? 創建一個能解析無效標記的解析器實例。
如果 convert_charrefs 為
True(默認值),則所有字符引用(script/style元素中的除外)都會自動轉換為相應的 Unicode 字符。一個
HTMLParser類的實例用來接受 HTML 數據,并在標記開始、標記結束、文本、注釋和其他元素標記出現的時候調用對應的方法。要實現具體的行為,請使用HTMLParser的子類并重載其方法。這個解析器不檢查結束標記是否與開始標記匹配,也不會因外層元素完畢而隱式關閉了的元素引發結束標記處理。
在 3.4 版更改: convert_charrefs 關鍵字參數被添加。
在 3.5 版更改: convert_charrefs 參數的默認值現在為
True。
HTML 解析器的示例程序?
下面是簡單的 HTML 解析器的一個基本示例,使用 HTMLParser 類,當遇到開始標記、結束標記以及數據的時候將內容打印出來。
from html.parser import HTMLParser
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print("Encountered a start tag:", tag)
def handle_endtag(self, tag):
print("Encountered an end tag :", tag)
def handle_data(self, data):
print("Encountered some data :", data)
parser = MyHTMLParser()
parser.feed('<html><head><title>Test</title></head>'
'<body><h1>Parse me!</h1></body></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 an end tag : body
Encountered an end tag : html
HTMLParser 方法?
HTMLParser 實例有下列方法:
-
HTMLParser.feed(data)? 填充一些文本到解析器中。如果包含完整的元素,則被處理;如果數據不完整,將被緩沖直到更多的數據被填充,或者
close()被調用。data 必須為str類型。
-
HTMLParser.close()? 如同后面跟著一個文件結束標記一樣,強制處理所有緩沖數據。這個方法能被派生類重新定義,用于在輸入的末尾定義附加處理,但是重定義的版本應當始終調用基類
HTMLParser的close()方法。
-
HTMLParser.reset()? 重置實例。丟失所有未處理的數據。在實例化階段被隱式調用。
-
HTMLParser.getpos()? 返回當前行號和偏移值。
-
HTMLParser.get_starttag_text()? 返回最近打開的開始標記中的文本。 結構化處理時通常應該不需要這個,但在處理“已部署”的 HTML 或是在以最小改變來重新生成輸入時可能會有用處(例如可以保留屬性間的空格等)。
下列方法將在遇到數據或者標記元素的時候被調用。他們需要在子類中重載。基類的實現中沒有任何實際操作(除了 handle_startendtag() ):
-
HTMLParser.handle_starttag(tag, attrs)? 這個方法在標簽開始的時候被調用(例如:
<div id="main">)。tag 參數是小寫的標記名。attrs 參數是一個
(name, value)形式的列表,包含了所有在標記的<>括號中找到的屬性。name 轉換為小寫,value 的引號被去除,字符和實體引用都會被替換。實例中,對于標簽
<A HREF="https://www.cwi.nl/">,這個方法將以下列形式被調用handle_starttag('a', [('href', 'https://www.cwi.nl/')])。html.entities中的所有實體引用,會被替換為屬性值。
-
HTMLParser.handle_endtag(tag)? 此方法被用來處理元素的結束標記(例如:
</div>)。tag 參數是小寫的標簽名。
-
HTMLParser.handle_startendtag(tag, attrs)? 類似于
handle_starttag(), 只是在解析器遇到 XHTML 樣式的空標記時被調用(<img ... />)。這個方法能被需要這種特殊詞法信息的子類重載;默認實現僅簡單調用handle_starttag()和handle_endtag()。
-
HTMLParser.handle_data(data)? 這個方法被用來處理任意數據(例如:文本節點和
<script>...</script>以及<style>...</style>中的內容)。
-
HTMLParser.handle_entityref(name)? 這個方法被用于處理
&name;形式的命名字符引用(例如>),其中 name 是通用的實體引用(例如:'gt')。如果 convert_charrefs 為True,該方法永遠不會被調用。
-
HTMLParser.handle_charref(name)? 這個方法被用來處理
&#NNN;和&#xNNN;形式的十進制和十六進制字符引用。例如,>等效的十進制形式為>,而十六進制形式為>;在這種情況下,方法將收到'62'或'x3E'。如果 convert_charrefs 為True,則該方法永遠不會被調用。
-
HTMLParser.handle_comment(data)? 這個方法在遇到注釋的時候被調用(例如:
<!--comment-->)。例如,
<!-- comment -->這個注釋會用' comment '作為參數調用此方法。Internet Explorer 條件注釋(condcoms)的內容也被發送到這個方法,因此,對于
<!--[if IE 9]>IE9-specific content<![endif]-->,這個方法將接收到'[if IE 9]>IE9-specific content<![endif]'。
-
HTMLParser.handle_decl(decl)? 這個方法用來處理 HTML doctype 申明(例如
<!DOCTYPE html>)。decl 形參為
<!...>標記中的所有內容(例如:'DOCTYPE html')。
-
HTMLParser.handle_pi(data)? 此方法在遇到處理指令的時候被調用。data 形參將包含整個處理指令。例如,對于處理指令
<?proc color='red'>,這個方法將以handle_pi("proc color='red'")形式被調用。它旨在被派生類重載;基類實現中無任何實際操作。注解
HTMLParser類使用 SGML 語法規則處理指令。使用'?'結尾的 XHTML 處理指令將導致'?'包含在 data 中。
-
HTMLParser.unknown_decl(data)? 當解析器讀到無法識別的聲明時,此方法被調用。
data 形參為
<![...]>標記中的所有內容。某些時候對派生類的重載很有用。基類實現中無任何實際操作。
例子?
下面的類實現了一個解析器,用于更多示例的演示:
from html.parser import HTMLParser
from html.entities import name2codepoint
class MyHTMLParser(HTMLParser):
def handle_starttag(self, tag, attrs):
print("Start tag:", tag)
for attr in attrs:
print(" attr:", attr)
def handle_endtag(self, tag):
print("End tag :", tag)
def handle_data(self, data):
print("Data :", data)
def handle_comment(self, data):
print("Comment :", data)
def handle_entityref(self, name):
c = chr(name2codepoint[name])
print("Named ent:", c)
def handle_charref(self, name):
if name.startswith('x'):
c = chr(int(name[1:], 16))
else:
c = chr(int(name))
print("Num ent :", c)
def handle_decl(self, data):
print("Decl :", data)
parser = MyHTMLParser()
解析一個文檔類型聲明:
>>> parser.feed('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
... '"http://www.w3.org/TR/html4/strict.dtd">')
Decl : DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"
解析一個具有一些屬性和標題的元素:
>>> parser.feed('<img src="python-logo.png" alt="The Python logo">')
Start tag: img
attr: ('src', 'python-logo.png')
attr: ('alt', 'The Python logo')
>>>
>>> parser.feed('<h1>Python</h1>')
Start tag: h1
Data : Python
End tag : h1
script 和 style 元素中的內容原樣返回,無需進一步解析:
>>> parser.feed('<style type="text/css">#python { color: green }</style>')
Start tag: style
attr: ('type', 'text/css')
Data : #python { color: green }
End tag : style
>>> parser.feed('<script type="text/javascript">'
... 'alert("<strong>hello!</strong>");</script>')
Start tag: script
attr: ('type', 'text/javascript')
Data : alert("<strong>hello!</strong>");
End tag : script
解析注釋:
>>> parser.feed('<!-- a comment -->'
... '<!--[if IE 9]>IE-specific content<![endif]-->')
Comment : a comment
Comment : [if IE 9]>IE-specific content<![endif]
解析命名或數字形式的字符引用,并把他們轉換到正確的字符(注意:這 3 種轉義都是 '>' ):
>>> parser.feed('>>>')
Named ent: >
Num ent : >
Num ent : >
填充不完整的塊給 feed() 執行,handle_data() 可能會多次調用(除非 convert_charrefs 被設置為 True ):
>>> for chunk in ['<sp', 'an>buff', 'ered ', 'text</s', 'pan>']:
... parser.feed(chunk)
...
Start tag: span
Data : buff
Data : ered
Data : text
End tag : span
解析無效的 HTML (例如:未引用的屬性)也能正常運行:
>>> parser.feed('<p><a class=link href=#main>tag soup</p ></a>')
Start tag: p
Start tag: a
attr: ('class', 'link')
attr: ('href', '#main')
Data : tag soup
End tag : p
End tag : a
