Comment puis-je convertir JSON en CSV?

191

J'ai un fichier JSON que je souhaite convertir en fichier CSV. Comment puis-je faire cela avec Python?

J'ai essayé:

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

Cependant, cela n'a pas fonctionné. J'utilise Django et l'erreur que j'ai reçue est:

`file' object has no attribute 'writerow'`

J'ai ensuite essayé ce qui suit:

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)  # ← changed

f.close()

J'obtiens alors l'erreur:

`sequence expected`

Exemple de fichier 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
        }
    }
]
petit poisson
la source
1
Une approche simple consiste à utiliser jq, comme décrit ici: stackoverflow.com/questions/32960857/...
Micah Elliott
Alternative tierce: json-csv.com (pour les conversions ponctuelles) ou json-csv.com/api pour automatiser avec Python. Il s'agit d'une solution simple pour les structures JSON plus complexes.
Stack Man

Réponses:

135

Tout d'abord, votre JSON a des objets imbriqués, il ne peut donc normalement pas être directement converti en CSV. Vous devez changer cela en quelque chose comme ceci:

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

Voici mon code pour générer du CSV à partir de cela:

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

Vous obtiendrez la sortie comme:

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
TU
la source
2
c'est du travail mais désolé avant puis-je obtenir quelque chose qui ne code pas en dur je le pense mieux id je peux utiliser f.writerow (a) et le a est une variable que je déclare avant merci avant
little_fish
Pour moi, cela fonctionne presque parfaitement. Dans le CSV exporté, certains des champs sont entourés de [u'et ']. Quelle est la solution de contournement (sans post-traitement)? s'il y en a un ... :)
Dror
3
Ci-dessous, j'ai montré un moyen de le faire plus généralement, sans avoir à le coder en dur
Alec McGail
5
hé, j'ai essayé mais je reçois un TypeError: a bytes-like object is required, not 'str'atf.writerow(['pk', 'model', 'codename', 'name', 'content_type'])
Aditya Hariharan
9
pour python3 changer la ligne avec l'ouverture du fichier csv enf = csv.writer(open("test.csv", "w", newline=''))
PiotrK
128

Avec la pandas bibliothèque , c'est aussi simple que d'utiliser deux commandes!

pandas.read_json()

Pour convertir une chaîne JSON en objet pandas (une série ou une dataframe). Ensuite, en supposant que les résultats ont été stockés sous la forme df:

df.to_csv()

Ce qui peut renvoyer une chaîne ou écrire directement dans un fichier csv.

Sur la base de la verbosité des réponses précédentes, nous devrions tous remercier les pandas pour le raccourci.

vmg
la source
1
C'est une réponse fantastique (+1) - si simple et .to_csv()vraiment puissante (filtrage de colonnes gratuit, par exemple). J'ai besoin d'apprendre les pandas.
WoJ
4
Comme indiqué, cette réponse ne fonctionne pas pour les données de cette question. orient='records'doit être défini, mais chaque ligne de fieldssera toujours un dict, ce qui n'est pas ce que l'OP a demandé.
Trenton McKinney
90

Je suppose que votre fichier JSON sera décodé en une liste de dictionnaires. Nous avons d'abord besoin d'une fonction qui aplatira les objets 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

Le résultat de l'exécution de cet extrait de code sur votre objet JSON:

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

est

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

Après avoir appliqué cette fonction à chaque dict dans le tableau d'entrée des objets JSON:

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

et trouver les noms de colonnes pertinents:

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

il n'est pas difficile d'exécuter cela via le module 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 ) )

J'espère que ça aide!

Alec McGail
la source
En utilisant Python 3.6, j'ai dû faire une liste du JSON aplati pour faire fonctionner la dernière boucle: "input = list (map (lambda x: flattenjson (x," __ "), input))". Je ne comprends pas pourquoi l'itérable ne suffit pas. J'ai également dû spécifier l'encodage lors de l'ouverture du fichier de sortie car mes données utilisent UTF8. Cela a vraiment aidé, merci !!
Alexis R
C'est super, merci Alec! Je l'ai modifié pour fonctionner avec plusieurs niveaux d'imbrication: stackoverflow.com/a/57228641/473201
phreakhead
36

