Pregunta

Tengo un archivo JSON que quiero para convertir a un archivo CSV. ¿Cómo puedo hacer esto con Python?

He intentado:

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 he recibido es:

file' object has no attribute 'writerow'

Así que, a continuación, He intentado 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()

A continuación, me sale el error:

sequence expected

archivo JSON de la muestra:

[
  {
    "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
    }
  }
]

No hay solución correcta

Otros consejos

No estoy seguro de que esta cuestión se resuelve ya o no, pero me deja pegar lo que he hecho referencia.

En primer lugar, su JSON ha anidado objetos, por lo que normalmente no se pueden convertir directamente a CSV. Es necesario cambiarlo 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 desde que:

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"]])

Usted recibirá salida 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

Con la pandas , esto es tan fácil como usar dos comandos!

pandas.read_json()

Para convertir una cadena JSON a un objeto de pandas (ya sea una serie o trama de datos). Entonces, suponiendo que los resultados se almacenan como df:

df.to_csv()

¿Qué puede devolver una cadena o escribir directamente a un archivo csv.

Con base en el nivel de detalle de las respuestas anteriores, todos deberíamos agradecer a los pandas para el acceso directo.

Estoy asumiendo que su archivo JSON decodificará en una lista de diccionarios. Primero necesitamos una función que aplanar 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 las columnas correspondientes:

columns = [ x for row in input for x in row.keys() ]
columns = list( set( columns ) )

que no es difícil de ejecutar este 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!

JSON puede representar una amplia variedad de estructuras de datos - un "objeto" JS es más o menos como un diccionario de Python (con claves de cadena), un JS "matriz" más o menos como una lista de Python, y puede anidar ellos, siempre y cuando los elementos finales "hoja" son números o cadenas.

CSV puede representar esencialmente sólo una tabla de 2-D - opcionalmente con una primera fila de "cabeceras", es decir, "los nombres de columna", que puede hacer que la tabla interpretable como una lista de dicts, en lugar de la interpretación normal, una lista de listas (de nuevo, elementos "hoja" pueden ser números o cadenas).

Por lo tanto, en el caso general, no se puede traducir una estructura JSON arbitraria a un archivo CSV. En unos pocos casos especiales que puede (matriz de matrices sin más anidación; matrices de objetos que todos tienen exactamente las mismas teclas). Cuyo caso especial, en su caso, se aplica a su problema? Los detalles de la solución dependen de qué caso especial que tienen. Dado el sorprendente hecho de que ni siquiera se menciona que se aplica uno, sospecho que no puede haber considerado la restricción, ninguno de los casos que puedan utilizarse en la práctica se aplica, y su problema es imposible de resolver. Pero por favor aclarar!

Una solución genérica que se traduce cualquier lista de JSON plana objetos a CSV.

Pase el archivo input.json como primer argumento en la línea de comandos.

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())

Este código debe trabajar para usted, en el supuesto de que los datos JSON se encuentra 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:
        fields = list(item['fields'].values())
        csv_file.writerow([item['pk'], item['model']] + fields)

Será fácil de usar csv.DictWriter(), la aplicación detallada puede ser como la siguiente:

def read_json(filename):
    return json.loads(open(filename).read())
def write_csv(data,filename):
    with open(filename, 'w+') 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á el referencia que pueden ayudarle.

Yo estaba teniendo problemas con de Dan solución propuesta , 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 } }
]

Como se menciona en las respuestas anteriores la dificultad en la conversión de JSON a csv es porque un archivo JSON puede contener diccionarios anidados y por lo tanto ser una estructura de datos multidimensional versos un csv que es una estructura de datos 2D. Sin embargo, una buena manera de convertir una estructura multidimensional a un csv es tener múltiples CSV que atan junto con las claves primarias.

En el ejemplo, la primera salida CSV tiene la columnas "PK", "modelo", "campos" como sus columnas. Los valores para "PK" y "modelo" son fáciles de conseguir, pero debido a que la columna de "campos" contiene un diccionario, que debería ser su propio csv y porque "nombre en clave" aparece al ser la clave primaria, se puede utilizar como entrada para "campos" para completar la primera csv. El segundo csv contiene el diccionario de la columna de "campos" con nombre en clave como el de la clave principal que se puede utilizar para atar las 2 CSVs juntos.

Aquí es una solución para el archivo JSON que convierte a los diccionarios anidados a 2 CSV.

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")

Sé que ha pasado mucho tiempo desde que esta pregunta se ha hecho, pero pensé que podría añadir a la respuesta de todos los demás y compartir un blog que creo que explica la solución de una manera muy concisa.

Aquí está el enlace

Abrir un archivo para escritura

employ_data = open('/tmp/EmployData.csv', 'w')

Crea 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 con el fin de guardar el contenido

employ_data.close()

Esto funciona relativamente bien. Se aplana el JSON para escribirlo en un archivo csv. elementos anidados se gestionan:)

Esto 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.

Mi forma sencilla de resolver esto:

