在Python中将XML / HTML实体转换为Unicode字符串

在Python中将XML / HTML实体转换为Unicode字符串

Convert XML/HTML Entities into Unicode String in Python

本问题已经有最佳答案,请猛点这里访问。

我正在做一些网页抓取工作,并且网站经常使用HTML实体来表示非ascii字符。 Python是否有一个实用程序可以接受带有HTML实体的字符串并返回unicode类型?

例如:

我回来了:

1
 

代表带有音调标记的"ǎ"。 以二进制形式表示为16位01ce。 我想将html实体转换为值u'\\u01ce'


Python具有htmlentitydefs模块,但是其中不包含对HTML实体进行转义的功能。

Python开发人员Fredrik Lundh(elementtree的作者等)在他的网站上具有这样的功能,该功能可用于十进制,十六进制和命名实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import re, htmlentitydefs

##
# Removes HTML or XML character references and entities from a text string.
#
# @param text The HTML (or XML) source text.
# @return The plain text, as a Unicode string, if necessary.

def unescape(text):
    def fixup(m):
        text = m.group(0)
        if text[:2] =="&#":
            # character reference
            try:
                if text[:3] =="&#x":
                    return unichr(int(text[3:-1], 16))
                else:
                    return unichr(int(text[2:-1]))
            except ValueError:
                pass
        else:
            # named entity
            try:
                text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
            except KeyError:
                pass
        return text # leave as is
    return re.sub("", fixup, text)

标准库自己的HTMLParser具有未记录的函数unescape(),它可以完全按照您的想法进行操作:

直至Python 3.4:

1
2
3
4
import HTMLParser
h = HTMLParser.HTMLParser()
h.unescape('© 2010') # u'\\xa9 2010'
h.unescape(' 2010') # u'\\xa9 2010'

Python 3.4+:

1
2
3
import html
html.unescape('© 2010') # u'\\xa9 2010'
html.unescape(' 2010') # u'\\xa9 2010'

使用内置的unichr-不需要BeautifulSoup:

1
2
3
>>> entity = '&#x01ce'
>>> unichr(int(entity[3:],16))
u'\\u01ce'

如果您使用的是Python 3.4或更高版本,则可以简单地使用html.unescape

1
2
3
import html

s = html.unescape(s)

替代方法,如果您有lxml:

1
2
3
>>> import lxml.html
>>> lxml.html.fromstring('&#x01ce').text
u'\\u01ce'

您可以在这里找到答案-从网页获取国际字符?

编辑:似乎BeautifulSoup不会转换以十六进制形式编写的实体。可以解决:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import copy, re
from BeautifulSoup import BeautifulSoup

hexentityMassage = copy.copy(BeautifulSoup.MARKUP_MASSAGE)
# replace hexadecimal character reference by decimal one
hexentityMassage += [(re.compile(' ]+);'),
                     lambda m: ' ' % int(m.group(1), 16))]

def convert(html):
    return BeautifulSoup(html,
        convertEntities=BeautifulSoup.HTML_ENTITIES,
        markupMassage=hexentityMassage).contents[0].string

html = '<html> </html>'
print repr(convert(html))
# u'\\u01ce\\u01ce'

编辑:

@dF提到的unescape()函数使用htmlentitydefs标准模块和unichr()在这种情况下可能更合适。


此功能应该可以帮助您正确处理并将实体转换回utf-8字符的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def unescape(text):
  """Removes HTML or XML character references
      and entities from a text string.
   @param text The HTML (or XML) source text.
   @return The plain text, as a Unicode string, if necessary.
   from Fredrik Lundh
   2008-01-03: input only unicode characters string.
   http://effbot.org/zone/re-sub.htm#unescape-html
  """

   def fixup(m):
      text = m.group(0)
      if text[:2] =="&#":
         # character reference
         try:
            if text[:3] =="&#x":
               return unichr(int(text[3:-1], 16))
            else:
               return unichr(int(text[2:-1]))
         except ValueError:
            print"Value Error"
            pass
      else:
         # named entity
         # reescape the reserved characters.
         try:
            if text[1:-1] =="amp":
               text ="&"
            elif text[1:-1] =="gt":
               text =">"
            elif text[1:-1] =="lt":
               text ="<"
            else:
               print text[1:-1]
               text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
         except KeyError:
            print"keyerror"
            pass
      return text # leave as is
   return re.sub("", fixup, text)

