UnicodeEncodeError:'ascii'编解码器无法对位置20中的字符u'\ xa0'进行编码:序数不在范围内(128)

问题描述 投票:1131回答:26

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

问题是错误并不总是可重现的;它有时适用于某些页面,有时,它通过投掷UnicodeEncodeError barfs。我已经尝试了几乎所有我能想到的东西,但是我没有找到任何可以持续工作的东西而不会抛出某种与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()

以下是运行上述代码段时在SOME字符串上生成的堆栈跟踪:

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)

我怀疑这是因为某些页面(或更具体地说,来自某些站点的页面)可能被编码,而其他页面可能是未编码的。所有这些网站都位于英国,并提供供英国消费的数据 - 因此,没有与内部化或处理用英语以外的任何文字处理的文本相关的问题。

有没有人有任何想法如何解决这个问题,以便我可以一致地解决这个问题?

python unicode beautifulsoup python-2.x python-unicode
26个回答
1245
投票

你需要阅读Python Unicode HOWTO。这个错误是very first example

基本上,停止使用str从unicode转换为编码的文本/字节。

相反,正确使用.encode()来编码字符串:

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

或者完全以unicode工作。


16
投票

在脚本开头添加以下行(或作为第二行):

# -*- coding: utf-8 -*-

这是python源代码编码的定义。更多信息在PEP 263


13
投票

这是对其他一些所谓的“警察出局”答案的重复。尽管这里有抗议活动,但有些情况下,简单地丢弃麻烦的角色/弦乐是一个很好的解决方案。

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

测试它:

if __name__ == '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

结果:

1
test
98°
98

建议:您可能想要将此函数命名为toAscii而不是?这是一个偏好问题。

这是为Python 2编写的。对于Python 3,我相信你会想要使用bytes(obj,"ascii")而不是str(obj)。我还没有测试过,但我会在某个时候修改答案。


10
投票

在shell中:

  1. 通过以下命令查找支持的UTF-8语言环境: locale -a | grep "UTF-8"
  2. 在运行脚本之前导出它,例如: export LC_ALL=$(locale -a | grep UTF-8) 或手动喜欢: export LC_ALL=C.UTF-8
  3. 通过打印特殊字符来测试它,例如python -c 'print(u"\u2122");'

以上在Ubuntu中测试过。


8
投票

我总是将下面的代码放在python文件的前两行中:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

6
投票

找到here的简单辅助函数。

def safe_unicode(obj, *args):
    """ return the unicode representation of obj """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)

def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        # obj is unicode
        return unicode(obj).encode('unicode_escape')

4
投票

只需添加一个变量编码('utf-8')

agent_contact.encode('utf-8')

3
投票

我刚刚使用了以下内容:

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

检查哪些文档说明了它:

unicodedata.normalize(form,unistr)返回Unicode字符串unistr的普通表单形式。表单的有效值为“NFC”,“NFKC”,“NFD”和“NFKD”。

Unicode标准基于规范等价和兼容性等效的定义定义了Unicode字符串的各种规范化形式。在Unicode中,可以以各种方式表示多个字符。例如,字符U + 00C7(带有CEDILLA的LATIN CAPITAL LETTER C)也可以表示为序列U + 0043(LATIN CAPITAL LETTER C)U + 0327(COMBINING CEDILLA)。

对于每个字符,有两种正常形式:正常形式C和正常形式D.正规形式D(NFD)也称为规范分解,并将每个字符转换为其分解形式。普通形式C(NFC)首先应用规范分解,然后再次组合预组合字符。

除了这两种形式之外,还有两种基于兼容性等效的其他常规形式。在Unicode中,支持某些字符,这些字符通常与其他字符统一。例如,U + 2160(ROMAN NUMERAL ONE)与U + 0049(LATIN CAPITAL LETTER I)完全相同。但是,它支持Unicode以与现有字符集(例如gb2312)兼容。

正常形式KD(NFKD)将应用兼容性分解,即用其等价物替换所有兼容性字符。正常形式KC(NFKC)首先应用兼容性分解,然后是规范组合物。

即使两个unicode字符串被规范化并且看起来与人类读者相同,如果一个具有组合字符而另一个没有,则它们可能无法相等。

为我解决它。简单易行。


3
投票

以下解决方案对我有用,刚补充说

在“字符串”中

(在字符串之前表示字符串为unicode)。

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report.  Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)

2
投票

我们使用本地化的灯具在Django中运行manage.py migrate时遇到了这个错误。

我们的源包含# -*- coding: utf-8 -*-声明,MySQL已正确配置为utf8,Ubuntu在/etc/default/locale中具有相应的语言包和值。

问题只是Django容器(我们使用docker)缺少LANG env var。

在重新运行迁移之前将LANG设置为en_US.UTF-8并重新启动容器可以解决问题。


2
投票

请打开终端并触发以下命令:

export LC_ALL="en_US.UTF-8"

409
投票

这是一个经典的python unicode痛点!考虑以下:

a = u'bats\u00E0'
print a
 => batsà

到目前为止一切都很好,但如果我们调用str(a),让我们看看会发生什么:

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

噢,这不会对任何人有任何好处!要修复错误,请使用.encode显式编码字节并告诉python要使用的编解码器:

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