Crear un nuevo archivo de Python como: json_to_csv.py

Añadir 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 añadir este código, guardar el archivo y ejecutar en el terminal:

  

pitón json_to_csv.py entrada.txt OUTPUT.CSV

Espero que esto te ayude.

seeya!

No es una manera muy inteligente de hacerlo, pero he tenido el mismo problema y esta trabajado 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()

Modificado respuesta de Alec McGail para apoyar 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!

import json,csv
t=''
t=(type('a'))
json_data = []
data = None
write_header = True
item_keys = []
try:
with open('kk.json') as json_file:
    json_data = json_file.read()

    data = json.loads(json_data)
except Exception as e:
    print( e)

with open('bar.csv', 'at') as csv_file:
    writer = csv.writer(csv_file)#, quoting=csv.QUOTE_MINIMAL)
    for item in data:
        item_values = []
        for key in item:
            if write_header:
                item_keys.append(key)
            value = item.get(key, '')
            if (type(value)==t):
                item_values.append(value.encode('utf-8'))
            else:
                item_values.append(value)
        if write_header:
            writer.writerow(item_keys)
            write_header = False
        writer.writerow(item_values)

Probar

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 item in data:
    output.writerow(item.values())

Este código funciona para cualquier archivo JSON dada

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 17 20:35:35 2019
author: Ram
"""

import json
import csv

with open("file1.json") as file:
    data = json.load(file)



# create the csv writer object
pt_data1 = open('pt_data1.csv', 'w')
csvwriter = csv.writer(pt_data1)

count = 0

for pt in data:

      if count == 0:

             header = pt.keys()

             csvwriter.writerow(header)

             count += 1

      csvwriter.writerow(pt.values())

pt_data1.close()

de Alec respuesta es grande, pero no funciona en el caso en que hay múltiples niveles de anidamiento. Aquí está una versión modificada que soporta múltiples niveles de anidamiento. También hace que los nombres de encabezado de un poco más agradable si el objeto anidado ya especifica su propia clave (datos por ejemplo Firebase Analytics / BigTable / BigQuery):

"""Converts JSON with nested fields into a flattened CSV file.
"""

import sys
import json
import csv
import os

import jsonlines

from orderedset import OrderedSet

# from https://stackoverflow.com/a/28246154/473201
def flattenjson( b, prefix='', delim='/', val=None ):
  if val == None:
    val = {}

  if isinstance( b, dict ):
    for j in b.keys():
      flattenjson(b[j], prefix + delim + j, delim, val)
  elif isinstance( b, list ):
    get = b
    for j in range(len(get)):
      key = str(j)

      # If the nested data contains its own key, use that as the header instead.
      if isinstance( get[j], dict ):
        if 'key' in get[j]:
          key = get[j]['key']

      flattenjson(get[j], prefix + delim + key, delim, val)
  else:
    val[prefix] = b

  return val

def main(argv):
  if len(argv) < 2:
    raise Error('Please specify a JSON file to parse')

  filename = argv[1]
  allRows = []
  fieldnames = OrderedSet()
  with jsonlines.open(filename) as reader:
    for obj in reader:
      #print obj
      flattened = flattenjson(obj)
      #print 'keys: %s' % flattened.keys()
      fieldnames.update(flattened.keys())
      allRows.append(flattened)

  outfilename = filename + '.csv'
  with open(outfilename, 'w') as file:
    csvwriter = csv.DictWriter(file, fieldnames=fieldnames)
    csvwriter.writeheader()
    for obj in allRows:
      csvwriter.writerow(obj)



if __name__ == '__main__':
  main(sys.argv)

Dado que los datos parece estar en un formato de diccionario, parecería que en realidad se debe utilizar csv.DictWriter () para realmente salida de las líneas con la información del encabezado apropiado. Esto debería permitir la conversión a manipular algo más fácil. El parámetro de nombres de campo sería a continuación, establecer el orden correctamente mientras que la salida de la primera línea como las cabeceras permitiría que se pueda leer y se procesa más tarde por csv.DictReader ().

Por ejemplo, Mike Repasar utiliza

output = csv.writer(sys.stdout)

output.writerow(data[0].keys())  # header row

for row in data:
  output.writerow(row.values())

Sin embargo basta con cambiar la configuración inicial de     salida = csv.DictWriter (filesetting, nombres de campo = datos [0] .keys ())

Tenga en cuenta que, dado que el orden de los elementos en un diccionario no está definida, puede que tenga que crear entradas FieldNames explícitamente. Vez hecho esto, el writerow funcionará. Las escrituras a continuación funcionan como se muestra en un principio.

Por desgracia no he enouthg reputación de hacer una pequeña contribución a la increíble respuesta @Alec McGail. Yo estaba usando python3 y he necesaria para convertir el mapa para una lista siguiendo el comentario @Alexis R.

Adicionalmente he encontrado el escritor csv estaba añadiendo un CR extra para el archivo (tengo una línea en blanco para cada línea con los datos dentro del archivo CSV). La solución fue muy fácil después de la respuesta @ Jason R. Coombs a este tema: en Python adición de un retorno de carro adicional

Es necesario simplemente añadir el = 'n \' parámetro lineterminator a la csv.writer. Será: csv_w = csv.writer( out_file, lineterminator='\n' )

Sorprendentemente, he encontrado que ninguna de las respuestas publicadas aquí tan lejos tratar correctamente con todos los escenarios posibles (por ejemplo, predice anidadas, listas anidadas, valores Ninguno, etc.).

Esta solución debe trabajar en todos los escenarios:

def flatten_json(json):
    def process_value(keys, value, flattened):
        if isinstance(value, dict):
            for key in value.keys():
                process_value(keys + [key], value[key], flattened)
        elif isinstance(value, list):
            for idx, v in enumerate(value):
                process_value(keys + [str(idx)], v, flattened)
        else:
            flattened['__'.join(keys)] = value

    flattened = {}
    for key in json.keys():
        process_value([key], json[key], flattened)
    return flattened

Puede utilizar este código para convertir un archivo JSON a archivo csv Después de leer el archivo, estoy convirtiendo el objeto de trama de datos pandas y luego guardarlo en un archivo CSV

import os
import pandas as pd
import json
import numpy as np

data = []
os.chdir('D:\\Your_directory\\folder')
with open('file_name.json', encoding="utf8") as data_file:    
     for line in data_file:
        data.append(json.loads(line))

dataframe = pd.DataFrame(data)        
## Saving the dataframe to a csv file
dataframe.to_csv("filename.csv", encoding='utf-8',index= False)

Puede ser que sea tarde a la fiesta, pero creo, he tratado el problema similar. Tenía un archivo JSON, que se veía así

JSON Estructura de archivos

Sólo quería extraer algunas claves / valores de estos archivos JSON. Por lo tanto, escribí el siguiente código para extraer la misma.

    """json_to_csv.py
    This script reads n numbers of json files present in a folder and then extract certain data from each file and write in a csv file.
    The folder contains the python script i.e. json_to_csv.py, output.csv and another folder descriptions containing all the json files.
