8

我正在尝试编写一个 Python 脚本,将一些 JSON 发布到 Web 服务器并获取一些 JSON。我在 StackOverflow 上拼凑了几个不同的例子,我认为我有一些主要工作的东西。

import urllib2
import json

url = "http://foo.com/API.svc/SomeMethod"
payload = json.dumps( {'inputs': ['red', 'blue', 'green']} )
headers = {"Content-type": "application/json;"}

req = urllib2.Request(url, payload, headers)
f = urllib2.urlopen(req)
response = f.read()
f.close()

data = json.loads(response) # <-- Crashes

最后一行抛出异常:

ValueError:无法解码任何 JSON 对象

当我查看 时response,我看到了有效的 JSON,但前几个字符是 BOM:

>>> response
'\xef\xbb\xbf[\r\n  {\r\n    ... Valid JSON here

所以,如果我手动去掉前三个字节:

data = json.loads(response[3::])

一切正常,并response变成了字典。

我的问题:

json当你给它一个 BOM 时,它似乎有点愚蠢。有什么不同的我可以做的urllib或者json图书馆让它知道这是一个 UTF8 字符串并这样处理它吗?我不想手动删除前 3 个字节。

4

3 回答 3

12

您可能应该对运行此服务的人大喊大叫,因为 UTF-8 文本上的 BOM 毫无意义。BOM 的存在是为了消除字节顺序的歧义,UTF-8 被定义为 little-endian。

也就是说,理想情况下,您应该先对字节进行解码,然后再对它们进行任何其他操作。幸运的是,Python 有一个可以识别和删除 BOM 的编解码器:utf-8-sig.

>>> '\xef\xbb\xbffoo'.decode('utf-8-sig')
u'foo'

所以你只需要:

data = json.loads(response.decode('utf-8-sig'))
于 2013-01-25T23:59:07.983 回答
5

如果我不是唯一遇到同样问题的人,而是使用requestsmodule 而不是urllib2,这里有一个适用于 Python 2.6 和 3.3 的解决方案:

import requests
r = requests.get(url, params=my_dict, auth=(user, pass))
print(r.headers['content-type'])  # 'application/json; charset=utf8'
if r.text[0] == u'\ufeff':  # bytes \xef\xbb\xbf in utf-8 encoding
    r.encoding = 'utf-8-sig'
print(r.json())
于 2014-05-09T15:35:03.547 回答
0

由于我缺乏足够的评论声誉,我会写一个答案。

当我需要保留未平仓的底层证券时,我通常会遇到这个Stream问题StreamWriter。但是,可以选择保持底层Stream打开的重载需要编码(在大多数情况下将是 UTF8),这里是如何在发出 BOM 的情况下做到这一点。

/* Since Encoding.UTF8 (the one you'd normally use in those cases) **emits**
 * the BOM, use whats below instead!
 */

// UTF8Encoding has an overload which enables / disables BOMs in the output
UTF8Encoding encoding = new UTF8Encoding(false);

using (MemoryStream ms = new MemoryStream())
using (StreamWriter sw = new StreamWriter(ms, encoding, 4096, true))
using (JsonTextWriter jtw = new JsonTextWriter(sw))
{
    serializer.Serialize(jtw, myObject);
}
于 2015-04-18T11:49:24.603 回答