Voil \ u00E0!

问题在于,当你调用str()时,python使用默认的字符编码来尝试编码你给它的字节,在你的情况下有时代表unicode字符。要解决这个问题,你必须告诉python如何使用.encode('whatever_unicode')处理你给它的字符串。大多数时候,使用utf-8应该没问题。

有关此主题的精彩论述,请参阅Ned Batchelder的PyCon演讲:http://nedbatchelder.com/text/unipain.html


1
投票

我刚刚遇到了这个问题,谷歌把我带到了这里,所以只是为了在这里添加一般解决方案,这对我有用:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

读完Ned's presentation之后,我有了这个想法。

不过,我并没有完全理解为什么会这样。因此,如果有人可以编辑这个答案或发表评论来解释,我会很感激。


1
投票

这有助于python 2.7

import sys
reload(sys)   
sys.setdefaultencoding('utf-8')

这有助于重新启用sys.setdefaultencoding()


0
投票

如果你有类似packet_data = "This is data"的东西,那么在初始化packet_data之后立即在下一行执行此操作:

unic = u''
packet_data = unic

0
投票

更新python 3.0及更高版本。在python编辑器中尝试以下内容:

locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8

这会将系统的默认语言环境编码设置为UTF-8格式。

更多可以阅读here at PEP 538 -- Coercing the legacy C locale to a UTF-8 based locale


0
投票

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

然而,我认为有一个微妙但重要的方面在很大程度上被忽略了,对于每个喜欢我的人来说都很重要,同时试图理解Python中的编码:Python 2与Python 3的字符表示管理有很大的不同。我觉得有一大块混乱,因为人们在没有版本意识的情况下阅读Python中的编码。

我建议有兴趣了解OP问题根本原因的人首先阅读Spolsky's对字符表示和Unicode的介绍,然后在Python 2和Python 3中转到Unicode上的Batchelder


0
投票

我有这个问题试图输出Unicode字符到stdout,但使用sys.stdout.write,而不是打印(这样我也可以支持输出到不同的文件)。

From BeautifulSoup's own documentation,我用编解码器库解决了这个问题:

import sys
import codecs

def main(fIn, fOut):
    soup = BeautifulSoup(fIn)
    # Do processing, with data including non-ASCII characters
    fOut.write(unicode(soup))

if __name__ == '__main__':
    with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
        with codecs.getwriter('utf-8')(sys.stdout) as fOut:
            main(fIn, fOut)

0
投票

唉这至少在Python 3中起作用了......

Python 3

有时错误是在环境变量和编码中

import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
... 
print(myText.encode('utf-8', errors='ignore'))

在编码中忽略错误的地方。


196
投票

我发现优雅的工作方法可以删除符号并继续将字符串保存为字符串如下:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

重要的是要注意使用ignore选项是危险的,因为它会静默地从使用它的代码中删除任何unicode(和国际化)支持,如此处所示(转换unicode):

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'

139
投票

好吧,我尝试了一切,但它没有帮助,谷歌搜索后我认为以下,它有所帮助。 python 2.7正在使用中。

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

80
投票

导致偶数打印失败的一个微妙问题是您的环境变量设置错误,例如。这里LC_ALL设置为“C”。在Debian中,他们不鼓励设置它:Debian wiki on Locale

$ echo $LANG
en_US.utf8
$ echo $LC_ALL 
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà

26
投票

对我来说,有用的是:

BeautifulSoup(html_text,from_encoding="utf-8")

希望这有助于某人。


25
投票

我实际上发现在我的大多数情况下,剥离这些字符要简单得多:

s = mystring.decode('ascii', 'ignore')

20
投票

试试这可能会解决,

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

19
投票

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

您可以尝试安装language-pack-en包来修复:

sudo apt-get install language-pack-en

它为所有支持的软件包(包括Python)提供英文翻译数据更新。如有必要,请安装不同的语言包(取决于您尝试打​​印的字符)。

在某些Linux发行版中,需要确保正确设置默认的英语语言环境(因此可以通过shell /终端处理unicode字符)。有时,安装它比手动配置更容易。

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

例如:

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

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

  • 你的语言环境文件(/etc/default/locale),它应具有例如 LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8" 要么: LC_ALL=C.UTF-8 LANG=C.UTF-8
  • LANG / LC_CTYPE在壳中的价值。
  • 检查shell支持的语言环境: locale -a | grep "UTF-8"

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

  1. 初始化和配置VM(例如使用vagrant): vagrant init ubuntu/trusty64; vagrant up; vagrant ssh 见:available Ubuntu boxes ..
  2. 打印unicode字符(如商标符号,如): $ python -c 'print(u"\u2122");' Traceback (most recent call last): File "<string>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
  3. 现在安装language-pack-en$ sudo apt-get -y install language-pack-en The following extra packages will be installed: language-pack-en-base Generating locales... en_GB.UTF-8... /usr/sbin/locale-gen: done Generation complete.
  4. 现在问题应该解决: $ python -c 'print(u"\u2122");' ™
  5. 否则,请尝试以下命令: $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");' ™
© www.soinside.com 2019 - 2024. All rights reserved.