ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

如果您是作为用户而不是作为开发者遇到这些错误,请检查 serverfault.com/questions/54591/…askubuntu.com/questions/599808/…
我将添加这一点,不要将 onlinegdb.com/online_python_interpreter 用于这些东西。正在使用该解释器来试用一些东西,但它没有为 Unicode 正确配置!总是以 'B'\nnn'' 格式打印...而我想要的只是一个 guillemet!在虚拟机上尝试过,它使用 chr() 立即按预期工作
试试这个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 我运行了您的代码段 NameError: name 'myText' is not defined
在执行脚本之前尝试在 shell 中设置 PYTHONIOENCODING$ export PYTHONIOENCODING=utf8

a
agf

您需要阅读 Python Unicode HOWTO。此错误是 very first example

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

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

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

或完全使用 unicode。


同意!我被教导的一个好的经验法则是使用“unicode 三明治”的想法。您的脚本接受来自外部世界的字节,但所有处理都应以 unicode 完成。只有当你准备好输出你的数据时,它才应该被压缩成字节!
万一其他人对此感到困惑,我发现了一件奇怪的事情:我的终端使用 utf-8,而当我 print 我的 utf-8 字符串时,它工作得很好。但是,当我将程序输出通过管道传输到文件时,它会抛出 UnicodeEncodeError。事实上,当输出被重定向(到文件或管道)时,我发现 sys.stdout.encodingNone!加入 .encode('utf-8') 解决了这个问题。
@drevicko:使用 PYTHONIOENCODING=utf-8 代替,即打印 Unicode 字符串并让环境设置预期的编码。
@steinar:在任何情况下都没有什么是有效的。一般来说,用户不应该关心您使用 Python 来实现您的实用程序(如果您出于某种原因决定用另一种语言重新实现接口,则接口不应更改),因此您不应该期望用户甚至知道 python-特定的环境变量。强制用户指定字符编码是糟糕的 UI;如有必要,在报告格式中嵌入字符编码。注意:在一般情况下,没有硬编码编码可以是“合理的默认值”。
这是一个糟糕且令人困惑的建议。人们使用 str 的原因是因为对象还不是字符串,所以没有 .encode() 方法可以调用。
A
Andbdrew

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

哦,dip,这对任何人都没有好处!要修复错误,请使用 .encode 显式编码字节并告诉 python 使用什么编解码器:

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

瞧\u00E0!

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

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


个人注意:当尝试输入“.encode”时,不要意外输入“.unicode”,然后想知道为什么没有任何效果。
好建议。但是,当您使用 str(x) 打印可能是或可能不是字符串的对象时,您会怎么做?如果 x 是数字、日期时间、布尔值或普通字符串,则 str(x) 有效。突然,如果它是一个 unicode,它就会停止工作。有没有办法获得相同的行为,或者我们现在是否需要添加一个 IF 检查来测试对象是否是要使用 .encode 的字符串,否则是 str()?
可以使用 None 值提出相同的问题。
你因为使用“Voil\u00E0!”而获得了我的投票。杰出的!
E
Edeson Bizerril

我找到了优雅的解决方法来删除符号并继续将字符串保留为字符串,如下所示:

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

请务必注意,使用忽略选项很危险,因为它会默默地从使用它的代码中删除任何 unicode(和国际化)支持,如下所示(convert unicode):

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

你让我今天一整天都感觉很好!对于 utf-8,这样做就足够了:yourstring = yourstring.encode('utf-8', 'ignore').decode('utf-8')
对我来说这确实有效,但我的情况不同,我正在保存文件名并且名称中有“/”并且路径不存在所以我必须使用 .replace("/","") 并因此保存我的脚本。同时忽略 ascii 也适用于 'utf-8' 案例。
@harrypotter0 用于连接文件路径正确使用 os.path.join(),当您开始进行跨平台编程时,这是一个非常好的习惯。 :)
A
Ashwin

好吧,我尝试了所有方法,但没有帮助,在谷歌搜索后我发现了以下内容并且它有所帮助。 python 2.7 正在使用中。

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