不知道为什么堆栈溢出线程不包含';'在搜索/替换中(即lambda m:'em>; *'),否则,BeautifulSoup可能会倒钩,因为可以将相邻字符解释为HTML代码的一部分(即&#39B表示&#39Blackout)。

这对我来说更好:

1
2
3
4
5
6
7
8
9
10
11
import re
from BeautifulSoup import BeautifulSoup

html_string=' Blackout in a can; on some shelves despite ban'

hexentityMassage = [(re.compile(' ]+);'),
lambda m: ' ' % int(m.group(1), 16))]

soup = BeautifulSoup(html_string,
convertEntities=BeautifulSoup.HTML_ENTITIES,
markupMassage=hexentityMassage)
  • int(m.group(1),16)将数字(以base-16指定)格式转换回整数。
  • m.group(0)返回整个匹配项,m.group(1)返回正则表达式捕获组
  • 基本上,使用markupMessage与:
    html_string = re.sub('] +);',lambda m:''%int(m.group(1),16),html_string)

  • 另一个解决方案是内置库xml.sax.saxutils(用于html和xml)。但是,它将仅转换&gt,&amp和&lt。

    1
    2
    3
    from xml.sax.saxutils import unescape

    escaped_text = unescape(text_to_escape)

    这是dF的答案的Python 3版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import re
    import html.entities

    def unescape(text):
       """
        Removes HTML or XML character references and entities from a text string.

        :param text:    The HTML (or XML) source text.
        :return:        The plain text, as a Unicode string, if necessary.
       """

        def fixup(m):
            text = m.group(0)
            if text[:2] =="&#":
                # character reference
                try:
                    if text[:3] =="&#x":
                        return chr(int(text[3:-1], 16))
                    else:
                        return chr(int(text[2:-1]))
                except ValueError:
                    pass
            else:
                # named entity
                try:
                    text = chr(html.entities.name2codepoint[text[1:-1]])
                except KeyError:
                    pass
            return text # leave as is
        return re.sub("", fixup, text)

    主要更改涉及现在为html.entitieshtmlentitydefs和现在为chrunichr。请参阅此Python 3移植指南。


    推荐阅读

      linux入侵网站命令?

      linux入侵网站命令?,工作,地址,信息,系统,数字,网站,名称,命令,网络,密码,lin

      字符串查找命令linux?

      字符串查找命令linux?,系统,字符串,工具,信息,文件,命令,字符,选项,文本,范

      linux命令替换字符串?

      linux命令替换字符串?,字符串,文件,批量,首次,数据,命令,内容,方法,用字,结

      linux命令中转义字符?

      linux命令中转义字符?,标准,本行,密码,字符,电脑,系统,环境,数据,命令,终端,l

      linux命令行字符颜色?

      linux命令行字符颜色?,系统,地址,代码,信息,数字,软件,通用,电脑,颜色,命令,l

      linux彩色字符命令?

      linux彩色字符命令?,数字,颜色,命令,字符,文字,终端,控制台,环境变量,白色,

      linux中替换字符命令?

      linux中替换字符命令?,工作,地址,系统,命令,资料,数据,信息,商业,管理,目录,L

      linux网站根目录命令?

      linux网站根目录命令?,系统,一致,设备,网站,目录,根目录,信息,标准,位置,电

      linux拼接字符串命令?

      linux拼接字符串命令?,系统,工作,代码,工具,名称,信息,地址,时间,数据,命令,l

      linux图形转字符命令?

      linux图形转字符命令?,系统,电脑,密码,界面,情况,地方,工具,图形界面,字符,

      linux隐藏字符的命令?

      linux隐藏字符的命令?,工作,地址,系统,发行,信息,标准,管理,命令,目录,文件,

      linux命令行最大字符?

      linux命令行最大字符?,系统,工作,数字,地址,等级,设备,软件,信息,标准,设计,l

      添加字符串命令linux?

      添加字符串命令linux?,情况,名称,文件,位置,名字,地方,连续,信息,命令,内容,L

      linux访问网站的命令?

      linux访问网站的命令?,地址,系统,服务,工作,网站,命令,网络,管理,信息,网址,L

      linux命令行大字符?

      linux命令行大字符?,工作,地址,系统,信息,管理,第一,发行,在线,最新,标准,lin

      linux命令查找字符串?

      linux命令查找字符串?,工具,信息,命令,字符串,系统,工作,文件,范本,样式,文

      linux命令字符搜索?

      linux命令字符搜索?,系统,工具,命令,灵活,信息,工作,字符串,文本,文件,模式,l

      linux大写字符命令?

      linux大写字符命令?,系统,工作,信息,档案,数字,地址,命令,名称,密码,时间,lin

      linux字符匹配命令?

      linux字符匹配命令?,工作,地址,管理,系统,工具,标准,命令,目录,信息,文件,Lin

      linux命令行登陆网站?

      linux命令行登陆网站?,网站,系统,密码,服务,地址,环境,网络,软件,状态,项目,