html.parser --- 簡單的 HTML 和 XHTML 剖析器¶
該模組定義了一個類別 HTMLParser,是剖析 (parse) HTML(HyperText Mark-up Language、超文本標記語言)和 XHTML 格式文本檔案的基礎。
- class html.parser.HTMLParser(*, convert_charrefs=True, scripting=False)¶
 建立一個能夠剖析無效標記的剖析器實例。
If convert_charrefs is true (the default), all character references (except the ones in elements like
scriptandstyle) are automatically converted to the corresponding Unicode characters.If scripting is false (the default), the content of the
noscriptelement is parsed normally; if it's true, it's returned as is without being parsed.HTMLParser實例被提供 HTML 資料,並在遇到開始標籤、結束標籤、文本、註解和其他標記元素時呼叫處理程式 (handler) 方法。使用者應該繼承HTMLParser並覆蓋其方法以實作所需的行為。此剖析器不檢查結束標籤是否與開始標籤匹配,也不會為透過結束外部元素來隱晦地被結束的元素呼叫結束標籤處理程式。
在 3.4 版的變更: 新增關鍵字引數 convert_charrefs。
在 3.5 版的變更: 引數 convert_charrefs 的預設值現在是
True。在 3.14.1 版的變更: Added the scripting parameter.
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.close()¶
 強制處理所有緩衝資料,如同它後面跟有文件結束標籤一樣。此方法可能有被衍生類別重新定義,以在輸入末尾定義額外的處理,但重新定義的版本仍應要呼叫
HTMLParser基底類別方法close()。
- HTMLParser.reset()¶
 重置實例。丟棄所有未處理的資料。這在實例化時被會隱晦地呼叫。
- HTMLParser.getpos()¶
 回傳目前列號 (line number) 和偏移量 (offset)。
- HTMLParser.get_starttag_text()¶
 回傳最近開啟 (open) 的開始標籤的文本。這對於結構化處理通常不必要,但在處理「已部署」的 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 ... />) 時呼叫。這個方法可能被需要這個特定詞彙資訊 (lexical information) 的子類別覆蓋;預設實作只是呼叫handle_starttag()和handle_endtag()。
- HTMLParser.handle_data(data)¶
 This method is called to process arbitrary data (e.g. text nodes and the content of elements like
scriptandstyle).
- HTMLParser.handle_entityref(name)¶
 This method is called to process a named character reference of the form
&name;(e.g.>), where name is a general entity reference (e.g.'gt'). This method is only called if convert_charrefs is false.
- HTMLParser.handle_charref(name)¶
 This method is called to process decimal and hexadecimal numeric character references of the form
&#NNN;and&#xNNN;. For example, the decimal equivalent for>is>, whereas the hexadecimal is>; in this case the method will receive'62'or'x3E'. This method is only called if convert_charrefs is false.
- HTMLParser.handle_comment(data)¶
 當遇到註解時呼叫此方法(例如
<!--comment-->)。舉例來說,註解
<!-- comment -->會使得此方法被以引數' comment '來呼叫。Internet Explorer 條件式註解(conditional comments, condcoms)的內容也會被發送到這個方法,故以
<!--[if IE 9]>IE9-specific content<![endif]-->為例,這個方法將會收到'[if IE 9]>IE9-specific content<![endif]'。
- HTMLParser.handle_decl(decl)¶
 呼叫此方法來處理 HTML 文件類型聲明 (doctype declaration)(例如
<!DOCTYPE html>)。decl 參數將是
<!...>標記內聲明部分的全部內容(例如'DOCTYPE html')。
- HTMLParser.handle_pi(data)¶
 遇到處理指示 (processing instruction) 時會呼叫的方法。 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
The content of elements like script and style is returned as is,
without further parsing:
>>> 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]
剖析附名 (named) 且為數值的 (numeric) 字元參照,並將它們轉換為正確的字元(注意:這 3 個參照都等同於 '>'):
>>> parser = MyHTMLParser()
>>> parser.feed('>>>')
Data     : >>>
>>> parser = MyHTMLParser(convert_charrefs=False)
>>> parser.feed('>>>')
Named ent: >
Num ent  : >
Num ent  : >
Feeding incomplete chunks to feed() works, but
handle_data() might be called more than once
if convert_charrefs is false:
>>> 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