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


1296

我在处理从不同网页(在不同站点上)获取的文本中的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)

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

是否有人对如何解决此问题有任何想法,以便我可以始终如一地解决此问题?


1
如果您收到这些错误的用户,而不是作为一个开发者,检查serverfault.com/questions/54591/...askubuntu.com/questions/599808/...
那巴西盖伊

我要补充一点,不要将onlinegdb.com/online_python_interpreter用于此内容。正在使用该解释器试用内容,但未正确配置Unicode!总是以'B'\ nnn''格式打印...当我想要的只是guillemet时!在VM上进行了尝试,并使用chr()可以按预期立即工作
JGFMK '18年

4
试试这个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'))
hhh

@hhh我运行了您的代码段NameError:名称'myText'未定义
KHAN irfan

9
在执行脚本之前,尝试在外壳中设置PYTHONIOENCODING$ export PYTHONIOENCODING=utf8
Noam Manos

Answers:


1361

您需要阅读Python Unicode HOWTO。这个错误是第一个例子

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

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

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

或完全以unicode工作。


23
同意!我被教导的一个很好的经验法则是使用“ unicode三明治”的想法。您的脚本接受外界的字节,但所有处理均应以unicode进行。仅当准备好输出数据时,才应将其重新划分为字节!
Andbdrew 2012年

255
如果有人对此感到困惑,我会发现一个奇怪的事情:我的终端使用utf-8,当print我使用utf-8字符串时,它可以很好地工作。但是,当我将程序输出通过管道传输到文件时,它会抛出一个UnicodeEncodeError。实际上,当输出重定向到文件或管道时,我发现它sys.stdout.encodingNone!坚持.encode('utf-8')解决问题。
drevicko

93
@drevicko:PYTHONIOENCODING=utf-8改为使用即打印Unicode字符串,并让环境设置所需的编码。
jfs

1
@steinar:在每种情况下都无效。通常,用户不必关心您使用Python来实现实用程序(如果出于某种原因决定用另一种语言重新实现该接口,则该接口不应更改),因此,您不应期望该用户甚至知道python-特定的环境。强制用户指定字符编码的UI不好;如有必要,将字符编码嵌入报告格式。注意:一般情况下,硬编码编码不能是“明智的默认选择”。
jfs 2015年

13
这是糟糕而令人困惑的建议。人们使用str的原因是因为对象还不是字符串,所以没有.encode()方法可以调用。
塞林2016年

433

这是经典的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


85
个人说明:尝试键入“ .encode”时,请不要意外键入“ .unicode”,然后请问为什么没有任何效果。
跳过霍夫曼

9
好建议。但是,当您使用str(x)打印可能是或不是字符串的对象时,您会怎么做呢?如果x是数字,日期时间,布尔值或普通字符串,则str(x)有效。突然,如果它是一个unicode,它将停止工作。是否有办法获得相同的行为,还是我们现在需要添加IF检查来测试对象是否为字符串,以使用.encode?否则返回str()?
Dirk R

同样的问题可能会None有价值。
Vadorequest '18

210

我发现可以通过优雅的方法删除符号并继续按以下方式将字符串保留为字符串:

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

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

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

17
你让我今天一整天都感觉很好!对于utf-8,只需执行以下操作:yourstring = yourstring.encode('utf-8', 'ignore').decode('utf-8')
luca76 '17

对我来说这确实有效,但是我的情况不同,我正在保存文件名,并且名称中带有“ /”,并且路径不存在,因此我必须使用.replace(“ /”,“”)并因此保存我的脚本。同时忽略ASCII也适用于'utf-8'情况。
Akash Kandpal '18

1
@ harrypotter0用于正确连接文件路径os.path.join(),当您开始进行跨平台编程时,这是一个很好的习惯。:)
login_not_failed

152

好吧,我尝试了一切,但并没有帮助,在谷歌搜索之后,我发现了以下内容并有所帮助。使用python 2.7。

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

7
不要这样 stackoverflow.com/questions/3828723/…,尽管当您在搜索错误时在结果顶部附近有类似stackoverflow.com/a/31137935/2141635的答案时,我可以理解为什么它似乎是一个好主意。
Padraic Cunningham

21
我尝试了该主题中几乎所有的建议,但实际上没有一个对我有用。最后我尝试了这个。实际上,这是唯一一种既简单又好用的方法。如果有人说“不这样做,然后拿出一个简单的解决方案,否则使用这一个,因为它是一个很好的工作拷贝和过去的解决方案。
理查德德稀土元素

