Пусть объект JSON принимает байты или позволяет выводить строки вывода

С 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 чтобы дать кодировку?

Ответ 1

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

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

Dive Into Python 3 содержит обзор ситуации.

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

Ответ 2

Pythons замечательная стандартная библиотека для спасения...

import codecs

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

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

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

Ответ 3

Я пришел к мнению, что вопрос - лучший ответ:)

import json
from urllib.request import urlopen

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

Ответ 4

Для других, кто пытается решить это, используя библиотеку 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'))

Ответ 5

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

import requests

url = 'here goes your url'

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

Ответ 6

Я столкнулся с аналогичными проблемами, используя 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 или новее.

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

import io

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

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

Ответ 11

Начиная с 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)

Ответ 12

Я использовал ниже программу для использования 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)