JSON peut représenter une grande variété de structures de données - un "objet" JS est à peu près comme un dict Python (avec des clés de chaîne), un "tableau" JS à peu près comme une liste Python, et vous pouvez les imbriquer aussi longtemps que le final " Les éléments "leaf" sont des nombres ou des chaînes.

CSV ne peut essentiellement représenter qu'un tableau 2D - éventuellement avec une première ligne d '"en-têtes", c'est-à-dire des "noms de colonnes", ce qui peut rendre le tableau interprétable comme une liste de dictionnaires, au lieu de l'interprétation normale, une liste de listes (encore une fois, les éléments «feuille» peuvent être des nombres ou des chaînes).

Ainsi, dans le cas général, vous ne pouvez pas traduire une structure JSON arbitraire en CSV. Dans quelques cas particuliers, vous pouvez (tableau de tableaux sans autre imbrication; tableaux d'objets qui ont tous exactement les mêmes clés). Quel cas particulier, le cas échéant, s'applique à votre problème? Les détails de la solution dépendent du cas particulier que vous avez. Étant donné le fait étonnant que vous ne mentionnez même pas lequel s'applique, je suppose que vous n'avez peut-être pas considéré la contrainte, aucun cas utilisable ne s'applique en fait, et votre problème est impossible à résoudre. Mais veuillez clarifier!

Alex Martelli
la source
C'est la meilleure réponse. J'ai essayé plusieurs fois un convertisseur JSON en CSV généralisé. Même avec des contraintes importantes, comme exiger un fichier de configuration qui donne une entrée sémantique à l'utilisateur, ou plusieurs fichiers de sortie qui se décomposent en plusieurs CSV. Même avec ces ajouts libéraux, je pense qu'il n'y a pas d'algorithme général pour convertir arbitraire JSON en CSV.
James Madison
31

Une solution générique qui convertit toute liste json d' objets plats en csv.

Passez le fichier input.json comme premier argument sur la ligne de commande.

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())
Mike Repass
la source
2
Un commentaire important - ce code déduit les colonnes / en-têtes des champs de la toute première ligne. Si vos données json ont des colonnes «dentelées», c'est-à-dire que row1 a 5 colonnes mais que row2 a 6 colonnes, alors vous devez faire un premier passage sur les données pour obtenir l'ensemble total de toutes les colonnes et l'utiliser comme en-têtes.
Mike Repass
Avec les données que j'avais, c'était une grande partie de la solution dont j'avais besoin, car mon JSON n'était pas irrégulier, cela fonctionnait à merveille avec quelques légers ajustements pour la sortie puisque je l'exécutais dans un script existant.
MichaelF
1
Ce code suppose également que les valeurs seront sorties dans le même ordre que les clés de la ligne d'en-tête. Bien que cela ait fonctionné par chance, ce n'est en aucun cas garanti.
RyanHennig
Obtention d'une erreur d'encodage. Une idée comment ajouter un encodage à utf-8?
Elad Tabak
26

