pandas read_json python
¿Cómo puedo convertir JSON a CSV? (15)
Como se mencionó en las respuestas anteriores, la dificultad para convertir json a csv se debe a que un archivo json puede contener diccionarios anidados y, por lo tanto, ser una estructura de datos multidimensional frente a un csv que es una estructura de datos 2D. Sin embargo, una buena forma de convertir una estructura multidimensional en una csv es tener varias csvs que se unan con claves primarias.
En su ejemplo, la primera salida de csv tiene las columnas "pk", "modelo", "campos" como sus columnas. Los valores para "pk" y "modelo" son fáciles de obtener, pero debido a que la columna "campos" contiene un diccionario, debe ser su propio csv y porque "nombre clave" aparece como la clave primaria, puede usar como entrada para "campos" para completar el primer csv. La segunda csv contiene el diccionario de la columna "campos" con el nombre clave como la clave principal que se puede usar para unir las 2 csvs.
Aquí hay una solución para su archivo json que convierte un diccionario anidado en 2 csvs.
import csv
import json
def readAndWrite(inputFileName, primaryKey=""):
input = open(inputFileName+".json")
data = json.load(input)
input.close()
header = set()
if primaryKey != "":
outputFileName = inputFileName+"-"+primaryKey
if inputFileName == "data":
for i in data:
for j in i["fields"].keys():
if j not in header:
header.add(j)
else:
outputFileName = inputFileName
for i in data:
for j in i.keys():
if j not in header:
header.add(j)
with open(outputFileName+".csv", ''wb'') as output_file:
fieldnames = list(header)
writer = csv.DictWriter(output_file, fieldnames, delimiter='','', quotechar=''"'')
writer.writeheader()
for x in data:
row_value = {}
if primaryKey == "":
for y in x.keys():
yValue = x.get(y)
if type(yValue) == int or type(yValue) == bool or type(yValue) == float or type(yValue) == list:
row_value[y] = str(yValue).encode(''utf8'')
elif type(yValue) != dict:
row_value[y] = yValue.encode(''utf8'')
else:
if inputFileName == "data":
row_value[y] = yValue["codename"].encode(''utf8'')
readAndWrite(inputFileName, primaryKey="codename")
writer.writerow(row_value)
elif primaryKey == "codename":
for y in x["fields"].keys():
yValue = x["fields"].get(y)
if type(yValue) == int or type(yValue) == bool or type(yValue) == float or type(yValue) == list:
row_value[y] = str(yValue).encode(''utf8'')
elif type(yValue) != dict:
row_value[y] = yValue.encode(''utf8'')
writer.writerow(row_value)
readAndWrite("data")
Tengo un archivo JSON que quiero convertir a un archivo CSV. ¿Cómo puedo hacer esto con Python?
Lo intenté:
import json
import csv
f = open(''data.json'')
data = json.load(f)
f.close()
f = open(''data.csv'')
csv_file = csv.writer(f)
for item in data:
f.writerow(item)
f.close()
Sin embargo, no funcionó. Estoy usando Django y el error que recibí es:
file'' object has no attribute ''writerow''
Entonces, intenté lo siguiente:
import json
import csv
f = open(''data.json'')
data = json.load(f)
f.close()
f = open(''data.csv'')
csv_file = csv.writer(f)
for item in data:
csv_file.writerow(item)
f.close()
Entonces obtengo el error:
sequence expected
Muestra de archivo json:
[
{
"pk": 22,
"model": "auth.permission",
"fields": {
"codename": "add_logentry",
"name": "Can add log entry",
"content_type": 8
}
},
{
"pk": 23,
"model": "auth.permission",
"fields": {
"codename": "change_logentry",
"name": "Can change log entry",
"content_type": 8
}
},
{
"pk": 24,
"model": "auth.permission",
"fields": {
"codename": "delete_logentry",
"name": "Can delete log entry",
"content_type": 8
}
},
{
"pk": 4,
"model": "auth.permission",
"fields": {
"codename": "add_group",
"name": "Can add group",
"content_type": 2
}
},
{
"pk": 10,
"model": "auth.permission",
"fields": {
"codename": "add_message",
"name": "Can add message",
"content_type": 4
}
}
]
Con la library pandas
, ¡ esto es tan fácil como usar dos comandos!
pandas.read_json()
Para convertir una cadena JSON en un objeto pandas (ya sea una serie o un marco de datos). Luego, suponiendo que los resultados se almacenaron como df
:
df.to_csv()
Que puede devolver una cadena o escribir directamente en un archivo csv.
En base a la verbosidad de las respuestas anteriores, todos debemos agradecer a los pandas por el atajo.
Dado que los datos parecen estar en un formato de diccionario, parece que en realidad debería usar csv.DictWriter () para generar realmente las líneas con la información de encabezado adecuada. Esto debería permitir que la conversión sea más fácil. El parámetro de nombres de campo luego configuraría el orden correctamente, mientras que el resultado de la primera línea como los encabezados permitiría que fuera leído y procesado posteriormente por csv.DictReader ().
Por ejemplo, Mike Repass utilizó
output = csv.writer(sys.stdout)
output.writerow(data[0].keys()) # header row
for row in data:
output.writerow(row.values())
Sin embargo, simplemente cambie la configuración inicial a output = csv.DictWriter (filesetting, fieldnames = data [0] .keys ())
Tenga en cuenta que dado que el orden de los elementos en un diccionario no está definido, es posible que tenga que crear entradas de nombres de campo explícitamente. Una vez que hagas eso, el escritor trabajará. Las escrituras luego funcionan como se muestra originalmente.
Estaba teniendo problemas con la solución propuesta por Dan , pero esto funcionó para mí:
import json
import csv
f = open(''test.json'')
data = json.load(f)
f.close()
f=csv.writer(open(''test.csv'',''wb+''))
for item in data:
f.writerow([item[''pk''], item[''model'']] + item[''fields''].values())
Donde "test.json" contenía lo siguiente:
[
{"pk": 22, "model": "auth.permission", "fields":
{"codename": "add_logentry", "name": "Can add log entry", "content_type": 8 } },
{"pk": 23, "model": "auth.permission", "fields":
{"codename": "change_logentry", "name": "Can change log entry", "content_type": 8 } }, {"pk": 24, "model": "auth.permission", "fields":
{"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 8 } }
]
Este código debería funcionar para usted, suponiendo que sus datos JSON se encuentren en un archivo llamado data.json
.
import json
import csv
with open("data.json") as file:
data = json.load(file)
with open("data.csv", "w") as file:
csv_file = csv.writer(file)
for item in data:
csv_file.writerow([item[''pk''], item[''model'']] + item[''fields''].values())
Esto funciona relativamente bien. Aplana el json para escribirlo en un archivo csv. Los elementos anidados se administran :)
Eso es para Python 3
import json
o = json.loads(''your json string'') # Be careful, o must be a list, each of its objects will make a line of the csv.
def flatten(o, k=''/''):
global l, c_line
if isinstance(o, dict):
for key, value in o.items():
flatten(value, k + ''/'' + key)
elif isinstance(o, list):
for ov in o:
flatten(ov, '''')
elif isinstance(o, str):
o = o.replace(''/r'','' '').replace(''/n'','' '').replace('';'', '','')
if not k in l:
l[k]={}
l[k][c_line]=o
def render_csv(l):
ftime = True
for i in range(100): #len(l[list(l.keys())[0]])
for k in l:
if ftime :
print(''%s;'' % k, end='''')
continue
v = l[k]
try:
print(''%s;'' % v[i], end='''')
except:
print('';'', end='''')
print()
ftime = False
i = 0
def json_to_csv(object_list):
global l, c_line
l = {}
c_line = 0
for ov in object_list : # Assumes json is a list of objects
flatten(ov)
c_line += 1
render_csv(l)
json_to_csv(o)
disfrutar.
JSON puede representar una amplia variedad de estructuras de datos: un "objeto" de JS es más o menos como un dict de Python (con claves de cadena), una "matriz" de JS más o menos como una lista de Python, y puedes anidar hasta la final " los elementos de la hoja son números o cadenas.
CSV puede representar esencialmente solo una tabla 2-D, opcionalmente con una primera fila de "encabezados", es decir, "nombres de columna", que pueden hacer que la tabla sea interpretable como una lista de dicts, en lugar de la interpretación normal, una lista de listas (de nuevo, los elementos "hoja" pueden ser números o cadenas).
Entonces, en el caso general, no puede traducir una estructura JSON arbitraria a un CSV. En algunos casos especiales puede (matriz de matrices sin anidamiento adicional, matrices de objetos que tienen exactamente las mismas claves). ¿Qué caso especial, si corresponde, se aplica a su problema? Los detalles de la solución dependen del caso especial que tenga. Dado el sorprendente hecho de que ni siquiera mencionas cuál aplica, sospecho que es posible que no hayas considerado la restricción, que ninguno de los casos utilizables se aplica, y tu problema es imposible de resolver. Pero por favor aclara!
Mi forma simple de resolver esto:
Cree un nuevo archivo de Python como: json_to_csv.py
Agrega este código:
import csv, json, sys
#if you are not using utf-8 files, remove the next line
sys.setdefaultencoding("UTF-8")
#check if you pass the input file and output file
if sys.argv[1] is not None and sys.argv[2] is not None:
fileInput = sys.argv[1]
fileOutput = sys.argv[2]
inputFile = open(fileInput)
outputFile = open(fileOutput, ''w'')
data = json.load(inputFile)
inputFile.close()
output = csv.writer(outputFile)
output.writerow(data[0].keys()) # header row
for row in data:
output.writerow(row.values())
Después de agregar este código, guarde el archivo y ejecútelo en la terminal:
python json_to_csv.py input.txt output.csv
Espero que esto te ayude.
¡NOS VEMOS!
No es una manera muy inteligente de hacerlo, pero he tenido el mismo problema y esto funcionó para mí:
import csv
f = open(''data.json'')
data = json.load(f)
f.close()
new_data = []
for i in data:
flat = {}
names = i.keys()
for n in names:
try:
if len(i[n].keys()) > 0:
for ii in i[n].keys():
flat[n+"_"+ii] = i[n][ii]
except:
flat[n] = i[n]
new_data.append(flat)
f = open(filename, "r")
writer = csv.DictWriter(f, new_data[0].keys())
writer.writeheader()
for row in new_data:
writer.writerow(row)
f.close()
No estoy seguro si esta pregunta ya está resuelta o no, pero déjame pegar lo que hice como referencia.
En primer lugar, su JSON tiene objetos anidados, por lo que normalmente no se puede convertir directamente a CSV. Tienes que cambiar eso a algo como esto:
{
"pk": 22,
"model": "auth.permission",
"codename": "add_logentry",
"content_type": 8,
"name": "Can add log entry"
},
......]
Aquí está mi código para generar CSV a partir de eso:
import csv
import json
x = """[
{
"pk": 22,
"model": "auth.permission",
"fields": {
"codename": "add_logentry",
"name": "Can add log entry",
"content_type": 8
}
},
{
"pk": 23,
"model": "auth.permission",
"fields": {
"codename": "change_logentry",
"name": "Can change log entry",
"content_type": 8
}
},
{
"pk": 24,
"model": "auth.permission",
"fields": {
"codename": "delete_logentry",
"name": "Can delete log entry",
"content_type": 8
}
}
]"""
x = json.loads(x)
f = csv.writer(open("test.csv", "wb+"))
# Write CSV Header, If you dont need that, remove this line
f.writerow(["pk", "model", "codename", "name", "content_type"])
for x in x:
f.writerow([x["pk"],
x["model"],
x["fields"]["codename"],
x["fields"]["name"],
x["fields"]["content_type"]])
Obtendrás resultados como:
pk,model,codename,name,content_type
22,auth.permission,add_logentry,Can add log entry,8
23,auth.permission,change_logentry,Can change log entry,8
24,auth.permission,delete_logentry,Can delete log entry,8
Sé que ha pasado mucho tiempo desde que se hizo esta pregunta, pero pensé que podría agregar a la respuesta de todos los demás y compartir una publicación de blog que creo que explicaría la solución de una manera muy concisa.
Aquí está el link
Abra un archivo para escribir
employ_data = open(''/tmp/EmployData.csv'', ''w'')
Crear el objeto escritor csv
csvwriter = csv.writer(employ_data)
count = 0
for emp in emp_data:
if count == 0:
header = emp.keys()
csvwriter.writerow(header)
count += 1
csvwriter.writerow(emp.values())
Asegúrese de cerrar el archivo para guardar los contenidos
employ_data.close()
Se modificó la respuesta de Alec McGail para admitir a JSON con listas dentro
def flattenjson(self, mp, delim="|"):
ret = []
if isinstance(mp, dict):
for k in mp.keys():
csvs = self.flattenjson(mp[k], delim)
for csv in csvs:
ret.append(k + delim + csv)
elif isinstance(mp, list):
for k in mp:
csvs = self.flattenjson(k, delim)
for csv in csvs:
ret.append(csv)
else:
ret.append(mp)
return ret
¡Gracias!
Será fácil usar csv.DictWriter()
, la implementación detallada puede ser así:
def read_json(filename):
return json.loads(open(filename).read())
def write_csv(data,filename):
with open(filename) as outf:
writer = csv.DictWriter(outf, data[0].keys())
writer.writeheader()
for row in data:
writer.writerow(row)
# implement
write_csv(read_json(''test.json''), ''output.csv'')
Tenga en cuenta que esto supone que todos sus objetos JSON tienen los mismos campos.
Aquí está la reference que puede ayudarte.
Supongo que su archivo JSON se decodificará en una lista de diccionarios. Primero necesitamos una función que aplanara los objetos JSON:
def flattenjson( b, delim ):
val = {}
for i in b.keys():
if isinstance( b[i], dict ):
get = flattenjson( b[i], delim )
for j in get.keys():
val[ i + delim + j ] = get[j]
else:
val[i] = b[i]
return val
El resultado de ejecutar este fragmento en su objeto JSON:
flattenjson( {
"pk": 22,
"model": "auth.permission",
"fields": {
"codename": "add_message",
"name": "Can add message",
"content_type": 8
}
}, "__" )
es
{
"pk": 22,
"model": "auth.permission'',
"fields__codename": "add_message",
"fields__name": "Can add message",
"fields__content_type": 8
}
Después de aplicar esta función a cada dict en la matriz de entrada de objetos JSON:
input = map( lambda x: flattenjson( x, "__" ), input )
y encontrar los nombres de columna relevantes:
columns = [ x for row in input for x in row.keys() ]
columns = list( set( columns ) )
no es difícil ejecutar esto a través del módulo csv:
with open( fname, ''wb'' ) as out_file:
csv_w = csv.writer( out_file )
csv_w.writerow( columns )
for i_r in input:
csv_w.writerow( map( lambda x: i_r.get( x, "" ), columns ) )
¡Espero que esto ayude!
Una solución genérica que traduce cualquier lista json de objetos planos a csv.
Pase el archivo input.json como primer argumento en la línea de comando.
import csv, json, sys
input = open(sys.argv[1])
data = json.load(input)
input.close()
output = csv.writer(sys.stdout)
output.writerow(data[0].keys()) # header row
for row in data:
output.writerow(row.values())