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

Hom*_*lli 1222 python unicode beautifulsoup python-2.x python-unicode

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

以下是运行上述代码段时在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)
Run Code Online (Sandbox Code Playgroud)

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

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

agf*_*agf 1298

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

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

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

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()
Run Code Online (Sandbox Code Playgroud)

或者完全以unicode工作.

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

And*_*rew 424

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

a = u'bats\u00E0'
print a
 => batsà
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都很好,但如果我们调用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)
Run Code Online (Sandbox Code Playgroud)

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

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà
Run Code Online (Sandbox Code Playgroud)

Voil\u00E0!

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

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

  • 个人注意:当尝试键入".encode"时,不要意外键入".unicode",然后想知道为什么没有任何效果. (82认同)
  • 好建议.但是当你使用str(x)来打印可能是也可能不是字符串的对象时,你会做什么呢?如果x是数字,日期时间,布尔值或普通字符串,则str(x)起作用.突然间,如果它是一个unicode它停止工作.有没有办法获得相同的行为或我们现在需要添加IF检查来测试对象是否为使用.encode的字符串,否则为str()? (9认同)

小智 200

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

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')
Run Code Online (Sandbox Code Playgroud)

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

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
Run Code Online (Sandbox Code Playgroud)

  • 你让我今天一整天都感觉很好!对于utf-8,它就足够了:`yourstring = yourstring.encode('utf-8','ignore').decode('utf-8')` (16认同)

Ash*_*win 144

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

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
Run Code Online (Sandbox Code Playgroud)

  • 我尝试了几乎所有这个主题的建议,但实际上没有一个对我有用.最后我尝试了这个.它真的是唯一一个简单而好的工作.如果有人说"不要这样做,那就来一个简单的解决方案.否则使用这个.因为这是一个很好的工作副本和过去的解决方案. (19认同)
  • 不要这样做.http://stackoverflow.com/questions/3828723/why-should-we-not-use-sys-setdefaultencodingutf-8-in-a-py-script,虽然你有这样的答案http://stackoverflow.com/a/31137935/2141635当您搜索错误时,在结果顶部附近我可以看到为什么它看起来像个好主意. (6认同)
  • 怎么能在python3中完成?很高兴知道. (4认同)
  • 我只想添加一个`if sys.version_info.major <3:` (4认同)
  • 经过这么多挫折之后,这个人工作了.谢谢一堆. (3认同)
  • 不要这样做!如果你这样做,你就可以避免*堆*Python2 和 unicode 的晦涩知识!惊恐的事件! (2认同)

max*_*olk 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à
Run Code Online (Sandbox Code Playgroud)


Ani*_*esh 27

对我来说,有用的是:

BeautifulSoup(html_text,from_encoding="utf-8")
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.


Phi*_*asa 24

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

s = mystring.decode('ascii', 'ignore')
Run Code Online (Sandbox Code Playgroud)

  • "完美"通常不是它的表现.它抛弃了你应该弄清楚如何正确处理的东西. (26认同)
  • Downvoted.这根本不是正确的解决方案.了解如何使用Unicode:http://www.joelonsoftware.com/articles/Unicode.html (8认同)
  • 只是剥离"那些"(非英语)字符不是解决方案,因为python必须支持所有语言你不觉得吗? (7认同)
  • 如果我正在编写一个只需要在内部公司应用程序中将英文文本打印到stdout的脚本,我只想让问题消失.无论什么有效. (5认同)
  • 看,呈现这个特定答案的最明智的方式就是这样:认识到ascii赋予某些语言和用户某种特权 - 这就是_escape hatch_,可能被那些可能正在粗略地攻击粗略的用户利用. ,在实现完整的unicode支持之前,可以将脚本编写在一起进行初步工作. (4认同)

ken*_*orb 22

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

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

sudo apt-get install language-pack-en
Run Code Online (Sandbox Code Playgroud)

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

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

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

例如:

