UnicodeDecodeError: 'utf8'编解码器无法解码位置3-6的字节:无效数据。

52

在Python2中,Unicode是如何工作的?我就是不明白。

我从服务器下载数据并解析为JSON格式。

Traceback (most recent call last):
  File "/usr/local/lib/python2.6/dist-packages/eventlet-0.9.12-py2.6.egg/eventlet/hubs/poll.py", line 92, in wait
    readers.get(fileno, noop).cb(fileno)
  File "/usr/local/lib/python2.6/dist-packages/eventlet-0.9.12-py2.6.egg/eventlet/greenthread.py", line 202, in main
    result = function(*args, **kwargs)
  File "android_suggest.py", line 60, in fetch
    suggestions = suggest(chars)
  File "android_suggest.py", line 28, in suggest
    return [i['s'] for i in json.loads(opener.open('https://market.android.com/suggest/SuggRequest?json=1&query='+s+'&hl=de&gl=DE').read())]
  File "/usr/lib/python2.6/json/__init__.py", line 307, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.6/json/decoder.py", line 319, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.6/json/decoder.py", line 336, in raw_decode
    obj, end = self._scanner.iterscan(s, **kw).next()
  File "/usr/lib/python2.6/json/scanner.py", line 55, in iterscan
    rval, next_pos = action(m, context)
  File "/usr/lib/python2.6/json/decoder.py", line 217, in JSONArray
    value, end = iterscan(s, idx=end, context=context).next()
  File "/usr/lib/python2.6/json/scanner.py", line 55, in iterscan
    rval, next_pos = action(m, context)
  File "/usr/lib/python2.6/json/decoder.py", line 183, in JSONObject
    value, end = iterscan(s, idx=end, context=context).next()
  File "/usr/lib/python2.6/json/scanner.py", line 55, in iterscan
    rval, next_pos = action(m, context)
  File "/usr/lib/python2.6/json/decoder.py", line 155, in JSONString
    return scanstring(match.string, match.end(), encoding, strict)
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 3-6: invalid data

谢谢!

编辑:以下字符串导致错误:'[{"t":"q","s":"abh\xf6ren"}]'。应将\xf6解码为ö(abhören)。


1
您正在尝试将一些无效的UTF-8数据解释为UTF-8。我们不知道您的数据,因此无法告诉您它实际上是什么。也许它是一个压缩的JSON字符串?在这种情况下,请先尝试使用.decode("zlib") - Sven Marnach
大多数情况下它可以工作,只是有时候不行。我认为可能是因为存在一些特殊字符导致它无法工作。 - ihucos
8
在 ISO-8895-1 和其他类似的 8 位编码中,0xF6 表示 ö。如果原始消息使用的是 ISO-8859-1,而不是 UTF-8,且超出您的控制范围,则可以始终执行 message = unicode(message, "ISO-8859-1") - Tadeusz A. Kadłubowski
/usr/lib/python2.6/urllib.py:1222: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal,之后出现了KeyError: u'\xf6' - ihucos
8个回答

85

NameError: 全局名称 'opener' 未定义 - Gopakumar N G
@GopakumarNG:查看urllib库以了解normal的示例堆栈跟踪。 - Tadeusz A. Kadłubowski
1
@TadeuszA.Kadłubowski感谢您提供“ISO-8859-1”编码,我之前并不知道这种编码方式,但它却意外地解决了我的nltk bug问题。 - sam boosalis
2
json.load( open( fname, 'r' ), encoding='ISO-8859-1' ) @GopakumarNG: - user1225054
@samboosalis nltk bug 链接失效了。 - Dave Liu
显示剩余3条评论

6

我的解决方案有点有趣。我从来没有想过这会像使用UTF-8编解码一样容易。我正在使用Notepad++(v5.6.8)。最初我没有注意到我用的是ANSI编码保存的。我使用单独的文件来放置所有本地化字典。我在Notepad++的“编码”选项卡下找到了我的解决方案。我选择“无BOM的UTF-8编码”并保存。它工作得非常出色。


1
我希望我能给你点赞十次。这就是我为之奋斗了两天的问题! - AmaChefe
在我的情况下,我选择了“使用UTF8编码”,它仍然起作用,但会暴露出奇怪的字符,我进行了替换。 每个使用Notepad++或其他编辑器的人都应该注意。 - AmaChefe