Ce code devrait fonctionner pour vous, en supposant que vos données JSON se trouvent dans un fichier appelé 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)
Dan Loewenherz
la source
1
Hmmm, non - csv_file.writerow(il n'y a pas f.writerowbien sûr, je suppose que vous avez fait une faute de frappe ici!) Veut une séquence, pas un dict - et dans votre exemple, chaque élément est un dict. Cela fonctionnerait pour l'autre cas spécial, comme je l'ai identifié dans ma réponse - où le fichier JSON a un tableau de tableaux; cela ne fonctionne pas pour un tableau d'objets, ce qui est le cas particulier que vous semblez essayer de résoudre (celui-ci nécessite un csv.DictWriter- et bien sûr vous devez extraire les noms de champ et décider d'un ordre afin de l'instancier ! -).
Alex Martelli
@DanLoewenherz Cela ne fonctionne pas sur les versions récentes de Python. TypeError: peut uniquement concaténer la liste (pas "dict_values") à la liste
Apolo Radomer
1
Réponse parfaite.
Akshat Gupta
18

Ce sera facile à utiliser csv.DictWriter(), l'implémentation détaillée peut être comme ceci:

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

Notez que cela suppose que tous vos objets JSON ont les mêmes champs.

Voici la référence qui peut vous aider.

RetourHttp402
la source
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien pour référence. Les réponses aux liens uniquement peuvent devenir invalides si la page liée change. - De l'avis
Mathieu
3
@purplepsycho J'ai trouvé cette réponse avec un vote négatif, qui méritait d'être un lien uniquement. Le nouvel utilisateur, qui ne savait peut-être pas que le lien n'est pas une bonne réponse, a corrigé cela. J'ai voté pour; peut-être pourriez-vous aussi encourager le nouvel utilisateur à continuer à participer à notre communauté?
Mawg dit de réintégrer Monica le
7

Utiliser à json_normalizepartir de pandas:

  • Compte tenu des données fournies, dans un fichier nommé test.json.
  • encoding='utf-8' peut ne pas être nécessaire.
  • Le code suivant tire parti de la pathlibbibliothèque.
  • .openest une méthode de pathlib.
  • Fonctionne également avec les chemins non Windows.
import pandas as pd
# As of Pandas 1.01, json_normalize as pandas.io.json.json_normalize is deprecated and is now exposed in the top-level namespace.
# from pandas.io.json import json_normalize
from pathlib import Path
import json

# set path to file
p = Path(r'c:\some_path_to_file\test.json')

# read json
with p.open('r', encoding='utf-8') as f:
    data = json.loads(f.read())

# create dataframe
df = pd.json_normalize(data)

# dataframe view
 pk            model  fields.codename           fields.name  fields.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
  4  auth.permission        add_group         Can add group                    2
 10  auth.permission      add_message       Can add message                    4

# save to csv
df.to_csv('test.csv', index=False, encoding='utf-8')

Sortie CSV:

pk,model,fields.codename,fields.name,fields.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
4,auth.permission,add_group,Can add group,2
10,auth.permission,add_message,Can add message,4

Autres ressources pour les objets JSON plus fortement imbriqués:

Trenton McKinney
la source
6

J'avais des problèmes avec la solution proposée par Dan , mais cela a fonctionné pour moi:

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

Où "test.json" contenait les éléments suivants:

[ 
{"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 } }
]
Amanda
la source
Erreur en essayant votre programme sur vos exemples de données C: \ curl> python json2csv.py Traceback (dernier appel en dernier): Fichier "json2csv.py", ligne 11, dans <module> f.writerow ([item ['pk '], item [' model ']] + item [' fields ']. values ​​()) TypeError: peut seulement concaténer la liste (pas "dict_values") à la liste
Mian Asbat Ahmad
Je l'ai réessayé tout à l'heure en Python 2.7.9 et cela fonctionne très bien pour moi.
Amanda
4

Comme mentionné dans les réponses précédentes, la difficulté de convertir json en csv est qu'un fichier json peut contenir des dictionnaires imbriqués et donc être une structure de données multidimensionnelle vers un csv qui est une structure de données 2D. Cependant, un bon moyen de transformer une structure multidimensionnelle en csv est d'avoir plusieurs csv qui sont liés aux clés primaires.

Dans votre exemple, la première sortie csv a les colonnes "pk", "model", "fields" comme colonnes. Les valeurs de "pk" et "model" sont faciles à obtenir, mais comme la colonne "fields" contient un dictionnaire, il doit s'agir de son propre csv et comme "codename" semble être la clé primaire, vous pouvez l'utiliser comme entrée pour "champs" pour compléter le premier csv. Le second csv contient le dictionnaire de la colonne "champs" avec le nom de code comme clé primaire qui peut être utilisée pour lier les 2 csv ensemble.

Voici une solution pour votre fichier json qui convertit un dictionnaire imbriqué 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")
dmathewwws
la source
4

Je sais que cela fait longtemps que cette question n'a pas été posée, mais j'ai pensé que je pourrais ajouter à la réponse de tout le monde et partager un article de blog qui, je pense, explique la solution de manière très concise.

Voici le lien

Ouvrez un fichier pour l'écriture

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

Créer l'objet écrivain 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())

Assurez-vous de fermer le fichier afin d'enregistrer le contenu

employ_data.close()
user3768804
la source
3

Ce n'est pas une façon très intelligente de le faire, mais j'ai eu le même problème et cela a fonctionné pour moi:

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()
Mulder1
la source
3

La réponse d'Alec est excellente, mais elle ne fonctionne pas dans le cas où il y a plusieurs niveaux d'imbrication. Voici une version modifiée qui prend en charge plusieurs niveaux d'imbrication. Cela rend également les noms d'en-tête un peu plus agréables si l'objet imbriqué spécifie déjà sa propre clé (par exemple, les données 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 is 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')

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

  print "Exporting to CSV..."
  outfilename = filename + '.csv'
  count = 0
  with open(outfilename, 'w') as file:
    csvwriter = csv.DictWriter(file, fieldnames=fieldnames)
    csvwriter.writeheader()
    for obj in allRows:
      # print 'allRows:\n'
      # print obj
      csvwriter.writerow(obj)
      count += 1

  print "Wrote %d rows" % count



if __name__ == '__main__':
  main(sys.argv)
phreakhead
la source
2

Cela fonctionne relativement bien. Il aplatit le json pour l'écrire dans un fichier csv. Les éléments imbriqués sont gérés :)

C'est pour 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)

prendre plaisir.

Loïc
la source
Le fichier .csv n'a pas été généré, à la place, le texte csv a été envoyé à la console. De plus, cela json.loadsne fonctionnait pas, je l'ai fait fonctionner avec json.load, ce qui donne bien un objet de liste. Troisièmement, les éléments imbriqués ont été perdus.
ZygD
2

Ma façon simple de résoudre ceci:

Créez un nouveau fichier Python comme: json_to_csv.py

Ajoutez ce code:

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

Après avoir ajouté ce code, enregistrez le fichier et exécutez sur le terminal:

python json_to_csv.py input.txt output.csv

J'espère que cela vous aidera.

À PLUS!

Gabriel Pires
la source
1
Cet échantillon fonctionne comme un charme! merci pour le partage j'ai pu convertir mon fichier json en CSV en utilisant ce script python
Mostafa
2

Étonnamment, j'ai trouvé qu'aucune des réponses publiées ici jusqu'à présent ne traite correctement tous les scénarios possibles (par exemple, dictionnaires imbriqués, listes imbriquées, valeurs Aucune, etc.).

Cette solution doit fonctionner dans tous les scénarios:

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
Max Berman
la source
2

Essaye ça

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())
Hasee Amarathunga
la source
2