4
如何在python3中完成?很高兴知道。
Kanerva Peter

3
经过如此多的挫败之后,这个工作了。谢谢你
Avraham Zhurba

4
我只想添加一张if sys.version_info.major < 3:
Falken教授的合同,该合同

87

导致甚至打印失败的一个细微问题是环境变量设置错误,例如。此处LC_ALL设置为“ C”。在Debian中,他们不鼓励设置它:Locale上的Debian Wiki

$ 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à

遇到了完全相同的问题,很糟糕,我在报告之前没有对其进行检查。非常感谢。顺便说一句,您可以用替换前两个命令env|grep -E '(LC|LANG)'
德米特里·维霍图洛夫

对于错误的编码问题,只有我的两分钱。我经常mc在“ subshel​​l模式”(Ctrl-O)中使用,而且我也忘记了在bash中添加了以下别名:alias mc="LANG=en_EN.UTF-8 mc"。因此,当我尝试运行ru_RU.UTF-8内部依赖于脚本的糟糕脚本时,它们就会死掉。在我发现真正的问题之前,从该线程中尝试了很多东西。:)
login_not_failed '18

你真棒。在GSUTIL中,正是由于这个问题,我的rsync失败了。修复了LC_ALL,一切都可以像红酒一样工作。<3谢谢<3
dsignr '19

27

对我来说,有效的是:

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

希望这对某人有帮助。


25

实际上,我发现在大多数情况下,仅去除那些字符会更加简单:

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

26
“完全”通常不是它所执行的。它丢弃了您应该弄清楚如何正确处理的东西。
2014年

7
仅仅去除“那些”(非英语)字符不是解决方案,因为python必须支持所有语言,您认为吗?
alemol 2015年

8
不赞成投票。这根本不是正确的解决方案。了解如何使用Unicode:joelonsoftware.com/articles/Unicode.html
Andrew Ferrier,

4
看,呈现此特定答案的最明智的方式是这样的:认识到ascii赋予了某些语言和用户一定的特权-这是逃生舱口,可能会被那些利用粗略的第一步通过的用户所利用,脚本一起执行潜在的工作,以实现完整的Unicode支持。
哈哈

5
如果我正在编写只需要在内部公司应用程序中将英文文本输出到stdout的脚本,那我只是想解决问题。无论如何。
kagronick '17

25

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

您可以尝试安装language-pack-en软件包来解决此问题:

sudo apt-get install language-pack-en

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

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

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

例如:

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_CTYPEin shell的值。

  • 通过以下方法检查您的shell支持的语言环境:

    locale -a | grep "UTF-8"

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

  1. 初始化和配置VM(例如使用vagrant):

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh

    请参阅:可用的Ubuntu盒

  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");'
    

1
什么已经language-pack-en得到了与Python或这个问题呢?AFAIK,它可以为消息提供语言翻译,但与编码无关
Alastair McCormack

2
在某些Linux发行版中,需要确保正确设置了默认的英语语言环境,尤其是在终端上运行Python脚本时。它对我有用。请参阅:字符编码
kenorb

喔好吧。您的意思是是否要使用非英语语言环境?我猜用户/etc/locale.gen在使用之前还必须进行编辑以确保其语言环境已构建?
Alastair McCormack

1
@AlastairMcCormack注释掉LANG/etc/default/locale(如/etc/locale.gen开不存在),然后跑掉locale-gen,但它并没有帮助。我不确定究竟能做什么language-pack-en,因为我找不到太多的文档,列出其中的内容也无济于事。
kenorb 2015年

1
台式机系统上不太可能已经没有utf-8语言环境,即,您可能不需要安装任何东西,只需配置LANG/ LC_CTYPE/ LC_ALL(例如LANG=C.UTF-8)即可。
jfs

19

在外壳中:

  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中测试过。


是的,这是最好的简短答案,我们无法修改源代码以使用.encode
Luat Nguyen-Neo.Mxn0

16

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

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

那就是python源代码编码的定义。PEP 263中的更多信息。


2
从外部文件加载的处理后的文本包含utf-8编码时,这不能解决问题。这仅对使用给定python脚本本身编写的文字有所帮助,只是python解释器的线索,但对文本处理没有影响。
Mikaelblomkvistsson

16

这是其他一些所谓的“警惕”答案的重新表述。在某些情况下,尽管有人在这里提出抗议,但简单地扔掉麻烦的字符/字符串是一个很好的解决方案。

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)。我尚未对此进行测试,但是我会在某个时候修改答案。


