python urllib返回两个0xfffd字符而不是预期的unicode字符

时间:2011-09-15 23:02:23

标签: python unicode

我正在抓一些网站,编码是unicode:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

要做到这一点,我使用urllib:

html = unicode(urllib.openurl(url).read(), 'utf-8')

有时一些unicode字符将被随机替换为两个0xFFFD字符。我想用4个字节编码的单个字符会被破坏,并且对于两个2字节的一半被替换为两个0xFFFD。这种替换的可能性非常低 - 可能会替换500 000中的一个角色。似乎只有非ascii字符被破坏了。

当在浏览器中呈现相同的页面时,我没有观察到任何这些替换。

如何识别哪个部分引入了问题?它是发送损坏字节的服务器还是没有正确读取它们的客户端?

@John Machin:

  1. Python版本为2.7.1
  2. 它可以在所有浏览器以及大多数http客户端(libcurl,wget,python)中观察到
  3. 我实际上在这里错了 - 有时这些错误会出现在呈现页面上的浏览器中。错误看起来像带有问号的两个菱形字符。
  4. 错误是随机的。有时他们出现,有时没有。页面越大,错误出现的可能性就越大。
  5. 所以我认为错误是在Web服务器端引入的。我会试着忽略它们。

3 个答案:

答案 0 :(得分:0)

浏览器为纠正无效字符做了很多魔术。尝试查看.read()返回的原始字节,并检查源页面是否包含无效字符。例如,有时页面会使用latin-1或类似字母编码重音字母,而其他字符则使用utf-8编码。

答案 1 :(得分:0)

我看到两种可能性。

  1. 如果.read()调用最后只返回多字节序列的一部分,则部分序列将被U + FFFD替换。请参阅UTF-8编码的this explanation。可以使用编码的代码点的第一个字节中的前导1位数轻松检测部分字节序列,这样您就可以解码除部分序列之外的所有内容,并在下一次读取时继续。代码点U + 007F和更低版本用一个字节编码,因此这个问题永远不会影响那些代码点。
  2. 也许该文档包含charset=utf-8声明,但实际上并未使用UTF-8编码。然后,任何不恰好是有效的UTF-8序列的字节将由U + FFFD替换。
  3. 如果您发布从服务器获得的一些示例字节序列,对于每个单独的读取操作,以及由这些字节产生的字符串,我们可以更加确定发生了什么。

答案 2 :(得分:0)

服务器和客户端完全有可能忠实地再现早期的填充结果。场景:有人在cp1252(通常的嫌疑人)中编码了文本。他们使用带有“替换”选项的UTF-8对其进行解码 - 引入u“\ ufffd” - 然后对结果进行编码。

示例原始文字:Seine Füße sind wund.

>>> original = "Seine F\xfc\xdfe sind wund." # encoded in cp1252
>>> ucode1 = original.decode('utf8', 'replace')
>>> ucode1
u'Seine F\ufffd\ufffde sind wund.'
>>> input_to_server = ucode1.encode('utf8')
>>> input_to_server
'Seine F\xef\xbf\xbd\xef\xbf\xbde sind wund.'
>>> observed_result = unicode(input_to_server, 'utf8')
>>> observed_result
u'Seine F\ufffd\ufffde sind wund.'
>>>

在任何情况下,如果您不提供更多信息,所有答案都将基于猜测,例如:

  • 什么版本的Python(正好请,例如2.7.1)

  • 您正在检查网址的浏览器是什么?什么是“观点 文字“告诉你?

  • 你说“我在同一页面上没有观察到任何替换 在浏览器中呈现。“好的,所以您从代码和浏览器中看到rhubarb \ufffd\ufffd artichoke rhubarb PLEASE-TELL-US-WHAT-YOU-SEE-HERE artichoke - 请透露。

  • 你有什么理由不能透露你所拥有的网址 问题?