将HTML实体转换为Unicode,反之亦然

84

如何在Python中将HTML实体转换为Unicode,反之亦然?


17
@Jarret Hardie:实际上,在Stack Overflow上使用show-and-tell是完全可行的。从FAQ的第一条目录(http://stackoverflow.com/faq)中可以看到:“问自己的编程问题并回答它们也是完全可以的”。虽然,我们也鼓励寻找重复的问题。 - chauncey
13
我正在发布一些我曾经为自己解答过的问题,以便其他寻找类似答案的用户受益。 - hekevintran
可以不使用外部库来完成。请参见https://dev59.com/DHRB5IYBdhLWcg3wUFvB#663128 - bobince
6
他正在为数据集做出贡献。 - Ryan Townshend
2
这个问题的范围比“重复”链接所指向的那个更广泛:这个问题还要求从Unicode转换为HTML实体,即“反之亦然”。 - Vebjorn Ljosa
9个回答

111

关于"反之亦然"(我自己也需要这个,所以找到了这个问题,但没有得到帮助,随后在另一个网站上找到了答案):

u'some string'.encode('ascii', 'xmlcharrefreplace')

将返回一个普通字符串,其中任何非ASCII字符都将转换为XML(HTML)实体。


1
我曾经忘记了xmlcharrefreplace,但它非常有用。每当我需要安全地存储编码或非ASCII字符到mysql时,我发现我需要使用这种方法。 - cybertoast
1
这无法处理包含Unicode字符U+2019的字符串文字HTML实体等效项’。 这不就是问题所问的吗(此答案将ASCII转换为Unicode子集)?text.decode('utf-8').encode('ascii', 'xmlcharrefreplace') - Mike S
1
@MikeS 它可以正常工作;>>> u'\u2019'.encode('utf-8').decode('utf-8').encode('ascii', 'xmlcharrefreplace') 返回 '’' - Piotr Dobrogost

33

你需要安装BeautifulSoup

from BeautifulSoup import BeautifulStoneSoup
import cgi

def HTMLEntitiesToUnicode(text):
    """Converts HTML entities to unicode.  For example '&' becomes '&'."""
    text = unicode(BeautifulStoneSoup(text, convertEntities=BeautifulStoneSoup.ALL_ENTITIES))
    return text

def unicodeToHTMLEntities(text):
    """Converts unicode to HTML entities.  For example '&' becomes '&'."""
    text = cgi.escape(text).encode('ascii', 'xmlcharrefreplace')
    return text

text = "&, ®, <, >, ¢, £, ¥, €, §, ©"

uni = HTMLEntitiesToUnicode(text)
htmlent = unicodeToHTMLEntities(uni)

print uni
print htmlent
# &, ®, <, >, ¢, £, ¥, €, §, ©
# &amp;, &#174;, &lt;, &gt;, &#162;, &#163;, &#165;, &#8364;, &#167;, &#169;

2
BeautifulSoup的API已经发生了变化。请参阅最新的文档 - scharfmn
@hekevintran:有没有可能打印 '¢, £, ¥, €, §, ©' 而不是 '¢, £, ¥, €, §, ©'。有什么想法吗? - Jagath
9
这个回答迫切需要更新为Python3版本。 - Routhinator

22

Python 2.7 和 BeautifulSoup4 的更新

使用 htmlparser 将 Unicode HTML 转换为 Unicode(Python 2.7 标准库):

>>> escaped = u'Monsieur le Cur&eacute; of the &laquo;Notre-Dame-de-Gr&acirc;ce&raquo; neighborhood'
>>> from HTMLParser import HTMLParser
>>> htmlparser = HTMLParser()
>>> unescaped = htmlparser.unescape(escaped)
>>> unescaped
u'Monsieur le Cur\xe9 of the \xabNotre-Dame-de-Gr\xe2ce\xbb neighborhood'
>>> print unescaped
Monsieur le Curé of the «Notre-Dame-de-Grâce» neighborhood

使用bs4(BeautifulSoup4)将Unicode HTML反转义为Unicode:

>>> html = '''<p>Monsieur le Cur&eacute; of the &laquo;Notre-Dame-de-Gr&acirc;ce&raquo; neighborhood</p>'''
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup(html)
>>> soup.text
u'Monsieur le Cur\xe9 of the \xabNotre-Dame-de-Gr\xe2ce\xbb neighborhood'
>>> print soup.text
Monsieur le Curé of the «Notre-Dame-de-Grâce» neighborhood

使用bs4(BeautifulSoup4)将Unicode转换为unicode HTML:

>>> unescaped = u'Monsieur le Curé of the «Notre-Dame-de-Grâce» neighborhood'
>>> from bs4.dammit import EntitySubstitution
>>> escaper = EntitySubstitution()
>>> escaped = escaper.substitute_html(unescaped)
>>> escaped
u'Monsieur le Cur&eacute; of the &laquo;Notre-Dame-de-Gr&acirc;ce&raquo; neighborhood'

3
点赞展示一个没有依赖项的标准库解决方案。 - Hartley Brody
重新审视 我刚看到@bobince在问题上留下的评论,指向这个答案。由于htmlparser现在已经有文档记录,而且那个评论并不突出,所以我删除了那部分回答。 - scharfmn

17

正如hekevintran的回答所建议的,你可以使用cgi.escape(s)对字符串进行编码,但需要注意该函数中的引号编码默认为false,因此最好在字符串旁边传递quote=True关键字参数。即使通过传递quote=True,该函数也不会转义单引号("'")。(由于这些问题,该函数自版本3.2以来已被废弃

建议使用html.escape(s)替代cgi.escape(s)。(自版本3.2开始)

同时,在版本3.4中引入了html.unescape(s)

因此,在Python 3.4中:

  • 使用html.escape(text).encode('ascii', 'xmlcharrefreplace').decode()将特殊字符转换为HTML实体。
  • 使用html.unescape(text)将HTML实体转换回普通文本表示。

1
在Python 2.7中,您可以使用HTMLParser.unescape(text)。 - frank

13
对于使用python3的情况,可以使用html.unescape()函数:
import html
s = "&amp;"
u = html.unescape(s)
# &

1
简单而甜美。 - Mark Ransom

8
$ python3 -c "
> import html
> print(
>     html.unescape('&amp;&#169;&#x2014;')
> )"
&©—

$ python3 -c "
> import html
> print(
>     html.escape('&©—')
> )"
&amp;©—

$ python2 -c "
> from HTMLParser import HTMLParser
> print(
>     HTMLParser().unescape('&amp;&#169;&#x2014;')
> )"
&©—

$ python2 -c "
> import cgi
> print(
>     cgi.escape('&©—')
> )"
&amp;©—

HTML只严格要求对&(和号)和<(左尖括号/小于号)进行转义。 https://html.spec.whatwg.org/multipage/parsing.html#data-state


3
如果像我这样的人想知道为什么某些实体编号(代码)如&#153;(商标符号),&#128;(欧元符号)未被正确编码,原因在于在ISO-8859-1(又名Windows-1252)中这些字符未定义。

同时请注意,默认字符集从html4更改为html5的utf-8。

因此,我们必须找到解决方法(首先查找和替换它们)。

参考来源(起点)来自Mozilla的文档。

https://developer.mozilla.org/en-US/docs/Web/Guide/Localizations_and_character_encodings


1
我使用了以下函数将从xls文件中提取的Unicode转换为HTML文件,并保留了在xls文件中找到的特殊字符:
def html_wr(f, dat):
    ''' write dat to file f as html
        . file is assumed to be opened in binary format
        . if dat is nul it is replaced with non breakable space
        . non-ascii characters are translated to xml       
    '''
    if not dat:
        dat = '&nbsp;'
    try:
        f.write(dat.encode('ascii'))
    except:
        f.write(html.escape(dat).encode('ascii', 'xmlcharrefreplace'))

希望这对某个人有用。

0
#!/usr/bin/env python3
import fileinput
import html

for line in fileinput.input():
    print(html.unescape(line.rstrip('\n')))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接