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)

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

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

答案

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

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

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

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

或完全以 unicode 工作。

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

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

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

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

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

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

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

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

对我来说,有效的是:

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

希望这对某人有帮助。

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

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

问题是您正在尝试打印 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
  • Shell 中LANG / LC_CTYPE值。

  • 通过以下方法检查您的 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");'
    ™

试试这个可能解决,

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

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

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

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