让JSON对象接受字节或让urlopen输出字符串

时间:2011-07-28 17:00:24

标签: python json python-3.x encoding urlopen

使用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的任何参数来提供编码?

12 个答案:

答案 0 :(得分:100)

Python拯救的精彩标准库...

import codecs

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

适用于py2和py3。

文档:Python 2Python3

答案 1 :(得分:79)

HTTP发送字节。如果有问题的资源是文本,则通常通过Content-Type HTTP标头或其他机制(RFC,HTML meta http-equiv,...)指定字符编码。

urllib 知道如何将字节编码为字符串,但它太天真 - 它是一个可怕的动力不足和非Pythonic库。

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

你的“解决方案”很好 - 虽然感觉不对,但这是正确的做法。

答案 2 :(得分:66)

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

import json
from urllib.request import urlopen

response = urlopen("site.com/api/foo/bar").read().decode('utf8')
obj = json.loads(response)

答案 3 :(得分:18)

对于其他试图使用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'))

答案 4 :(得分:11)

这个适用于我,我用过'请求' json()的图书馆会查看requests for humans

中的文档
import requests

url = 'here goes your url'

obj = requests.get(url).json() 

答案 5 :(得分:5)

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

您可以在此处详细了解: https://docs.python.org/3/whatsnew/3.6.html#json

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

答案 6 :(得分:3)

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

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

From the docs:"如果as_text设置为True,则返回值将是解码后的unicode字符串"

答案 7 :(得分:2)

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

json.loads(req.stream.read().decode('utf-8'))

答案 8 :(得分:1)

刚刚找到这个简单的方法来将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"}

希望能帮到你

答案 9 :(得分:1)

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

import io

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

io.TextIOWrapper比编解码器的模块阅读器更受欢迎。 https://www.python.org/dev/peps/pep-0400/

答案 10 :(得分:0)

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

答案 11 :(得分:-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)