Domanda

Ho un file JSON che voglio convertirlo in un file CSV. Come posso fare questo con Python?

ho provato:

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

Tuttavia, non ha funzionato. Sto usando Django e l'errore che ho ricevuto è:

file' object has no attribute 'writerow'

Così, poi ho provato il seguente:

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

Allora ottengo l'errore:

sequence expected

Esempio di file 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
    }
  }
]

Nessuna soluzione corretta

Altri suggerimenti

Non sono sicuro che questa domanda è risolto già o no, ma mi permetta di incollare quello che ho fatto per riferimento.

In primo luogo, la vostra JSON è annidato oggetti, in modo che di norma non può essere direttamente convertiti in formato CSV. È necessario cambiare la situazione a qualcosa di simile:

{
    "pk": 22,
    "model": "auth.permission",
    "codename": "add_logentry",
    "content_type": 8,
    "name": "Can add log entry"
},
......]

Ecco il mio codice per generare CSV da questo:

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

Si otterrà in uscita come:

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 , questo è facile come usare due comandi!

pandas.read_json()

Per convertire una stringa JSON in un oggetto panda (o una serie o dataframe). Quindi, supponendo che i risultati sono stati memorizzati come df:

df.to_csv()

Che può o restituire una stringa o scrivere direttamente a un file CSV.

Sulla base del livello di dettaglio delle risposte precedenti, dovremmo tutti ringraziare il panda per il collegamento.

Io parto dal presupposto che il file JSON decodifica in una lista di dizionari. In primo luogo abbiamo bisogno di una funzione che appiattire gli oggetti 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

Il risultato dell'esecuzione di questo frammento sul vostro oggetto JSON:

flattenjson( {
    "pk": 22, 
    "model": "auth.permission", 
    "fields": {
      "codename": "add_message", 
      "name": "Can add message", 
      "content_type": 8
    }
  }, "__" )

è

{
    "pk": 22, 
    "model": "auth.permission', 
    "fields__codename": "add_message", 
    "fields__name": "Can add message", 
    "fields__content_type": 8
}

Dopo aver applicato questa funzione per ciascun dict nell'array ingresso di oggetti JSON:

input = map( lambda x: flattenjson( x, "__" ), input )

e di trovare i nomi delle colonne rilevanti:

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

non è difficile eseguire questo attraverso il modulo 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 ) )

Spero che questo aiuta!

JSON può rappresentare una vasta gamma di strutture di dati - un "oggetto" JS è più o meno come un dict Python (con le chiavi ad arco), un JS "allineamento" più o meno come una lista Python, ed è possibile nidificare loro il più a lungo gli elementi finali "foglia" sono numeri o stringhe.

CSV può essenzialmente rappresentare solamente una tabella 2-D - opzionalmente con una prima fila di "header", cioè "nomi colonna", che può rendere il tavolo interpretabile come un elenco di dicts, invece dell'interpretazione normale, una lista di liste (ancora una volta, gli elementi "foglia" possono essere numeri o stringhe).

Quindi, nel caso generale, non è possibile tradurre una struttura arbitraria JSON in un file CSV. In alcuni casi particolari si può (array di array senza ulteriore annidamento matrici di oggetti che sono tutti esattamente le stesse chiavi). Quale caso particolare, se del caso, si applica al tuo problema? I dettagli della soluzione dipendono dal caso particolare si ha. Dato il fatto sorprendente che non hanno nemmeno menziona quale si applica, ho il sospetto che non può avere considerato il vincolo, nessuno dei due casi si applica utilizzabile in realtà, e il problema è impossibile da risolvere. Ma per favore chiarire!

Una soluzione generica che si traduce ogni lista JSON di piatto gli oggetti in formato CSV.

passare il file input.json come primo argomento sulla linea di 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())

Questo codice dovrebbe funzionare per voi, supponendo che i dati JSON è in un file chiamato 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)

Sarà facile da usare csv.DictWriter(), l'attuazione dettagliata può essere in questo modo:

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

Si noti che questo presuppone che tutti i tuoi oggetti JSON hanno gli stessi campi.

Ecco il riferimento che possono aiutare.

ho avuto problemi con di Dan soluzione proposta , ma questo ha funzionato per me:

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

Dove "test.json" conteneva la seguente:

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

Come accennato nelle risposte precedenti la difficoltà nel convertire JSON in formato CSV è perché un file JSON può contenere dizionari annidate e quindi essere una struttura di dati multidimensionale versetti un csv, che è una struttura di dati 2D. Tuttavia, un buon modo per trasformare una struttura multidimensionale di un csv è quello di avere più CSVs che legano insieme con chiavi primarie.

