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

时间:2012-03-30 12:06:41

标签: 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()

以下是运行上述代码段时在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)

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

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

34 个答案:

答案 0 :(得分:1226)

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

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

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

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

或完全使用unicode。

答案 1 :(得分:407)

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

答案 2 :(得分:194)

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

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

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

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

答案 3 :(得分:136)

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

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

答案 4 :(得分: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à

答案 5 :(得分:25)

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

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

答案 6 :(得分:25)

对我来说,有效的是:

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

希望这有助于某人。

答案 7 :(得分:20)

尝试一下可能会解决

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

答案 8 :(得分:18)

问题是您正在尝试打印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中的价值。

  • 检查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");'
    ™
    

答案 9 :(得分:16)

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

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

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

答案 10 :(得分: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)。我还没有测试过,但我会在某个时候修改答案。

答案 11 :(得分:10)

在外壳中:

  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中进行了测试。

答案 12 :(得分:7)

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

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

答案 13 :(得分: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')

答案 14 :(得分:4)

只需添加到变量编码(&#39; utf-8&#39;)

agent_contact.encode('utf-8')

答案 15 :(得分:3)

我刚刚使用了以下内容:

static const unsigned long two_n[32] = {
    1UL <<  0, 1UL <<  1, 1UL <<  2, 1UL <<  3,
    1UL <<  4, 1UL <<  5, 1UL <<  6, 1UL <<  7,
    1UL <<  8, 1UL <<  9, 1UL << 10, 1UL << 11,
    1UL << 12, 1UL << 13, 1UL << 14, 1UL << 15,
    1UL << 16, 1UL << 17, 1UL << 18, 1UL << 19,
    1UL << 20, 1UL << 21, 1UL << 22, 1UL << 23,
    1UL << 24, 1UL << 25, 1UL << 26, 1UL << 27,
    1UL << 28, 1UL << 29, 1UL << 30, 1UL << 31
};

查看有关它的文档:

  

unicodedata.normalize(form,unistr)返回正常的表单形式   Unicode字符串unistr。表单的有效值为'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(ROMAN NUMERAL ONE)与U + 0049完全相同   (拉丁文大写字母I)。但是,Unicode支持它   与现有字符集的兼容性(例如gb2312)。

     

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

     

即使两个unicode字符串被规范化并且看起来与a相同   人类读者,如果一个人结合了角色而另一个没有,   他们可能无法比较平等。

为我解决它。简单易行。

答案 16 :(得分:3)

以下解决方案适用于我,刚刚添加了

  

u“String”

在我的字符串之前

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

答案 17 :(得分:2)

请打开终端并执行以下命令:

export LC_ALL="en_US.UTF-8"

答案 18 :(得分:2)

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

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

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

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

答案 19 :(得分:1)

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

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

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

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

答案 20 :(得分:1)

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

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

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

答案 21 :(得分:1)

通常将此不支持的编码 字符串(例如data_that_causes_this_error)写入某个文件(例如results.txt),这是可行的

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

答案 22 :(得分:0)

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

unic = u''
packet_data = unic

答案 23 :(得分: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

答案 24 :(得分:0)

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

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

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

答案 25 :(得分: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)

答案 26 :(得分:0)

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

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

答案 27 :(得分:0)

这有助于python 2.7

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

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

答案 28 :(得分:0)

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

避免的简单提示:

try: 
    data=str(data)
except:
    data = str(data)

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

答案 29 :(得分:0)

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

答案 30 :(得分:0)

这将起作用:

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

输出:

>>>bats

答案 31 :(得分:0)

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

import sys
import io

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

答案 32 :(得分:0)

您可以在运行脚本之前将字符编码设置为 UTF-8

export LC_CTYPE="en_US.UTF-8"

这通常应该可以解决问题。

答案 33 :(得分:0)

它对我有用:

export LC_CTYPE="en_US.UTF-8"