Permitir que el objeto JSON acepte bytes o permitir que urlopen las cadenas de salida


Con Python3 estoy solicitando un documento json desde una URL.

response = urllib.request.urlopen(request)

El objeto response es un objeto similar a un archivo con los métodos read y readline.

Normalmente se puede crear un objeto JSON con un archivo abierto en modo texto.

obj = json.load(fp)

Lo que me gustaría hacer es:

obj = json.load(response)

Sin embargo, esto no funciona ya que urlopen devuelve un objeto file en modo binario.

Un trabajo alrededor es, por supuesto:

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

Pero esto se siente mal...

¿Hay una mejor manera ¿que puedo transformar un objeto de archivo de bytes en un objeto de archivo de cadena? ¿O me falta algún parámetro para urlopen o json.load para dar una codificación?

Author: abccd, 2011-07-28

11 answers

HTTP envía bytes. Si el recurso en cuestión es texto, la codificación de caracteres se especifica normalmente, ya sea por el encabezado HTTP Content-Type o por otro mecanismo (un RFC, HTML meta http-equiv,...).

urllib debería saber cómo codificar los bytes en una cadena, pero es demasiado ingenuo-es una horrible falta de potencia y de la onu-de la biblioteca de Python.

Bucear en Python 3 proporciona una visión general sobre la situación.

Su "solución alternativa" está bien, aunque se siente mal, es la forma correcta de hacerlo.

 76
Author: Humphrey Bogart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-03 18:50:50

La maravillosa biblioteca estándar de Python al rescate {

import codecs

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

Funciona con py2 y py3.

Docs: Python 2, Python3

 97
Author: jbg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-23 10:29:57

He llegado a la opinión de que la pregunta es la mejor respuesta:)

import json
from urllib.request import urlopen

response = urlopen("site.com/api/foo/bar").read().decode('utf8')
obj = json.loads(response)
 66
Author: SergO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-27 12:55:57

Para cualquier otra persona que intente resolver esto usando la biblioteca 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'))
 17
Author: Luke Yeager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-13 18:06:42

Este funciona para mí, usé la biblioteca 'request' con json() echa un vistazo al documento en requests for humans

import requests

url = 'here goes your url'

obj = requests.get(url).json() 
 9
Author: Sarthak Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-20 03:47:00

Me encontré con problemas similares usando Python 3.4.3 & 3.5.2 y Django 1.11.3. Sin embargo, cuando actualicé a Python 3.6.1 los problemas desaparecieron.

Puedes leer más sobre esto aquí: https://docs.python.org/3/whatsnew/3.6.html#json

Si no está vinculado a una versión específica de Python, solo considere actualizar a 3.6 o posterior.

 5
Author: PaulMest,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-12 01:19:14

Si está experimentando este problema mientras usa el microframe del frasco, entonces puede hacer:

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

Desde los documentos:"Si as_text se establece en True, el valor devuelto será una cadena unicode decodificada"

 3
Author: cs_stackX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-27 11:17:13

Acabo de encontrar este sencillo método para hacer que el contenido HttpResponse sea un 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"}

Espero que te ayude

 2
Author: Aditya Kresna Permana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-27 17:26:09

Su solución en realidad me acaba de salvar. Estaba teniendo muchos problemas procesando la solicitud usando el framework Falcon. Esto funcionó para mí. req siendo el formulario de solicitud curl pr httpie

json.loads(req.stream.read().decode('utf-8'))
 2
Author: thielyrics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-09 17:21:37

Esto transmitirá los datos de bytes a json.

import io

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

Io.TextIOWrapper es preferible al lector de módulos del códec. https://www.python.org/dev/peps/pep-0400 /

 1
Author: Collin Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-28 20:30:36

Utilicé el siguiente programa para usar 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)
 -1
Author: jayesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-15 01:27:00