8

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

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

6

这里可以找到简单的帮助程序功能。

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')

要获取转义的字节字符串(使用ascii编码将任意Unicode字符串转换为字节),可以使用backslashreplace错误处理程序:u'\xa0'.encode('ascii', 'backslashreplace')。尽管您应该避免这种表示形式,而是将环境配置为接受非ASCII字符-现在是2016年!
jfs

新年快乐@JFSebastian。我只是对Python-Unicode问题感到沮丧,然后终于得到了有效的解决方案。我对此一无所知。无论如何,感谢小费。
Parag Tyagi -morpheus-



3

我只使用了以下内容:

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

查看有关它的文档说明:

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

Unicode标准基于规范对等和兼容性对等的定义,定义了Unicode字符串的各种规范化形式。在Unicode中,可以用各种方式表示几个字符。例如,字符U + 00C7(带有CEDILLA的拉丁文大写字母C)也可以表示为序列U + 0043(拉丁文的大写字母C)U + 0327(合并CEDILLA)。

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

除了这两种形式,还有基于兼容性对等的两种其他常规形式。在Unicode中,支持某些字符,这些字符通常会与其他字符统一。例如,U + 2160(罗马数字ONE)与U + 0049(拉丁大写字母I)实际上是同一回事。但是,Unicode支持它与现有字符集(例如gb2312)兼容。

普通形式的KD(NFKD)将应用兼容性分解,即用所有等效字符替换它们的等效字符。范式KC(NFKC)首先应用兼容性分解,然后进行规范组合。

即使将两个unicode字符串归一化并在人类读者看来是相同的,但是如果一个字符串包含组合字符而另一个字符串没有组合,则它们可能不相等。

为我解决。简单容易。


3

下面的解决方案为我工作,刚刚添加

u“字符串”

(将字符串表示为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)

3

this这至少在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'))

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


2

我只是遇到了这个问题,而Google带领我来到这里,因此,为了在这里添加一般的解决方案,这对我有用:

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

阅读内德的演讲后,我有了这个主意。

不过,我并没有声称完全理解为什么这样做。因此,如果任何人都可以编辑此答案或发表评论以进行解释,我将不胜感激。


3
什么是type价值?之前和之后?我认为这样做的原因是通过执行unic += valueunic = unic + value添加字符串和unicode相同的操作,其中python然后为结果假设unicode,unic即更精确的类型(考虑一下何时做a = float(1) + int(1)a变为float),然后value = unic指向碰巧是unicode value的新unic对象。
Tom Myddeltyn '16

2

manage.py migrate在带有本地化夹具的Django中运行时,我们遇到了此错误。

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

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

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


1

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

但是,我认为有一个微妙但重要的方面已被很大程度上忽略,这对于像我这样在尝试理解Python编码时最终落到这里的每个人都非常重要:Python 2 vs Python 3字符表示的管理截然不同。我觉得很多困惑与人们在不了解版本的情况下阅读Python编码有关。

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


是的,我的错误是在python 2.7上,'a'.format(u'ñ'),正确的解决方案是不使用.encode('utf-8')而是始终使用unicode字符串,(python 3中的默认值) ):u'a'.format(u'ñ'),
Rogelio

1

尽量避免将变量转换为str(variable)。有时,这可能会导致问题。

避免的简单提示:

try: 
    data=str(data)
except:
    data = data #Don't convert to String

上面的示例还将解决Encode错误。


这不起作用,因为您只会在以下情况中遇到错误:
Aurele Collinet,



0

我遇到了尝试将Unicode字符输出到stdout,但使用sys.stdout.write而不是print的问题(这样我也可以支持将输出输出到其他文件)。

从BeautifulSoup自己的文档中,我使用编解码器库解决了此问题:

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

当使用Apache部署django项目时,经常会发生此问题。因为Apache在/ etc / sysconfig / httpd中设置环境变量LANG = C。只需打开文件并注释(或更改为您的样式)此设置即可。或使用WSGIDaemonProcess命令的lang选项,在这种情况下,您将能够为不同的虚拟主机设置不同的LANG环境变量。


0

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

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

这给我留下了不会抛出错误的东西。


0

这将起作用:

 >>>print(unicodedata.normalize('NFD', re.sub("[\(\[].*?[\)\]]", "", "bats\xc3\xa0")).encode('ascii', 'ignore'))

输出:

>>>bats
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.