我在处理从不同网页(在不同的网站上)获取的文本中的unicode字符时遇到了问题。我用的是BeautifulSoup。

问题是,误差并不总是可再现的;它有时会处理某些页面,有时会通过抛出UnicodeEncodeError而退出。我几乎尝试了我能想到的所有方法,但我没有找到任何能在不引发某种Unicode相关错误的情况下始终工作的方法。

导致问题的代码部分如下所示:

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

下面是运行上面的代码段时在某些字符串上生成的堆栈跟踪:

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

我怀疑这是因为某些页面(或者更具体地说,来自某些网站的页面)可能是编码的,而其他页面可能是未编码的。所有的网站都设在英国,并提供英国消费的数据,因此不存在与内化或处理非英语文本相关的问题。

有没有人对如何解决这个问题有什么想法,以便我能够始终如一地解决这个问题?


当前回答

推荐的解决方案不适用于我,我可以忍受转储所有非ascii字符,因此

s = s.encode('ascii',errors='ignore')

这给我留下了一些不会出错的东西。

其他回答

一般情况下,如果将这个不支持的编码字符串(比如data_that_causes_ths_error)写入某个文件(例如results.txt),这是有效的

f = open("results.txt", "w")
  f.write(data_that_causes_this_error.encode('utf-8'))
  f.close()

问题是您试图打印unicode字符,但您的终端不支持它。

您可以尝试安装语言包en-package来解决此问题:

sudo apt-get install language-pack-en

它为所有支持的包(包括Python)提供英语翻译数据更新。如果需要,安装不同的语言包(取决于您要打印的字符)。

在某些Linux发行版上,为了确保正确设置默认的英语区域设置(因此,可以通过shell/终端处理unicode字符),需要使用此选项。有时安装它比手动配置它更容易。

然后在编写代码时,确保在代码中使用正确的编码。

例如:

open(foo, encoding='utf-8')

如果仍有问题,请仔细检查系统配置,例如:

您的区域设置文件(/etc/default/locate),该文件应具有例如。LANG=“en_US.UTF-8”LC_ALL=“en_US.UTF-8”或:LC_ALL=C.UTF-8LANG=C.UTF-8外壳中LANG/LC_CTYPE的值。通过以下方式检查shell支持的语言环境:区域设置-a |grep“UTF-8”


演示新VM中的问题和解决方案。

初始化并设置VM(例如使用流浪者):流浪者init ubuntu/trusty64;流浪;流浪ssh请参阅:可用的Ubuntu盒子。。打印unicode字符(如商标符号™): $python-c'打印(u“\u2122”);'回溯(最近一次调用):文件“<string>”,第1行,在<module>中UnicodeEncodeError:“ascii”编解码器无法对位置0中的字符u“\u2122”进行编码:序号不在范围内(128)现在安装语言包en:$sudo apt-get-y安装语言包en将安装以下额外软件包:基本语言包正在生成区域设置。。。en_GB.UTF-8…/usr/sbin/locale gen:done生成完成。现在应该解决问题:$python-c'打印(u“\u2122”);'™否则,请尝试以下命令:$LC_ALL=C.UTF-8 python-C'打印(u“\u2122”);'™

在运行脚本之前,可以将字符编码设置为UTF-8:

export LC_CTYPE="en_US.UTF-8"

这通常可以解决问题。

我只使用了以下内容:

import unicodedata
message = unicodedata.normalize("NFKD", message)

检查文档中的内容:

unicodedata.normalize(form,unistr)返回Unicode字符串unistr。表单的有效值为“NFC”、“NFKC”、,“NFD”和“NFKD”。Unicode标准定义了Unicode的各种规范化形式字符串,基于规范等价的定义和兼容性等效。在Unicode中以各种方式表达。例如,字符U+00C7(LATIN大写字母C和CEDILLA)也可以表示为序列U+0043(拉丁大写字母C)U+0327(组合塞迪拉)。对于每个字符,有两种范式:范式C和正规形式D(NFD)也称为规范形式并将每个字符转换为其分解形式。范式C(NFC)首先应用正则分解,然后再次编写预先组合的字符。除了这两种形式外,还有两种额外的正规形式基于兼容性等效性。在Unicode中,某些字符是支持通常与其他字符统一的字符。对于例如,U+2160(罗马数字一)实际上与U+0049是一样的(拉丁大写字母I)。但是,Unicode支持与现有字符集(例如gb2312)兼容。范式KD(NFKD)将应用相容性分解,即用它们的等价物替换所有兼容字符。这个范式KC(NFKC)首先应用相容性分解,然后是规范组成。即使两个unicode字符串被规范化人类读者,如果一个有组合字符而另一个没有,它们可能不相等。

帮我解决,简单易行。

这里的许多答案(例如@agf和@Andbdrew)已经解决了OP问题最直接的方面。

然而,我认为有一个微妙但重要的方面在很大程度上被忽视了,这对所有像我这样的人来说都是非常重要的,因为他们在试图理解Python中的编码:Python 2和Python 3对字符表示的管理是截然不同的。我觉得有很大一部分困惑与人们在没有版本意识的情况下阅读Python编码有关。

我建议任何有兴趣了解OP问题根源的人,首先阅读Spolsky对字符表示和Unicode的介绍,然后转到Python 2和Python 3中Unicode的Batchelder。