open(foo, encoding='utf-8')
Run Code Online (Sandbox Code Playgroud)

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


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

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

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    
    Run Code Online (Sandbox Code Playgroud)

    请参阅:可用的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)
    
    Run Code Online (Sandbox Code Playgroud)
  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.
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在问题应该解决:

    $ python -c 'print(u"\u2122");'
    ™
    
    Run Code Online (Sandbox Code Playgroud)
  5. 否则,请尝试以下命令:

    $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
    ™
    
    Run Code Online (Sandbox Code Playgroud)

  • 在某些Linux发行版中,为了确保正确设置默认的英语语言环境,尤其是在终端上运行Python脚本时,需要这样做.它曾经对我有用.请参阅:[字符编码](http://unix.stackexchange.com/q/3218/21471) (2认同)

Jos*_*udi 21

试试这可能会解决,

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
Run Code Online (Sandbox Code Playgroud)

  • `NameError:未定义名称'reload' (2认同)

And*_*yko 16

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

# -*- coding: utf-8 -*-
Run Code Online (Sandbox Code Playgroud)

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

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

Buv*_*inJ 14

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

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""
Run Code Online (Sandbox Code Playgroud)

测试它:

if __name__ == '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )
Run Code Online (Sandbox Code Playgroud)

结果:

1
test
98°
98
Run Code Online (Sandbox Code Playgroud)

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


ken*_*orb 14

在外壳中:

  1. 通过以下命令查找支持的UTF-8语言环境:

    locale -a | grep "UTF-8"
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在运行脚本之前将其导出,例如:

    export LC_ALL=$(locale -a | grep UTF-8)
    
    Run Code Online (Sandbox Code Playgroud)

    或手动像:

    export LC_ALL=C.UTF-8
    
    Run Code Online (Sandbox Code Playgroud)
  3. 通过打印特殊字符进行测试,例如

    python -c 'print(u"\u2122");'
    
    Run Code Online (Sandbox Code Playgroud)

以上在Ubuntu中测试过。


Cal*_*leb 12

这个对我有用:

export LC_CTYPE="en_US.UTF-8"
Run Code Online (Sandbox Code Playgroud)


Dre*_*ams 10

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


Per*_*ira 8

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

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
Run Code Online (Sandbox Code Playgroud)


小智 7

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

export LC_ALL="en_US.UTF-8"
Run Code Online (Sandbox Code Playgroud)


hhh*_*hhh 7

唉,这至少在 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'))
Run Code Online (Sandbox Code Playgroud)

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


Ped*_*ito 7

较晚回答,但此错误与您的终端编码不支持某些字符有关。
\n我python3使用以下方法修复了它:

\n
import sys\nimport io\n\nsys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='utf8')\nprint("\xc3\xa9, \xc3\xa0, ...")\n
Run Code Online (Sandbox Code Playgroud)\n


Par*_*us- 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')
Run Code Online (Sandbox Code Playgroud)


Dra*_*ag0 6

我刚刚使用了以下内容:

\n\n
import unicodedata\nmessage = unicodedata.normalize("NFKD", message)\n
Run Code Online (Sandbox Code Playgroud)\n\n

检查文档对此有何说明:

\n\n
\n

unicodedata.normalize(form, unistr) 返回 Unicode 字符串 unistr 的范式。表单的有效值为 \xe2\x80\x98NFC\xe2\x80\x99、\xe2\x80\x98NFKC\xe2\x80\x99、\n \xe2\x80\x98NFD\xe2\x80\x99 和 \xe2\ x80\x98NFKD\xe2\x80\x99。

\n\n

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

\n\n

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

\n\n

除了这两种形式之外,还有两种基于兼容性等价性的附加范式。在 Unicode 中,支持某些字符,这些字符通常与其他字符统一。例如,U+2160(罗马数字一)实际上与 U+0049\n(拉丁文大写字母 I)相同。但是,它在 Unicode 中受支持,以便与现有字符集(例如 gb2312)兼容。

\n\n

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

\n\n

即使两个 unicode 字符串已标准化并且对于人类读者来说看起来相同,但如果其中一个具有组合字符而另一个没有 xe2x80x99t,则它们比较起来可能不相等。

\n
\n\n

帮我解决了 简单又容易。

\n


Ara*_*mar 5

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

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)
Run Code Online (Sandbox Code Playgroud)


Kai*_*rov 5

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

agent_contact.encode('utf-8')
Run Code Online (Sandbox Code Playgroud)


Gul*_*zar 5

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

s = s.encode('ascii',errors='ignore')
Run Code Online (Sandbox Code Playgroud)

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


Pe *_*Dro 5

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

f = open("results.txt", "w")
  f.write(data_that_causes_this_error.encode('utf-8'))
  f.close()
Run Code Online (Sandbox Code Playgroud)