Позвольте объекту JSON принимать байты или позволить выводить строки urlopen - PullRequest
175 голосов
/ 28 июля 2011

В Python 3 я запрашиваю документ json с URL.

response = urllib.request.urlopen(request)

Объект response является файловым объектом с методами read и readline. Обычно объект JSON можно создать с помощью файла, открытого в текстовом режиме.

obj = json.load(fp)

Я хотел бы сделать следующее:

obj = json.load(response)

Это, однако, не работает, так как urlopen возвращает объект файла в двоичном режиме.

Обойти это, конечно:

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

но это плохо ...

Есть ли лучший способ, которым я могу преобразовать объект файла байтов в объект файла строки? Или я пропускаю какие-либо параметры для urlopen или json.load для кодирования?

Ответы [ 11 ]

100 голосов
/ 14 сентября 2014

Прекрасная стандартная библиотека Python для спасения…

import codecs

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

Работает как с py2, так и с py3.

Документы: Python 2 , Python3

79 голосов
/ 28 июля 2011

HTTP отправляет байты.Если рассматриваемым ресурсом является текст, кодировка символов обычно указывается либо с помощью HTTP-заголовка Content-Type, либо с помощью другого механизма (RFC, HTML meta http-equiv, ...).

urllib должен знать, как кодировать байты в строку, но это слишком наивно - это ужасно слабая и непитоновая библиотека.

Dive Into Python 3 обеспечиваетобзор ситуации.

Ваш «обходной путь» в порядке - хотя он кажется неправильным, это правильный способ сделать это.

66 голосов
/ 27 августа 2015

Я пришел к выводу, что вопрос является лучшим ответом:)

import json
from urllib.request import urlopen

response = urlopen("site.com/api/foo/bar").read().decode('utf8')
obj = json.loads(response)
18 голосов
/ 13 октября 2016

Для тех, кто пытается решить эту проблему с помощью библиотеки 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'))
12 голосов
/ 13 июня 2017

Этот работает для меня, я использовал библиотеку 'request' с json(), проверьте документ в запросах для людей

import requests

url = 'here goes your url'

obj = requests.get(url).json() 
5 голосов
/ 12 июля 2017

Я столкнулся с похожими проблемами, используя 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 или более поздней.

3 голосов
/ 27 декабря 2016

Если вы столкнулись с этой проблемой при использовании микрофреймера для колб, вы можете просто сделать:

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

Из документов : «Если as_text установлен в True, возвращаемое значение будет декодированной строкой Unicode»

2 голосов
/ 09 декабря 2017

Твой обходной путь фактически спас меня. У меня было много проблем с обработкой запроса с использованием платформы Falcon. Это сработало для меня. требуется форма запроса curl pr httpie

json.loads(req.stream.read().decode('utf-8'))
1 голос
/ 28 февраля 2018

Это приведет к потоковой передаче байтовых данных в json.

import io

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

io.TextIOWrapper предпочтительнее модуля чтения кодека. https://www.python.org/dev/peps/pep-0400/

1 голос
/ 27 декабря 2015

Только что нашел этот простой способ сделать содержимое 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"}

Надеюсь, что вам поможет

...