Deje que el objeto JSON acepte bytes o deje cadenas de salida urlopen

Con Python 3 estoy solicitando un documento json desde una URL.

response = urllib.request.urlopen(request) 

El objeto de response es un objeto similar a un archivo con métodos de read y línea de read . Normalmente, un objeto JSON se puede crear con un archivo abierto en modo de 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 de archivo en modo binario.

Un trabajo alrededor es por supuesto:

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

pero esto se siente mal …

¿Hay una mejor manera de 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 encoding?

HTTP envía bytes. Si el recurso en cuestión es texto, la encoding de caracteres se especifica normalmente, ya sea por el encabezado HTTP de tipo de contenido 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 biblioteca horriblemente poco poderosa y no pythonica.

Dive Into Python 3 proporciona una visión general de la situación.

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

La maravillosa biblioteca estándar de Python al rescate …

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

Funciona tanto con py2 como con py3.

Documentos: Python 2 , Python3

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) 

Para cualquier otra persona que intente resolver esto utilizando la biblioteca de 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')) 

Este funciona para mí, usé la biblioteca de ‘solicitudes’ con json() echa un vistazo al documento en solicitudes para personas

 import requests url = 'here goes your url' obj = requests.get(url).json() 

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.

Puede 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 la versión 3.6 o posterior.

Si está experimentando este problema mientras utiliza el microframework del matraz, puede simplemente hacer:

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

De la documentación : “Si as_text se establece en True, el valor de retorno será una cadena Unicode descodificada”

Acabo de encontrar este método simple para hacer contenido HttpResponse como 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

Tu solución realmente me salvó. Estaba teniendo muchos problemas al procesar la solicitud utilizando el framework Falcon. Esto funcionó para mí. siendo el formulario de solicitud curl pr httpie

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

Esto transmitirá los datos de bytes a json.

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

io.TextIOWrapper se prefiere al lector de módulos del codec. https://www.python.org/dev/peps/pep-0400/

Utilicé el siguiente progtwig 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)