Convierta una matriz de bytes en formato JSON

6 minutos de lectura

Avatar de usuario de Merouane Benthameur
merouane benthameur

quiero analizar un bytes string en formato JSON para convertirlo en objetos python. Esta es la fuente que tengo:

my_bytes_value = b'[{\'Date\': \'2016-05-21T21:35:40Z\', \'CreationDate\': \'2012-05-05\', \'LogoType\': \'png\', \'Ref\': 164611595, \'Classe\': [\'Email addresses\', \'Passwords\'],\'Link\':\'http://some_link.com\'}]'

Y este es el resultado deseado que quiero tener:

[{
"Date": "2016-05-21T21:35:40Z",
"CreationDate": "2012-05-05",
"LogoType": "png",
"Ref": 164611595,
"Classes": [
  "Email addresses",
  "Passwords"
],
"Link": "http://some_link.com"}]

Primero, convertí los bytes a cadena:

my_new_string_value = my_bytes_value.decode("utf-8")

pero cuando trato de invocar loads para analizarlo como JSON:

my_json = json.loads(my_new_string_value)

me sale este error:

json.decoder.JSONDecodeError: Expecting value: line 1 column 174 (char 173)

  • Lo primero es lo primero. Bytes a cadena, luego cadena a JSON

    – Un jugador de críquet

    15/10/2016 a las 13:39

  • He convertido los bytes a cadena usando .decode("utf-8") pero cuando trato de convertir la cadena a JOSN, aparece este error json.decoder.JSONDecodeError: Expecting value: line 1 column 174 (char 173)

    – Merouane Benthameur

    15/10/2016 a las 13:49

  • ¿Puede actualizar su pregunta con el código relevante e imprimir la cadena decodificada?

    – Un jugador de críquet

    15/10/2016 a las 13:50

  • Y, ¿de dónde sacas este json?

    – Un jugador de críquet

    15/10/2016 a las 13:52

  • @MerouaneBenthameur La razón por la que falla es porque la cadena que tienes no es JSON. Lo más obvio es que JSON usa "no '.

    – monstruoso

    15/10/2016 a las 13:58

Avatar de usuario de PM 2Ring
PM 2 Anillo

Su bytes el objeto es casi JSON, pero usa comillas simples en lugar de comillas dobles y debe ser una cadena. Entonces, una forma de solucionarlo es decodificar el bytes a str y reemplaza las comillas. Otra opción es utilizar ast.literal_eval; ver más abajo para más detalles. Si desea imprimir el resultado o guardarlo en un archivo como JSON válido, puede cargar el JSON en una lista de Python y luego volcarlo. P.ej,

import json

my_bytes_value = b'[{\'Date\': \'2016-05-21T21:35:40Z\', \'CreationDate\': \'2012-05-05\', \'LogoType\': \'png\', \'Ref\': 164611595, \'Classe\': [\'Email addresses\', \'Passwords\'],\'Link\':\'http://some_link.com\'}]'

# Decode UTF-8 bytes to Unicode, and convert single quotes 
# to double quotes to make it valid JSON
my_json = my_bytes_value.decode('utf8').replace("'", '"')
print(my_json)
print('- ' * 20)

# Load the JSON to a Python list & dump it back out as formatted JSON
data = json.loads(my_json)
s = json.dumps(data, indent=4, sort_keys=True)
print(s)

producción

[{"Date": "2016-05-21T21:35:40Z", "CreationDate": "2012-05-05", "LogoType": "png", "Ref": 164611595, "Classe": ["Email addresses", "Passwords"],"Link":"http://some_link.com"}]
- - - - - - - - - - - - - - - - - - - - 
[
    {
        "Classe": [
            "Email addresses",
            "Passwords"
        ],
        "CreationDate": "2012-05-05",
        "Date": "2016-05-21T21:35:40Z",
        "Link": "http://some_link.com",
        "LogoType": "png",
        "Ref": 164611595
    }
]

Como menciona Antti Haapala en los comentarios, podemos usar ast.literal_eval para convertir my_bytes_value a una lista de Python, una vez que la hemos decodificado a una cadena.

from ast import literal_eval
import json

my_bytes_value = b'[{\'Date\': \'2016-05-21T21:35:40Z\', \'CreationDate\': \'2012-05-05\', \'LogoType\': \'png\', \'Ref\': 164611595, \'Classe\': [\'Email addresses\', \'Passwords\'],\'Link\':\'http://some_link.com\'}]'

data = literal_eval(my_bytes_value.decode('utf8'))
print(data)
print('- ' * 20)

