html.parser — 簡單的 HTML 和 XHTML 解析器

原始碼: Lib/html/parser.py


此模組定義了一個類 HTMLParser,它作為解析以 HTML(超文字標記語言)和 XHTML 格式化的文字檔案的基礎。

class html.parser.HTMLParser(*, convert_charrefs=True)

建立一個能夠解析無效標記的解析器例項。

如果 convert_charrefsTrue (預設值),則所有字元引用(除了 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; 的命名字元引用(例如,&gt;),其中 *name* 是通用實體引用(例如,'gt')。如果 *convert_charrefs* 為 True,則永遠不會呼叫此方法。

HTMLParser.handle_charref(name)

此方法被呼叫以處理形如 &#NNN;&#xNNN; 的十進位制和十六進位制數字字元引用。例如,&gt; 的十進位制等效項是 &#62;,而十六進位制等效項是 &#x3E;;在這種情況下,該方法將接收 '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()

解析 doctype

>>> 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

scriptstyle 元素的內容按原樣返回,無需進一步解析

>>> 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('&gt;&#62;&#x3E;')
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