在 Python 中将 Unicode 转换为 ASCII 且无错误

2025-02-12 10:04:00
admin
原创
53
摘要:问题描述:我的代码只是抓取网页,然后将其转换为 Unicode。html = urllib.urlopen(link).read() html.encode("utf8","ignore") self.response.out.write(html) 但我得到了Unic...

问题描述:

我的代码只是抓取网页,然后将其转换为 Unicode。

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)

但我得到了UnicodeDecodeError


Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/greg/clounce/main.py", line 55, in get
    html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

我猜想这意味着 HTML 包含了一些错误的 Unicode 格式。我是否可以删除导致问题的代码字节,而不是收到错误?


解决方案 1:

>>> u'aあä'.encode('ascii', 'ignore')
'a'

meta使用响应中或标头中相应标签中的字符集解码您收到的字符串Content-Type,然后进行编码。

该方法encode(encoding, errors)接受自定义错误处理程序。除此以外,默认值为ignore

>>> u'aあä'.encode('ascii', 'replace')
b'a??'
>>> u'aあä'.encode('ascii', 'xmlcharrefreplace')
b'aあä'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\/u3042\ä'

请参阅https://docs.python.org/3/library/stdtypes.html#str.encode

解决方案 2:

作为 Ignacio Vazquez-Abrams 答案的扩展

>>> u'aあä'.encode('ascii', 'ignore')
'a'

有时需要删除字符中的重音符号并打印基本形式。这可以通过以下方式实现

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore')
'aa'

您可能还希望将其他字符(例如标点符号)转换为最接近的字符,例如,右单引号 Unicode 字符在编码时不会转换为 ascii 撇号。

>>> print u'/u2019'
’
>>> unicodedata.name(u'/u2019')
'RIGHT SINGLE QUOTATION MARK'
>>> u'/u2019'.encode('ascii', 'ignore')
''
# Note we get an empty string back
>>> u'/u2019'.replace(u'/u2019', u'\'').encode('ascii', 'ignore')
"'"

尽管有更有效的方法来实现这一点。有关更多详细信息,请参阅此问题Python 的“此 Unicode 的最佳 ASCII”数据库在哪里?

解决方案 3:

使用unidecode - 它甚至可以立即将奇怪的字符转换为 ascii,甚至将中文转换为语音 ascii。

$ pip install unidecode

然后:

>>> from unidecode import unidecode
>>> unidecode(u'北京')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'

解决方案 4:

2018 年更新:

截至 2018 年 2 月,使用类似压缩gzip已经变得非常流行(大约 73% 的网站使用它,包括 Google、YouTube、Yahoo、Wikipedia、Reddit、Stack Overflow 和 Stack Exchange Network 等大型网站)。

如果您像原始答案中那样对经过 gzip 压缩的响应进行简单解码,则会收到类似以下错误:

UnicodeDecodeError:'utf8'编解码器无法解码位置 1 中的字节 0x8b:意外的代码字节

为了解码 gzpipped 响应,您需要添加以下模块(在 Python 3 中):

import gzip
import io

注意: 在 Python 2 中,你应该StringIO使用io

然后你就可以像这样解析内容:

response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource

此代码读取响应,并将字节放入缓冲区。gzip然后模块使用该函数读取缓冲区GZipFile。之后,可以将 gzip 文件再次读入字节,并最终解码为正常可读的文本。

2010 年的原始答案:

我们能得到实际使用的值吗link

此外,当我们尝试.encode()已编码的字节字符串时,我们通常会遇到此问题。因此,您可以先尝试对其进行解码,如下所示

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")

举个例子:

html = 'xa0'
encoded_str = html.encode("utf8")

失败

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)

尽管:

html = 'xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")

成功且无错误。请注意,“windows-1252”是我用作示例的。我从chardet获得此信息,并且有 0.5 的置信度认为它是正确的!(好吧,给定一个 1 个字符长度的字符串,您期望什么呢)您应该将其更改为从返回的字节字符串的编码,以.urlopen().read()适用于您检索的内容。

我发现的另一个问题是,.encode()string 方法返回的是修改后的字符串,而不是修改源代码。因此,这样做毫无用处,self.response.out.write(html)因为 html 不是来自 html.encode 的编码字符串(如果这是您最初想要的)。

正如 Ignacio 所建议的,检查源网页以了解从 返回的字符串的实际编码read()。它要么在 Meta 标签之一中,要么在响应中的 ContentType 标头中。然后将其用作 的参数.decode()

但请注意,不应假设其他开发人员有足够的责任确保标头和/或元字符集声明与实际内容相匹配。(这很麻烦,是的,我应该知道,我以前就是其中之一)。

