在Python中将XML / HTML实体转换为Unicode字符串
时间:2020-03-05 18:51:51 来源:igfitidea点击:
我正在做一些网页抓取工作,并且网站经常使用HTML实体来表示非ascii字符。 Python是否有一个实用程序可以接受带有HTML实体的字符串并返回unicode类型?
例如:
我回来了:
ǎ
代表带有色调标记的""。以二进制形式表示为16位01ce。我想将html实体转换为值'u'\ u01ce'
解决方案
回答
我们可以在这里找到答案-从网页上获取国际字符?
编辑:似乎" BeautifulSoup"不会转换以十六进制形式编写的实体。可以解决:
import copy, re from BeautifulSoup import BeautifulSoup hexentityMassage = copy.copy(BeautifulSoup.MARKUP_MASSAGE) # replace hexadecimal character reference by decimal one hexentityMassage += [(re.compile('&#x([^;]+);'), lambda m: '&#%d;' % 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提到的使用htmlentitydefs
标准模块和unichr()
的unescape()
函数可能更合适。
回答
使用内置的unichr
-BeautifulSoup是不必要的:
>>> entity = 'ǎ' >>> unichr(int(entity[3:],16)) u'\u01ce'
回答
Python具有htmlentitydefs模块,但是其中不包含对HTML实体进行转义的功能。
Python开发人员Fredrik Lundh(elementtree的作者等)在他的网站上具有这样的功能,该功能可用于十进制,十六进制和命名实体:
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("&#?\w+;", fixup, text)
回答
此功能应该可以正确处理并将实体转换回utf-8字符的功能。
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 = "&amp;" elif text[1:-1] == "gt": text = "&gt;" elif text[1:-1] == "lt": text = "&lt;" 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("&#?\w+;", fixup, text)
回答
不知道为什么堆栈溢出线程不包含';'在搜索/替换中(即lambda m:'&#%d *; *'),如果不这样做,BeautifulSoup可能会倒钩,因为相邻字符可以解释为HTML代码的一部分(即&#39B表示&# 39停电)。
这对我来说更好:
import re from BeautifulSoup import BeautifulSoup html_string='<a href="/cgi-bin/article.cgi?f=/c/a/2010/12/13/BA3V1GQ1CI.DTL"title="">'Blackout in a can; on some shelves despite ban</a>' hexentityMassage = [(re.compile('&#x([^;]+);'), lambda m: '&#%d;' % int(m.group(1), 16))] soup = BeautifulSoup(html_string, convertEntities=BeautifulSoup.HTML_ENTITIES, markupMassage=hexentityMassage)
- int(m.group(1),16)将数字(以16为基数指定)格式转换回整数。
- m.group(0)返回整个匹配项,m.group(1)返回正则表达式捕获组
- 基本上使用markupMessage与以下内容相同:html_string = re.sub('&#x([^;] +);',lambda m:'&#%d;'%int(m.group(1),16) ,html_string)