【问题标题】:Decoding HTML entities with Python使用 Python 解码 HTML 实体
【发布时间】:2010-11-15 14:04:39
【问题描述】:

我正在尝试从NYTimes.com 解码 HTML 条目,但我无法弄清楚我做错了什么。

举个例子:

"U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’"

我尝试过 BeautifulSoup、decode('iso-8859-1') 和 django.utils.encoding 的 smart_str 都没有成功。

【问题讨论】:

  • 这个问题似乎出现了很多没有好的解决方案。让我想写一些我自己的东西......
  • 哈,我认为这是迄今为止我找到的最佳解决方案。我实际上可能会自己尝试这样做。如果我这样做,我会发布我的解决方案。
  • @Triptych:有unescape()

标签: python unicode character-encoding content-type beautifulsoup


【解决方案1】:

试试这个:

import re

def _callback(matches):
    id = matches.group(1)
    try:
        return unichr(int(id))
    except:
        return id

def decode_unicode_references(data):
    return re.sub("&#(\d+)(;|(?=\s))", _callback, data)

data = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’"
print decode_unicode_references(data)

【讨论】:

  • UnicodeEncodeError: 'charmap' codec can't encode character u'\u2019' in position 12: character maps to 无论我尝试什么,这似乎都是我不断遇到的错误。
  • 你能提供更多代码吗?我刚刚用我写的函数试了一下,字符 2019 工作正常。它显示为:
  • 关于您的正则表达式的几个问题: (1) 不应该是 \d 而不是 \w 吗?正则表达式将匹配    但随后它将在 int() 中崩溃 (2) 允许字符引用(它不是实体)以空格而不是 ';' 结尾看起来很宽容——你不应该提这个吗? (3) 最后一部分写成 [;\s] 不是更好吗?
  • 约翰,您在第一点部分是正确的。它不会匹配  因为那不是以&# 开头的,但是是的,它应该是\d。关于允许它以空格结尾的第二点,应该注意的是,即使它不漂亮,它仍然受到支持。我已按以下方式更新了代码:(​​1) 将其更改为 \d,(2) 使回调更强大,以及 (3) 使用前瞻断言来结束空格,而不是像以前那样吸收它。
  • 埃文,感谢开导,特别是关于空白的容忍度,我不知道。通过查看 HTML 4.01 和 2.0 规范,我得到了更多线索。他们参考了 SGML 标准 (ISO 8879)。成本 = 238 瑞士法郎(!)所以我没有阅读它,但 HTML 2.0 评论说 ';'仅当引用后面的字符将成为名称的一部分时才需要。 FF、IE 和 Opera 的实验使用空格 - / X A 和 & 而不是 ;都给出了相同的结果:它们终止了引用并且没有被吞没。我期待着您更新的解决方案;-)
【解决方案2】:

这确实有效:

from BeautifulSoup import BeautifulStoneSoup
s = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’"
decoded = BeautifulStoneSoup(s, convertEntities=BeautifulStoneSoup.HTML_ENTITIES)

如果您想要一个字符串而不是 Unicode 对象,您需要将其解码为支持所使用字符的编码; ISO-8859-1 没有:

result = decoded.encode("UTF-8")

不幸的是,您需要一个外部模块来完成这样的事情;简单的 HTML/XML 实体解码应该在标准库中,并且不需要我使用诸如“BeautifulStoneSoup”之类的无意义类名的库。 (类和函数名不应该是“创造性的”,它们应该是有意义的。)

【讨论】:

  • lxml,可惜也不在标准库中,它还提供了一个 Beautiful Soup 解析器(以及更多),但“创造性”的名称有点少。
  • 在标准库(模块 htmlentitydefs)中支持实体解码。 OP 拥有的是(十进制)数字字符引用,而不是实体。
  • 与 BeautifulSoup 而不是 BeautifulStoneSoup 一起使用也同样有效——“创意”少了一步 :)
  • '名字不应该是“创意”'这是一个冷酷的规则,还是只是个人选择?
  • @TankorSmash:没有任何权威——除了编译器——强迫你遵循任何编码标准,但这对我来说似乎是常识。
【解决方案3】:

实际上你所拥有的并不是 HTML 实体。这些有三个品种......东西——例如      都表示 U+00A0 NO-BREAK SPACE。

 (您拥有的类型)是“数字字符引用”(十进制)。
  是“数字字符引用”(十六进制)。
  是一个实体。

延伸阅读:http://htmlhelp.com/reference/html40/entities/

您将在此处找到 Python2.x 的代码,该代码对输入进行三合一扫描:http://effbot.org/zone/re-sub.htm#unescape-html

【讨论】:

    【解决方案4】:
    >>> from HTMLParser import HTMLParser
    >>> print HTMLParser().unescape('U.S. Adviser’s Blunt Memo on Iraq: '
    ...                             'Time ‘to Go Home’')
    U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’
    

    该函数在 Python 2 中未记录。It is fixed in Python 3.4+:它公开为 html.unescape() there

    【讨论】:

    • 对于未来的用户来说,这个答案似乎很少有人支持,因为它比现有答案晚了 4 年。这似乎至少是一个很好的答案。这个答案的优点是它很简单(不像编写自己的函数来使用正则表达式解释 HTML 标准)并且使用标准库(不像 BeautifulSoup)。它的缺点是使用了未记录的函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-15
    相关资源
    最近更新 更多