4
您看到的错误意味着您从远程端接收到的数据不是有效的JSON格式。JSON(根据规范)通常为UTF-8,但也可以是UTF-16或UTF-32(无论是大端还是小端)。您看到的确切错误意味着数据的某个部分不是有效的UTF-8(并且也不是UTF-16或UTF-32,因为这些会产生不同的错误)。
也许您应该检查实际从远程端接收到的响应,而不是盲目地将数据传递给json.loads()。现在,您正在将响应中的所有数据读入字符串,并假设它是JSON。相反,请检查响应的内容类型。确保网页实际上声称为您提供JSON,而不是例如非JSON的错误消息。
(另外,在检查响应后,使用opener.open()返回的类似文件的对象通过传递给json.load(),而不是将所有数据读入字符串并将其传递给json.loads()。)

opener.open 不会返回文件对象:TypeError: expected string or buffer。我编辑了我的帖子并添加了导致问题的字符串。 - ihucos
那个 TypeError 表示你仍在使用 json.loads() 而不是 json.load()opener.open() 确实返回一个文件类对象,因为你在代码中这样使用它。你拥有的 JSON 字符串是无效的 JSON -- \xf6 在 UTF-8 中不是 ü,只有在某些单字节编码(比如 iso-8859-1)中才是。JSON 不应该以这些编码形式给出,只应该使用 UTF-8、UTF-16 或 UTF-32。你需要修复 JSON 供应商(使其使用 \\u00f6 替代 \xf6),或者找出这是什么编码,并在将其解析为 JSON 之前将其重新编码为 UTF-8。 - Thomas Wouters
抱歉,我没有注意到“s”。但是谢谢你,我会放弃的。)-: - ihucos

3
将编码更改为Latin1 / ISO-8859-1的解决方案解决了我在tex4ht输出上调用html2text.py时观察到的问题。我将其用于LaTeX文档的自动字数统计:tex4ht将它们转换为HTML,然后html2text.py将其剥离为纯文本以通过wc -w进行进一步的计数。现在,如果例如德语“Umlaut”通过文献数据库条目输入,该过程将失败,因为html2text.py会抱怨,例如

UnicodeDecodeError: 'utf8' codec can't decode bytes in position 32243-32245: invalid data

这些错误随后会特别难以追踪,并且基本上您希望在参考部分中具有Umlaut。从html2text.py内部进行简单的更改,从

data = data.decode(encoding)

data = data.decode("ISO-8859-1")

解决了该问题;如果使用HTML文件作为第一个参数调用脚本,则还可以传递编码作为第二个参数并省略修改。

1

将以下内容复制粘贴到命令行中:

export LC_CTYPE="en_US.UTF-8" 

1

如果有人遇到同样的问题,我正在使用YouCompleteMe的vim,在启动ycmd时出现以下错误信息,我的解决方法是:export LC_CTYPE="en_US.UTF-8",问题解决了。


0
临时解决方法:unicode(urllib2.urlopen(url).read(), 'utf8') - 如果返回的是UTF-8,则应该可以工作。

urlopen().read()返回字节,您需要将它们解码为Unicode字符串。此外,检查http://bugs.python.org/issue4733中的补丁会很有帮助。


无法运行:'ascii' codec can't decode byte 0xf6 in position 18: ordinal not in range(128) - ihucos
1
"unicode(chars)"不是将字符解码为Unicode的正确方式(您至少需要指定编码),而且这并不是问题所在。 - Thomas Wouters
ANSI是“美国国家标准学会”。 - John Machin
2
在OP的情况下,显而易见的问题是数据不是UTF-8,因此使用UTF-8解码将无法工作。JSON数据是字节,而不是Unicode。它包含Unicode,并且这些字节应该被编码为UTF-8、UTF-16或UTF-32,但在这里并不是这样。 - Thomas Wouters

0
在你的 android_suggest.py 文件中,将那个庞大的一行返回语句分解成逐步执行的小块。在某个地方记录下 repr(string_passed_to_json.loads),以便在出现异常时进行检查。仔细观察结果。如果问题不明显,请编辑你的问题以显示 repr。

好的,我已经在我的帖子中添加了导致问题的字符串。 - ihucos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接