解决方案 5:

我在所有项目中都使用此辅助函数。如果它无法转换 unicode,它会忽略它。这与 django 库有关,但只要稍加研究,您就可以绕过它。

from django.utils import encoding

def convert_unicode_to_string(x):
    """
    >>> convert_unicode_to_string(u'nixf1era')
    'niera'
    """
    return encoding.smart_str(x, encoding='ascii', errors='ignore')

使用这个之后我不再收到任何unicode错误。

解决方案 6:

对于损坏的控制台(例如cmd.exeHTML 输出),您可以随时使用:

my_unicode_string.encode('ascii','xmlcharrefreplace')

这将保留所有非 ASCII 字符,同时使它们可以在纯 ASCIIHTML 中打印。

警告如果您在生产代码中使用它来避免错误,则很可能您的代码中存在错误。唯一有效的用例是打印到非unicode控制台或在HTML上下文中轻松转换为HTML实体。

最后,如果您在 Windows 上使用 cmd.exe,则可以键入chcp 65001以启用 utf-8 输出(适用于 Lucida Console 字体)。您可能需要添加myUnicodeString.encode('utf8')

解决方案 7:

你写道“我认为这意味着 HTML 在某些地方包含一些错误格式的 unicode 尝试。”

HTML 不应包含任何类型的“unicode 尝试”,无论格式是否正确。它必须包含以某种编码方式编码的 Unicode 字符,这些编码通常会预先提供...查找“charset”。

您似乎假设字符集是 UTF-8 ... 依据是什么?错误消息中显示的“ ”字节表示您可能有一个单字节字符集,例如 cp1252。

如果您无法理解 HTML 开头的声明,请尝试使用chardet来找出可能的编码。

为什么你用“正则表达式”标记你的问题?

将整个问题替换为非问题后进行更新:

html = urllib.urlopen(link).read()
# html refers to a str object. To get unicode, you need to find out
# how it is encoded, and decode it.

html.encode("utf8","ignore")
# problem 1: will fail because html is a str object;
# encode works on unicode objects so Python tries to decode it using 
# 'ascii' and fails
# problem 2: even if it worked, the result will be ignored; it doesn't 
# update html in situ, it returns a function result.
# problem 3: "ignore" with UTF-n: any valid unicode object 
# should be encodable in UTF-n; error implies end of the world,
# don't try to ignore it. Don't just whack in "ignore" willy-nilly,
# put it in only with a comment explaining your very cogent reasons for doing so.
# "ignore" with most other encodings: error implies that you are mistaken
# in your choice of encoding -- same advice as for UTF-n :-)
# "ignore" with decode latin1 aka iso-8859-1: error implies end of the world.
# Irrespective of error or not, you are probably mistaken
# (needing e.g. cp1252 or even cp850 instead) ;-)

解决方案 8:

如果您有一个字符串line,则可以使用.encode([encoding], [errors='strict'])字符串的方法来转换编码类型。

line = 'my big string'

line.encode('ascii', 'ignore')

有关在 Python 中处理 ASCII 和 unicode 的更多信息,这是一个非常有用的网站:https ://docs.python.org/2/howto/unicode.html

解决方案 9:

我认为答案是存在的,但只是零散的,这使得很难快速解决问题,例如

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

让我们举一个例子,假设我有一个文件,其中包含以下形式的一些数据(包含 ascii 和非 ascii 字符)

1/10/17, 21:36 - 土地:欢迎 ��

我们只想忽略并保留 ascii 字符。

此代码将执行以下任务:

import unicodedata
fp  = open(<FILENAME>)
for line in fp:
    rline = line.strip()
    rline = unicode(rline, "utf-8")
    rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore')
    if len(rline) != 0:
        print rline

并且 type(rline) 会给你

>type(rline) 
<type 'str'>

解决方案 10:

您可以使用下面这段代码作为示例,避免 Unicode 到 ASCII 的错误:

from anyascii import anyascii

content = "Base Rent for – CC# 2100 Acct# 8410: $41,667.00 – PO – Lines - for Feb to Dec to receive monthly"
content = anyascii(content)
print(content)

解决方案 11:

unicodestring = 'xa0'

decoded_str = unicodestring.decode("windows-1252")
encoded_str = decoded_str.encode('ascii', 'ignore')

对我有用

解决方案 12:

看起来你正在使用 python 2.x。Python 2.x 默认为 ascii,它不了解 Unicode。因此是例外。

只需在 shebang 后粘贴以下行即可

# -*- coding: utf-8 -*-
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用