Ce code fonctionne pour n'importe quel fichier json donné

# -*- 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()
Ram Prajapati
la source
Tout fichier JSON qui ne contient pas de listes.
Yagizcan Degirmenci
1

Modification de la réponse d'Alec McGail pour prendre en charge JSON avec des listes à l'intérieur

    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

Merci!

Sawan Vaidya
la source
1
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)
Dnyaneshwar Shendurwadkar
la source
1

Si nous considérons l'exemple ci-dessous pour convertir le fichier au format json en fichier au format csv.

{
 "item_data" : [
      {
        "item": "10023456",
        "class": "100",
        "subclass": "123"
      }
      ]
}

Le code ci-dessous convertira le fichier json (data3.json) en fichier csv (data3.csv).

import json
import csv
with open("/Users/Desktop/json/data3.json") as file:
    data = json.load(file)
    file.close()
    print(data)

fname = "/Users/Desktop/json/data3.csv"

with open(fname, "w", newline='') as file:
    csv_file = csv.writer(file)
    csv_file.writerow(['dept',
                       'class',
                       'subclass'])
    for item in data["item_data"]:
         csv_file.writerow([item.get('item_data').get('dept'),
                            item.get('item_data').get('class'),
                            item.get('item_data').get('subclass')])

Le code mentionné ci-dessus a été exécuté dans le pycharm installé localement et il a réussi à convertir le fichier json en fichier csv. J'espère que cette aide pour convertir les fichiers.