不要这样做。 stackoverflow.com/questions/3828723/…,尽管当您在搜索错误时在结果顶部附近有类似 stackoverflow.com/a/31137935/2141635 的答案时,我可以明白为什么这看起来是个好主意。
我尝试了该主题中的几乎所有建议,但实际上没有一个对我有用。最后我尝试了这个。它真的是唯一一个简单又好用的方法。如果有人说“不要这样做,请提供一个简单的解决方案。否则使用这个。因为它是一个很好的工作副本和过去的解决方案。
这怎么能在 python3 中完成?很高兴知道。
不要这样做!如果你这样做,你就可以避免大量关于 Python2 和 unicode 的神秘知识!惊恐的事件!
我只需添加一个 if sys.version_info.major < 3:
m
maxpolk

甚至导致打印失败的一个微妙问题是您的环境变量设置错误,例如。这里 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à

遇到了完全相同的问题,太糟糕了,我在 reporting 之前没有检查过。非常感谢。顺便说一句,您可以将前两个命令替换为 env|grep -E '(LC|LANG)'
只是我在错误编码问题上的两分钱。我经常在“子shell 模式”(Ctrl-O) 中使用 mc,但我也忘记了我在 bash 中添加了以下别名:alias mc="LANG=en_EN.UTF-8 mc"。因此,当我尝试运行内部依赖于 ru_RU.UTF-8 的编写不佳的脚本时,它们就会死掉。在我发现真正的问题之前,从这个线程中尝试了很多东西。 :)
你太棒了。在 GSUTIL 中,正是由于这个问题,我的 rsync 失败了。修复了 LC_ALL,一切都像葡萄酒一样正常工作。 <3谢谢你<3
k
kenorb

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

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

sudo apt-get install language-pack-en

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

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

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

例如:

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

shell 中 LANG/LC_CTYPE 的值。

通过以下方式检查您的 shell 支持的语言环境: locale -a | grep "UTF-8"

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

初始化和配置虚拟机(例如使用 vagrant): vagrant init ubuntu/trusty64;流浪起来; vagrant ssh 请参阅:可用的 Ubuntu 框。打印 unicode 字符(例如商标符号 like ™):$ python -c 'print(u"\u2122");'回溯(最后一次调用):文件“”,第 1 行,在 UnicodeEncodeError:'ascii' 编解码器无法在位置 0 编码字符 u'\u2122':序数不在范围内(128)现在安装 language-pack-en: $ sudo apt-get -y install language-pack-en 将安装以下额外的包: language-pack-en-base 生成语言环境... en_GB.UTF-8... /usr /sbin/locale-gen: done 生成完成。现在问题应该解决了: $ python -c 'print(u"\u2122");' ™ 否则,请尝试以下命令: $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");' ™


language-pack-en 与 Python 或这个问题有什么关系? AFAIK,它可以为消息提供语言翻译,但与编码无关
在某些 Linux 发行版上,需要它来确保正确设置默认的英语语言环境,尤其是在终端上运行 Python 脚本时。它曾一度对我有用。请参阅:character encoding
喔好吧。你的意思是如果你想使用非英语语言环境?我猜用户还必须编辑 /etc/locale.gen 以确保在使用之前构建他们的语言环境?
@AlastairMcCormack 从 /etc/default/locale 中注释掉 LANG(因为 /etc/locale.gen 不存在)并运行 locale-gen,但它没有帮助。我不确定 language-pack-en 究竟做了什么,因为我没有找到太多文档,列出它的内容也没有多大帮助。
桌面系统上不太可能没有 utf-8 语言环境,即,您可能不需要安装任何东西,只需配置 LANG/ LC_CTYPE/ LC_ALL (例如,{4 })。
k
kenorb

在外壳中:

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

以上在 Ubuntu 中测试。


是的,这是最好的简短答案,我们不能修改源代码以使用 .encode
我在 python3 中使用了它,并且在设置 LC_ALL 后它现在可以正常工作了。谢谢
P
Phil LaNasa

实际上,我发现在大多数情况下,仅删除这些字符要简单得多:

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

“完美”通常不是它的表现。它扔掉了你应该弄清楚如何正确处理的东西。
只是去掉“那些”(非英语)字符不是解决方案,因为 python 必须支持所有语言,你不觉得吗?
否决。这根本不是正确的解决方案。了解如何使用 Unicode:joelonsoftware.com/articles/Unicode.html
看,呈现这个特定答案的最明智的方式是这样:认识到 ascii 赋予某些语言和用户一定的特权 - 这是可能被那些可能正在粗略破解的用户利用的逃生舱口,第一次通过, 在实现完全 unicode 支持之前,可能会一起编写脚本以进行初步工作。
如果我正在编写一个只需要在内部公司应用程序中将英文文本打印到标准输出的脚本,我只想让问题消失。什么都行。
A
Animesh

