在 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)
但我得到了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.exe
HTML 输出),您可以随时使用:
my_unicode_string.encode('ascii','xmlcharrefreplace')
这将保留所有非 ASCII 字符,同时使它们可以在纯 ASCII和HTML 中打印。
警告:如果您在生产代码中使用它来避免错误,则很可能您的代码中存在错误。唯一有效的用例是打印到非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 -*-