HTMLParser误解了href中的实体。这是一个错误吗?我应该报告吗?

时间:2014-09-27 07:04:15

标签: python html python-3.x html-entities html-parser

我不想知道如何解决这个问题,因为我已经解决了这个问题。我只是问它是不是真的是一个bug以及是否以及如何报告它。 您可以在下面找到代码和输出:

from html.parser import HTMLParser

class MyParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        for at in attrs:
            if at[0] == 'href':
                print(at[1])
        return super().handle_starttag(tag, attrs)

    def handle_data(self, data):
        return super().handle_data(data)

    def handle_endtag(self, tag):
        return super().handle_endtag(tag)



s = '<a href="/home?ID=123&gt3=7">nomeLink</a>'

p = MyParser()
p.feed(s)

以下是输出:

“/家ID = 123&GT; 3 = 7”

2 个答案:

答案 0 :(得分:3)

不,这不是一个错误。您正在为解析器提供无效的HTML,在HTML属性的URL中包含&的正确方法是将其转义为&amp;

>>> s = '<a href="/home?ID=123&amp;gt3=7">nomeLink</a>'
>>> p = MyParser()
>>> p.feed(s)
/home?ID=123&gt3=7

解析器尽力而为(根据HTML标准的要求)并尽最大努力为您提供“已修复”的数据。在这种情况下,它尝试修复另一个常见的HTML错误:将&gt;拼写为&gt(忘记;分号)。

我建议您改用BeautifulSoup,而不是自己构建(相当低级别)html.parser库。 BeautifulSoup支持多个解析器,其中一些解析器可以比其他解析器更好地处理损坏的HTML。

例如,html5lib解析器可以在属性中处理未转义的&符号,而不是html.parser可以:

>>> from bs4 import BeautifulSoup
>>> s = '<a href="/home?ID=123&gt3=7">nomeLink</a>'
>>> BeautifulSoup(s, 'html.parser').find('a')['href']
'/home?ID=123>3=7'
>>> BeautifulSoup(s, 'html5lib').find('a')['href']
'/home?ID=123&gt3=7'

为了完整起见,第三个支持的解析器lxml也处理未转义的&符号,就好像它们被转义一样:

>>> BeautifulSoup(s, 'lxml').find('a')['href']
'/home?ID=123&gt3=7'

你可以直接使用lxmlhtml5lib,但是你放弃了BeautifulSoup提供的漂亮的高级API。

答案 1 :(得分:1)

在win32上的Python 3.3.2(v3.3.2,2013年5月16日,00:03:43)[MSC v.1600 32位(英特尔)]

让Feed s =&#39;&lt; p a =&#34;&amp;#39;&#34;&gt;&#39;到MyHTMLParser:

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print(attrs)

这是有效的html标签,其中&amp;#39;用于&#39;。 在这种情况下,MyHTMLParser为attrs提供:

[('a', "'")]

这种结果的原因是使用了unescape函数:

Lines in source file html/parser.py, class HTMLParser
348:            if attrvalue:
349:                attrvalue = self.unescape(attrvalue)

其中self.unescape是一个内部帮助器,用于删除特殊字符引用,仅用于属性值。请参阅parser.py中的第504-532行。