对我来说,有效的是:

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

希望这可以帮助某人。


B
BuvinJ

这是对其他一些所谓的“逃避”答案的重新散列。尽管这里表达了抗议,但在某些情况下,简单地丢弃麻烦的字符/字符串是一个很好的解决方案。

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

更新:我的原始答案是为 Python 2 编写的。对于 Python 3:

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

注意:如果您希望在“不安全”Unicode 字符所在的位置留下一个 ? 指示符,请在调用中指定 replace 而不是 ignore 以对错误处理程序进行编码。

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

最后,这是一个使用 six 的更强大的 PY2/3 版本,我选择使用 replace,并加入了一些字符交换,以用简单的垂直引号替换花哨的 unicode 引号和撇号,它们向左或向右卷曲。的 ascii 集。您可以自己扩展此类交换:

from six import PY2, iteritems 

CHAR_SWAP = { u'\u201c': u'"'
            , u'\u201D': u'"' 
            , u'\u2018': u"'" 
            , u'\u2019': u"'" 
}

def toAscii( text ) :    
    try:
        for k,v in iteritems( CHAR_SWAP ): 
            text = text.replace(k,v)
    except: pass     
    try: return str( text ) if PY2 else bytes( text, 'replace' ).decode('ascii')
    except UnicodeEncodeError:
        return text.encode('ascii', 'replace').decode('ascii')
    except: return ""

if __name__ == '__main__':     
    print( toAscii( u'testin\u2019' ) )

A
Andriy Ivaneyko

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

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

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


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

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

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

非常感谢!我不明白为什么它适用于其他脚本而不是这个脚本。答案是来自未来的失踪;)
h
hhh

唉,这至少在 Python 3 中有效......

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

其中错误在编码中被忽略。


S
Simas Joneliunas

这个对我有用:

export LC_CTYPE="en_US.UTF-8"

P
Parag Tyagi

找到了简单的辅助函数 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')

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

只需添加到变量 encode('utf-8')

agent_contact.encode('utf-8')

N
Ngoc-Vuong Ho

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

export LC_ALL="en_US.UTF-8"

D
Drag0

我刚刚使用了以下内容:

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

检查有关它的文档说明:

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

为我解决。简单易行。


P
Pedro Lobito

迟到的答案,但此错误与您的终端编码不支持某些字符有关。
我在 python3 上使用以下方法修复了它:

import sys
import io

sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')
print("é, à, ...")

A
Aravind Krishnakumar

下面的解决方案对我有用,刚刚添加

“字符串”

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

P
Pe Dro

在一般情况下,将此不支持的编码 字符串(比如说data_that_causes_this_error)写入某个文件(例如results.txt),这是可行的

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

D
Dreams

如果它是打印语句的问题,很多时候它只是终端打印的问题。这对我有帮助:export PYTHONIOENCODING=UTF-8


p
pepoluan

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

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

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

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


type 的价值是多少?在此之前和之后?我认为这行得通的原因是,通过执行与 unic = unic + value 相同的 unic += value,您正在添加一个字符串和一个 unicode,然后 python 假定结果 unic 的 unicode 即更精确的类型(想想何时您这样做 a = float(1) + int(1)a 变为浮点数)然后 value = unicvalue 指向恰好是 unicode 的新 unic 对象。
f
followben

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

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

问题只是 Django 容器(我们使用 docker)缺少 LANG 环境变量。

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


Z
ZF007

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


G
Gulzar

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

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

这给我留下了一些不会引发错误的东西。


S
Simón Ramírez Amaya

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

但是,我认为有一个微妙但重要的方面在很大程度上被忽略了,这对于像我一样最终来到这里并试图理解 Python 中的编码的每个人来说都非常重要:Python 2 与 Python 3 字符表示管理完全不同.我觉得那里的一大块混乱与人们阅读 Python 中的编码而不了解版本有关。

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


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

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

避免的简单提示:

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

上面的例子也将解决编码错误。


这不起作用,因为您只会在 except 中遇到错误
h
halfer

如果您有类似 packet_data = "This is data" 的内容,则在初始化 packet_data 之后的下一行执行此操作:

unic = u''
packet_data = unic

p
palswim

我在尝试将 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)