【问题标题】:HTMLParser misunderstands entities in href. Is it a bug or not? Should I report it?HTMLParser 误解了 href 中的实体。这是一个错误吗?我应该报告吗?
【发布时间】:2014-11-22 05:04:34
【问题描述】:

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

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)

以下是输出:

"/home?ID=123>3=7"

【问题讨论】:

  • HTML 格式错误; &amp;amp; 应该转义为 &amp;amp;。解析器正在尽力修复损坏。

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


【解决方案1】:

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

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

解析器尽其所能(按照 HTML 标准的要求)并尽其所能为您提供“修复”的数据。在这种情况下,它尝试修复另一个常见的 HTML 损坏错误:将 &amp;gt; 拼写为 &amp;gt(忘记了 ; 分号)。

与其自己构建在(相当低级的)html.parser 库之上,我建议您改用BeautifulSoup。 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。

【讨论】:

  • 我确实已经尝试过使用漂亮的肥皂来查找锚点,但它没有在 html 页面中找到所有锚点,而只找到了第一个。如果我能找到这个例子,我会发布它。也许网页经常不正确
  • BeatifulSoup 使用html.parser,除非您安装了 lxml;单独使用html.parser 毫无意义。这样你不会得到更好的结果。对于损坏的 HTML,请使用不同的解析器。 html5lib 做得最好,但速度较慢。
  • 是的,网络上到处都是破碎的 HTML,这是设置“宽容”标准的缺点。
【解决方案2】:

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

让 s = '

' 给 MyHTMLParser:

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

这是有效的 html 标记,其中 '是为了'。 在这种情况下,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 行。

【讨论】:

    猜你喜欢
    • 2022-10-24
    • 2017-04-01
    • 2017-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    相关资源
    最近更新 更多