Python 的
html.parser.HTMLParser
似乎总是解码属性中的实体引用(例如,将 ¶
翻译为 ¶
)。有办法禁用这个吗?
我喜欢解析的HTML是:
<ul>
<li>¶ & ¶</a>
<li><a href="index.php?option=view&id=108">First link</a>
<li><a href="index.php?option=view¶ms=28">Second link</a>
</ul>
这是格式稍有错误的 HTML:
<li>
标签永远不会关闭,并且 href URL 中的 & 符号未进行 url 编码(应该是 &
)。
遗憾的是,
html.parser.HTMLParser
将 URL 中的 ¶ms
解码为 ¶ms
并返回 ¶ms
,如以下代码所示:
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):
if data.strip():
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)
html = """
<ul>
<li>¶ & ¶</a>
<li><a href="index.php?option=view&id=108">First link</a>
<li><a href="index.php?option=view¶ms=28">Second link</a>
</ul>
"""
parser = MyHTMLParser(convert_charrefs=False)
parser.feed(html)
输出为:
Start tag: ul
Start tag: li
Named ent: ¶
Named ent: &
Num ent : ¶
End tag : a
Start tag: li
Start tag: a
attr: ('href', 'index.php?option=view&id=108')
Data : First link
End tag : a
Start tag: li
Start tag: a
attr: ('href', 'index.php?option=view¶ms=28')
Data : Second link
End tag : a
End tag : ul
输出显示为数据调用了
handle_entityref
,但从未为 href 参数调用。因此,我没有能力影响这种行为,并且我陷入了错误解释的 URL 中。
有没有办法通过
html.parser.HTMLParser
禁用entityrefs的解码?
由于 Python 的
html.parser.HTMLParser
没有提供内置方法来防止对属性中的实体引用进行解码,因此要解决此限制,您所能做的就是预处理 HTML 字符串,以将任何实体引用替换为占位符文本(例如,在将其传递给解析器之前使用唯一的字符串。解析后,您可以将这些占位符恢复为其原始实体引用。
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):
if data.strip():
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)
html = """
<ul>
<li>¶ & ¶</li>
<li><a href="index.php?option=view&id=108">First link</a></li>
<li><a href="index.php?option=view¶ms=28">Second link</a></li>
</ul>
"""
placeholders = { # <-- Replace entities with placeholders
'¶': 'PLACEHOLDER_PARA',
'&': 'PLACEHOLDER_AMP',
'¶': 'PLACEHOLDER_NUM'
}
for entity, placeholder in placeholders.items():
html = html.replace(entity, placeholder)
parser = MyHTMLParser()
parser.feed(html)
# And now we replace placeholders back with original entities in the output
for entity, placeholder in placeholders.items():
html = html.replace(placeholder, entity)
print(html)