Nel tuo esempio, la prima uscita CSV ha il colonne "pk", "modello", "campi", come le colonne. I valori per "pk", e "modello" sono facili da ottenere, ma perché la colonna "campi" contiene un dizionario, che dovrebbe essere il suo csv e perché "nome in codice" appare a essere la chiave primaria, è possibile utilizzare come ingresso per i "campi" per completare la prima csv. Il secondo csv contiene il dizionario dalla colonna "campi" con codename come la chiave primaria che può essere utilizzata per legare le 2 CSVs insieme.

Ecco una soluzione per il file JSON che converte un dizionari annidati 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")

Lo so che è stato un lungo periodo di tempo dal momento che questo problema è stato fatto, ma ho pensato che avrei potuto aggiungere alla risposta di tutti gli altri e condividere un post sul blog che penso spiegare la soluzione in un modo molto conciso.

Ecco il link

Aprire un file per la scrittura

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

Crea l'oggetto csv scrittore

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

Assicurarsi di chiudere il file, al fine di salvare il contenuto

employ_data.close()

Questo funziona relativamente bene. Si appiattisce la JSON di scrivere in un file CSV. elementi nidificati vengono gestiti:)

Questo è per 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)

godere.

Il mio modo semplice per risolvere questo:

Creare un nuovo file Python come: json_to_csv.py

Aggiungi questo codice:

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

Dopo aggiungere questo codice, salvare il file ed eseguire al terminale:

  

Python json_to_csv.py input.txt output.csv

Spero che questo aiuto.

SeeYa!

Non è un modo molto intelligente per farlo, ma ho avuto lo stesso problema e questo ha funzionato per me:

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

Modificata la risposta di Alec McGail per sostenere JSON con le liste all'interno

    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

Grazie!

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)

Prova questo

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

Questo codice funziona per qualsiasi dato file json

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

di Alec risposta è grande, ma non funziona nel caso in cui ci sono più livelli di nidificazione. Ecco una versione modificata che supporta più livelli di nidificazione. Rende anche i nomi di intestazione di un po 'più bello se l'oggetto nidificato specifica già la propria chiave (per esempio dati 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)

Poiché i dati sembra essere in un formato dizionario, sembrerebbe che si dovrebbe effettivamente utilizzare csv.DictWriter () per realtà di uscita le linee con le informazioni di intestazione appropriata. Ciò dovrebbe consentire la conversione da movimentare un po 'più facile. Il parametro fieldnames sarebbe quindi impostare l'ordine corretto mentre l'uscita della prima linea le intestazioni consentirebbe di essere letto ed elaborato successivamente da csv.DictReader ().

Per esempio, Mike Repass utilizzato

output = csv.writer(sys.stdout)

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

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

Tuttavia basta cambiare la configurazione iniziale di     output = csv.DictWriter (filesetting, fieldnames = data [0] .keys ())

Si noti che, poiché l'ordine degli elementi in un dizionario non è definita, potrebbe essere necessario creare FieldNames voci in modo esplicito. Una volta fatto questo, il writerow funzionerà. Le operazioni di scrittura poi lavorare come originariamente indicato.

Purtroppo non ho enouthg reputazione di dare un piccolo contributo alla straordinaria risposta @Alec McGail. Stavo usando python3 e ho avuto bisogno di convertire la mappa per un elenco, dopo il commento @Alexis R.

Additionaly ho trovato lo scrittore csv stava aggiungendo un CR in più per il file (ho una riga vuota per ogni linea con i dati all'interno del file CSV). La soluzione è stata molto semplice seguendo la risposta @ Jason R. Coombs a questa discussione: CSV in Python l'aggiunta di un ritorno a capo in più

È necessario aggiungere semplicemente il lineterminator = 'n \' parametro al csv.writer. Sarà: csv_w = csv.writer( out_file, lineterminator='\n' )

A sorpresa, ho scoperto che nessuna delle risposte postato qui in modo affare molto correttamente con tutti gli scenari possibili (ad esempio, dicts nidificati, liste nidificate, i valori None, ecc).

Questa soluzione dovrebbe funzionare su tutti gli scenari:

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

È possibile utilizzare questo codice per convertire un file JSON in un file CSV Dopo aver letto il file, sto convertendo l'oggetto da panda dataframe e quindi salvare questo in un file 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)

potrei essere in ritardo alla festa, ma penso, ho affrontato il problema simile. Ho avuto un file JSON che si presentava così

File JSON Struttura

Volevo solo estrarre chiavi / valori pochi da queste file di JSON. Così, ho scritto il seguente codice per estrarre la stessa.

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

Spero che questo vi aiuterà. Per i dettagli su come questo lavoro di codice è possibile controllare qui

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top