在html.parser中禁用entityref解码

问题描述 投票:0回答:1

Python 的

html.parser.HTMLParser
似乎总是解码属性中的实体引用(例如,将
¶
翻译为
)。有办法禁用这个吗?

我喜欢解析的HTML是:

  <ul>
    <li>&para; &amp; &#xb6;</a>
    <li><a href="index.php?option=view&id=108">First link</a>
    <li><a href="index.php?option=view&params=28">Second link</a>
  </ul>

这是格式稍有错误的 HTML:

<li>
标签永远不会关闭,并且 href URL 中的 & 符号未进行 url 编码(应该是
&amp;
)。

遗憾的是,

html.parser.HTMLParser
将 URL 中的
&params
解码为
&para;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>&para; &amp; &#xb6;</a>
  <li><a href="index.php?option=view&id=108">First link</a>
  <li><a href="index.php?option=view&params=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
1个回答
0
投票

由于 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>&para; &amp; &#xb6;</li>
  <li><a href="index.php?option=view&id=108">First link</a></li>
  <li><a href="index.php?option=view&params=28">Second link</a></li>
</ul>
"""

placeholders = { # <-- Replace entities with placeholders
    '&para;': 'PLACEHOLDER_PARA',
    '&amp;': 'PLACEHOLDER_AMP',
    '&#xb6;': '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)
© www.soinside.com 2019 - 2024. All rights reserved.