SABYASACHI SAHA
la source
0

Puisque les données semblent être dans un format de dictionnaire, il semblerait que vous devriez réellement utiliser csv.DictWriter () pour produire réellement les lignes avec les informations d'en-tête appropriées. Cela devrait permettre de gérer un peu plus facilement la conversion. Le paramètre fieldnames définirait alors l'ordre correctement tandis que la sortie de la première ligne comme en-têtes lui permettrait d'être lu et traité plus tard par csv.DictReader ().

Par exemple, Mike Repass a utilisé

output = csv.writer(sys.stdout)

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

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

Cependant, changez simplement la configuration initiale en output = csv.DictWriter (filesetting, fieldnames = data [0] .keys ())

Notez que puisque l'ordre des éléments dans un dictionnaire n'est pas défini, vous devrez peut-être créer des entrées de noms de champs explicitement. Une fois que vous faites cela, l'écrivain fonctionnera. Les écritures fonctionnent alors comme indiqué à l'origine.

sabbahillel
la source
0

Malheureusement, je n'ai pas assez de réputation pour apporter une petite contribution à l'incroyable réponse @Alec McGail. J'utilisais Python3 et j'ai dû convertir la carte en une liste à la suite du commentaire @Alexis R.

De plus, j'ai trouvé que l'écrivain csv ajoutait un CR supplémentaire au fichier (j'ai une ligne vide pour chaque ligne avec des données dans le fichier csv). La solution était très simple suite à la réponse de @Jason R. Coombs à ce fil: CSV en Python ajoutant un retour chariot supplémentaire

Vous devez simplement ajouter le paramètre lineterminator = '\ n' au csv.writer. Ce sera:csv_w = csv.writer( out_file, lineterminator='\n' )

Derwyddon
la source
0

Vous pouvez utiliser ce code pour convertir un fichier json en fichier csv Après avoir lu le fichier, je convertis l'objet en pandas dataframe, puis je l'enregistre dans un fichier 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)
Terminator17
la source
cela ne prend pas en compte les sous-champs (tels que les "champs" dans l'exemple) - le sous-objet est dans une colonne au lieu de son contenu séparé en colonnes individuelles également.
Cribber
0

Je suis peut-être en retard à la fête, mais je pense que j'ai traité le même problème. J'avais un fichier json qui ressemblait à ceci

Structure de fichier JSON

Je voulais seulement extraire quelques clés / valeurs de ces fichiers json. Donc, j'ai écrit le code suivant pour extraire le même.

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

J'espère que cela aidera. Pour plus de détails sur le fonctionnement de ce code, vous pouvez vérifier ici

Udit Hari Vashisht
la source
0

Ceci est une modification de la réponse de @ MikeRepass. Cette version écrit le CSV dans un fichier et fonctionne à la fois pour Python 2 et Python 3.

import csv,json
input_file="data.json"
output_file="data.csv"
with open(input_file) as f:
    content=json.load(f)
try:
    context=open(output_file,'w',newline='') # Python 3
except TypeError:
    context=open(output_file,'wb') # Python 2
with context as file:
    writer=csv.writer(file)
    writer.writerow(content[0].keys()) # header row
    for row in content:
        writer.writerow(row.values())
cowlinator
la source