Python: Intentar deserializar múltiples objetos JSON en un archivo con cada objeto que abarca varias líneas pero espaciadas constantemente

Ok, después de casi una semana de investigación, voy a darle a SO una oportunidad. Tengo un archivo de texto que tiene el siguiente aspecto (muestra 3 objetos json separados como ejemplo, pero el archivo tiene 50 K de estos):

{ "zipcode":"00544", "current":{"canwc":null,"cig":7000,"class":"observation"}, "triggers":[178,30,176,103,179,112,21,20,48,7,50,40,57] } { "zipcode":"00601", "current":{"canwc":null,"cig":null,"class":"observation"}, "triggers":[12,23,34,28,100] } { "zipcode":"00602", "current":{"canwc":null,"cig":null,"class":"observation"}, "triggers":[13,85,43,101,38,31] } 

Sé cómo trabajar con objetos JSON utilizando la biblioteca json de Python, pero tengo un desafío con la forma de crear 50 mil objetos json diferentes al leer el archivo. (Tal vez ni siquiera estoy pensando en esto correctamente pero, en última instancia, necesito deserializar y cargar en una base de datos) Lo probé y pensé que necesitaba un generador, así que pude usar:

 with open(file) as f: for line in itertools.islice(f, 0, 7): #since every 7 lines is a json object jfile = json.load(line) 

Pero lo anterior obviamente no funciona, ya que no está leyendo las 7 líneas como un solo objeto json y tampoco estoy seguro de cómo iterar en un archivo completo y cargar objetos json individuales.

Lo siguiente me daría una lista que puedo cortar:

 list(open(file))[:7] 

Cualquier ayuda sería realmente apreciada.


Muy cerca de lo que necesito y creo que, literalmente, a un paso de distancia, pero todavía estoy luchando un poco con la iteración. Esto finalmente me dará una impresión iterativa de todos los marcos de datos, pero ¿cómo puedo hacer que pueda capturar un dataframe gigante con todas las piezas esencialmente concatenadas? Luego podría exportar el último dataframe a csv, etc. (¿También hay una mejor manera de cargar este resultado en una base de datos en lugar de crear primero un dataframe gigante?)

 def lines_per_n(f, n): for line in f: yield ''.join(chain([line], itertools.islice(f, n - 1))) def flatten(jfile): for k, v in jfile.items(): if isinstance(v, list): jfile[k] = ','.join(v) elif isinstance(v, dict): for kk, vv in v.items(): jfile['%s' % (kk)] = vv del jfile[k] return jfile with open('deadzips.json') as f: for chunk in lines_per_n(f, 7): try: jfile = json.loads(chunk) pd.DataFrame(flatten(jfile).items()) except ValueError, e: pass else: pass 

En su lugar, cargue 6 líneas adicionales y pase la cadena a json.loads() :

 with open(file) as f: for line in f: # slice the next 6 lines from the iterable, as a list. lines = [line] + list(itertools.islice(f, 6)) jfile = json.loads(''.join(lines)) # do something with jfile 

json.load() más que solo el siguiente objeto en el archivo, e islice(f, 0, 7) leerá solo las primeras 7 líneas, en lugar de leer el archivo en bloques de 7 líneas.

Puede ajustar la lectura de un archivo en bloques de tamaño N en un generador:

 from itertools import islice, chain def lines_per_n(f, n): for line in f: yield ''.join(chain([line], itertools.islice(f, n - 1))) 

luego úsalo para fragmentar tu archivo de entrada:

 with open(file) as f: for chunk in lines_per_n(f, 7): jfile = json.loads(chunk) # do something with jfile 

Alternativamente, si tus bloques resultan ser de longitud variable, lee hasta que tengas algo que analice:

 with open(file) as f: for line in f: while True: try: jfile = json.loads(line) break except ValueError: # Not yet a complete JSON value line += next(f) # do something with jfile 

Como se indica en otra parte, una solución general es leer el archivo en partes, agregar cada pieza a la última y tratar de analizar esa nueva parte. Si no se analiza, continúa hasta que obtengas algo que sí lo hace. Una vez que tenga algo que analiza, devuélvalo y reinicie el proceso. Enjuague con espuma hasta que se quede sin datos.

Aquí hay un generador sucinto que hará esto:

 def load_json_multiple(segments): chunk = "" for segment in segments: chunk += segment try: yield json.loads(chunk) chunk = "" except ValueError: pass 

Úsalo así:

 with open('foo.json') as f: for parsed_json in load_json_multiple(f): print parsed_json 

Espero que esto ayude.