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

新手上路,请多包涵

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

原文由 themirror 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 360
2 个回答

2018 年更新:

截至 2018 年 2 月,使用像 gzip 这样的压缩已经变得 非常流行(大约 73% 的网站使用它,包括谷歌、YouTube、雅虎、维基百科、Reddit、Stack Overflow 和 Stack Exchange Network 网站等大型网站).

如果您像原始答案一样使用压缩响应进行简单解码,您将收到类似或类似的错误:

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() 的参数。

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

原文由 Vin-G 发布,翻译遵循 CC BY-SA 4.0 许可协议

>>> 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

原文由 Ignacio Vazquez-Abrams 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题