"""

import os
import json
import csv


def get_list_of_json_files():
    """Returns the list of filenames of all the Json files present in the folder
    Parameter
    ---------
    directory : str
        'descriptions' in this case
    Returns
    -------
    list_of_files: list
        List of the filenames of all the json files
    """

    list_of_files = os.listdir('descriptions')  # creates list of all the files in the folder

    return list_of_files


def create_list_from_json(jsonfile):
    """Returns a list of the extracted items from json file in the same order we need it.
    Parameter
    _________
    jsonfile : json
        The json file containing the data
    Returns
    -------
    one_sample_list : list
        The list of the extracted items needed for the final csv
    """

    with open(jsonfile) as f:
        data = json.load(f)

    data_list = []  # create an empty list

    # append the items to the list in the same order.
    data_list.append(data['_id'])
    data_list.append(data['_modelType'])
    data_list.append(data['creator']['_id'])
    data_list.append(data['creator']['name'])
    data_list.append(data['dataset']['_accessLevel'])
    data_list.append(data['dataset']['_id'])
    data_list.append(data['dataset']['description'])
    data_list.append(data['dataset']['name'])
    data_list.append(data['meta']['acquisition']['image_type'])
    data_list.append(data['meta']['acquisition']['pixelsX'])
    data_list.append(data['meta']['acquisition']['pixelsY'])
    data_list.append(data['meta']['clinical']['age_approx'])
    data_list.append(data['meta']['clinical']['benign_malignant'])
    data_list.append(data['meta']['clinical']['diagnosis'])
    data_list.append(data['meta']['clinical']['diagnosis_confirm_type'])
    data_list.append(data['meta']['clinical']['melanocytic'])
    data_list.append(data['meta']['clinical']['sex'])
    data_list.append(data['meta']['unstructured']['diagnosis'])
    # In few json files, the race was not there so using KeyError exception to add '' at the place
    try:
        data_list.append(data['meta']['unstructured']['race'])
    except KeyError:
        data_list.append("")  # will add an empty string in case race is not there.
    data_list.append(data['name'])

    return data_list


def write_csv():
    """Creates the desired csv file
    Parameters
    __________
    list_of_files : file
        The list created by get_list_of_json_files() method
    result.csv : csv
        The csv file containing the header only
    Returns
    _______
    result.csv : csv
        The desired csv file
    """

    list_of_files = get_list_of_json_files()
    for file in list_of_files:
        row = create_list_from_json(f'descriptions/{file}')  # create the row to be added to csv for each file (json-file)
        with open('output.csv', 'a') as c:
            writer = csv.writer(c)
            writer.writerow(row)
        c.close()


if __name__ == '__main__':
    write_csv()

Espero que esto ayude. Para detalles sobre cómo funciona este código se puede comprobar aquí

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top