s = json.dumps(data, indent=4, sort_keys=True)
print(s)

Generalmente, este problema surge porque alguien ha guardado datos imprimiendo su Python repr en lugar de usar el json módulo para crear datos JSON adecuados. Si es posible, es mejor solucionar ese problema para que se creen los datos JSON adecuados en primer lugar.

  • No creo que sea una cadena JSON, sino una repetición de Python, así que use literal_eval en su lugar

    – Antti Haapala — Слава Україні

    16 de octubre de 2016 a las 6:49

  • Por cierto, si desea analizar o atravesar una estructura JSON complicada, consulte stackoverflow.com/a/52414034/4014959 & stackoverflow.com/a/41778581/4014959

    – PM 2 Ring

    24 de noviembre de 2020 a las 2:14

  • Re: En general, surge este problema … se crean datos JSON adecuados: Los datos de bytes aparentemente no son JSON serializables: json.dumps(b'\0x41\x45') -> TypeError: Object of type bytes is not JSON serializable

    – Vercingatorix

    18 de marzo a las 14:05

  • @Vercingatorix JSON es para serializar datos que en última instancia se componen de cadenas, números y valores booleanos (o nulos), no está diseñado para hacer frente a datos binarios arbitrarios. Pero es bastante fácil transformar dichos datos en un formato compatible con JSON, por ejemplo, puede crear una cadena hexadecimal simple con docs.python.org/3/library/stdtypes.html#bytes.hex O podría optimizar eso ligeramente con docs.python.org/3/library/base64.html

    – PM 2 Ring

    18 de marzo a las 14:24

Simplemente puede usar,

import json

json.loads(my_bytes_value)

  • esto debería tener una marca verde.

    – Kishore

    17 de julio de 2021 a las 17:11

  • Realmente no. Esto responde a la pregunta del título, pero omite que el ejemplo proporcionado por OP tiene comillas simples. json.loads(my_bytes_value) lanzaría un json.decoder.JSONDecodeError en este caso.

    – Pierre Mónico

    20 de julio a las 9:54

Pitón 3.5 + Usar módulo io

import json
import io

my_bytes_value = b'[{\'Date\': \'2016-05-21T21:35:40Z\', \'CreationDate\': \'2012-05-05\', \'LogoType\': \'png\', \'Ref\': 164611595, \'Classe\': [\'Email addresses\', \'Passwords\'],\'Link\':\'http://some_link.com\'}]'

fix_bytes_value = my_bytes_value.replace(b"'", b'"')

my_json = json.load(io.BytesIO(fix_bytes_value))  

  • ¡gracias! esta es la ruta menos complicada y más directa, especialmente si el json dentro de bytesarray ya está formateado correctamente.

    – Jason Rahm

    21 de enero de 2021 a las 4:16

Para convertir esta matriz de bytes directamente a json, primero puede convertir la matriz de bytes en una cadena con decode (), utf-8 es estándar. Cambie los marcadores de comillas. El último paso es eliminar ” de la cadena volcada, para cambiar el objeto json de cadena a lista.

dumps(s.decode()).replace("'", '"')[1:-1]

Mejor solución es:

import json
byte_array_example = b'{"text": "\u0627\u06CC\u0646 \u06CC\u06A9 \u0645\u062A\u0646 \u062A\u0633\u062A\u06CC \u0641\u0627\u0631\u0633\u06CC \u0627\u0633\u062A."}'    
res = json.loads(byte_array_example.decode('unicode_escape'))
print(res)

resultado:

{'text': 'این یک متن تستی فارسی است.'}

decode by utf-8 no puede decodificar caracteres Unicode. La solución correcta es uicode_escape

Está bien

Avatar de usuario de Suraj Rao
Suraj Rao

d = json.dumps(byte_str.decode('utf-8'))

Avatar de usuario de Darkstar Dream
Sueño de Estrella Oscura

si tiene un objeto de bytes y desea almacenarlo en un archivo JSON, primero debe decodificar el objeto de bytes porque JSON solo tiene algunos tipos de datos y los datos de bytes sin procesar no son uno de ellos. Tiene matrices, números decimales, cadenas y objetos.

Para decodificar un objeto de byte, primero debe conocer su codificación. Para esto, puedes usar

import chardet
encoding = chardet.detect(your_byte_object)['encoding']

entonces puede guardar este objeto en su archivo json de esta manera

data = {"data": your_byte_object.decode(encoding)}
with open('request.txt', 'w') as file:
    json.dump(data, file)

¿Ha sido útil esta solución?