在Python中将Unicode转换为ASCII而不出错

2024-04-25 23:49:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我的代码只是擦掉一个网页,然后将其转换为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错误的尝试。我可以删除导致问题的任何代码字节,而不是出现错误吗?


Tags: 代码inpyhtmlgooglecontentsunicodeutf8
3条回答

2018年更新:

截至2018年2月,使用压缩(如gzip)已成为quite popular(约73%的网站使用压缩,包括大型网站,如Google、YouTube、Yahoo、Wikipedia、Reddit、Stack Overflow和Stack Exchange Network sites)。
如果使用gzip响应执行原始答案中的类似简单解码,则会出现类似或类似的错误:

UnicodeDecodeError: 'utf8' codec can't decode byte 0x8b in position 1: unexpected code byte

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

import gzip
import io

注意:In Python 2 you'd use ^{} instead of ^{}

然后您可以这样解析内容:

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()的返回字符串的实际编码。它要么在一个元标记中,要么在响应的ContentType头中。然后将其用作.decode()的参数。

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

作为伊格纳西奥·巴斯克斯·艾布拉姆斯回答的延伸

>>> 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')
"'"

尽管有更有效的方法来实现这一点。有关详细信息,请参见此问题Where is Python's "best ASCII for this Unicode" database?

>>> 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&#12354;&#228;'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\\u3042\\xe4'

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

相关问题 更多 >

    热门问题