183

使用 Python 3,我从 URL 请求一个 json 文档。

response = urllib.request.urlopen(request)

response对象是具有readreadline方法的类文件对象。通常,可以使用以文本模式打开的文件来创建 JSON 对象。

obj = json.load(fp)

我想做的是:

obj = json.load(response)

但是,这不起作用,因为 urlopen 以二进制模式返回文件对象。

解决方法当然是:

str_response = response.read().decode('utf-8')
obj = json.loads(str_response)

但这感觉很糟糕......

有没有更好的方法可以将字节文件对象转换为字符串文件对象?或者我是否缺少任何参数urlopenjson.load提供编码?

4

12 回答 12

102

Python 出色的标准库来拯救...</p>

import codecs

reader = codecs.getreader("utf-8")
obj = json.load(reader(response))

适用于 py2 和 py3。

文档:Python 2Python3

于 2014-09-14T01:39:12.060 回答
80

HTTP 发送字节。如果所讨论的资源是文本,则通常通过 Content-Type HTTP 标头或其他机制(RFC、HTMLmeta http-equiv等)指定字符编码。

urllib 应该知道如何将字节编码为字符串,但它太天真了——它是一个可怕的功能不足和非 Python 的库。

Dive Into Python 3提供了有关情况的概述。

你的“变通办法”很好——虽然感觉不对,但这是正确的做法。

于 2011-07-28T17:13:03.753 回答
67

我认为这个问题是最好的答案:)

import json
from urllib.request import urlopen

response = urlopen("site.com/api/foo/bar").read().decode('utf8')
obj = json.loads(response)
于 2015-08-27T12:55:57.683 回答
20

对于其他尝试使用该requests库解决此问题的人:

import json
import requests

r = requests.get('http://localhost/index.json')
r.raise_for_status()
# works for Python2 and Python3
json.loads(r.content.decode('utf-8'))
于 2016-10-13T18:06:42.293 回答
14

这个对我有用,我使用“请求”库来查看人类请求中json()的文档

import requests

url = 'here goes your url'

obj = requests.get(url).json() 
于 2017-06-13T04:36:26.573 回答
7

我在使用 Python 3.4.3 & 3.5.2 和 Django 1.11.3 时遇到了类似的问题。但是,当我升级到 Python 3.6.1 时,问题就消失了。

您可以在此处阅读更多相关信息: https ://docs.python.org/3/whatsnew/3.6.html#json

如果您不依赖特定版本的 Python,只需考虑升级到 3.6 或更高版本。

于 2017-07-12T01:19:14.890 回答
3

如果您在使用烧瓶微框架时遇到此问题,那么您可以这样做:

data = json.loads(response.get_data(as_text=True))

来自文档:“如果 as_text 设置为 True,则返回值将是解码的 unicode 字符串”

于 2016-12-27T11:17:13.533 回答
1

这会将字节数据流式传输到 json 中。

import io

obj = json.load(io.TextIOWrapper(response))

io.TextIOWrapper 优先于编解码器的模块阅读器。https://www.python.org/dev/peps/pep-0400/

于 2018-02-28T20:30:36.697 回答
1

从 Python 3.6 开始,您可以使用直接json.loads()反序列bytes化对象(编码必须是 UTF-8、UTF-16 或 UTF-32)。因此,仅使用标准库中的模块,您可以:

import json
from urllib import request

response = request.urlopen(url).read()
data = json.loads(response)
于 2019-09-25T14:57:03.367 回答
1

您的解决方法实际上只是救了我。我在使用 Falcon 框架处理请求时遇到了很多问题。这对我有用。req 是请求表单 curl pr httpie

json.loads(req.stream.read().decode('utf-8'))
于 2017-12-09T17:21:37.897 回答
0

刚刚找到了这个简单的方法来将 HttpResponse 内容作为 json

import json

request = RequestFactory() # ignore this, this just like your request object

response = MyView.as_view()(request) # got response as HttpResponse object

response.render() # call this so we could call response.content after

json_response = json.loads(response.content.decode('utf-8'))

print(json_response) # {"your_json_key": "your json value"}

希望对你有帮助

于 2015-12-27T17:20:18.443 回答
-2

我用下面的程序来使用json.loads()

import urllib.request
import json
endpoint = 'https://maps.googleapis.com/maps/api/directions/json?'
api_key = 'AIzaSyABbKiwfzv9vLBR_kCuhO7w13Kseu68lr0'
origin = input('where are you ?').replace(' ','+')
destination = input('where do u want to go').replace(' ','+')
nav_request = 'origin={}&destination={}&key={}'.format(origin,destination,api_key)
request = endpoint + nav_request
response = urllib.request.urlopen(request).read().decode('utf-8')
directions = json.loads(response)
print(directions)
于 2018-02-14T16:24:52.193 回答