Jak przekonwertować JSON na CSV?


184

Mam plik JSON, który chcę przekonwertować na plik CSV. Jak mogę to zrobić za pomocą Pythona?

Próbowałem:

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

Jednak to nie zadziałało. Używam Django, a otrzymany błąd to:

file' object has no attribute 'writerow'

Następnie spróbowałem:

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

Pojawia się błąd:

sequence expected

Przykładowy plik 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
        }
    }
]

1
csv_file.writerow (item) wymaga, aby element był prostą listą ciągów lub liczb. Spróbuj przekonwertować każdy obiekt json na płaską listę, np. {„Pk”: 22, „model”: „auth.permission”} zmieni się w [22, auth.permission].
Suppressingfire,

1
Proste podejście do tego jest takie jq, jak opisano tutaj: stackoverflow.com/questions/32960857/…
Micah Elliott

Alternatywa innej firmy: json-csv.com (dla jednorazowych konwersji) lub json-csv.com/api do automatyzacji za pomocą Pythona. Jest to proste rozwiązanie dla bardziej złożonych struktur JSON.
Stack Man

Odpowiedzi:


129

Po pierwsze, JSON ma zagnieżdżone obiekty, więc zwykle nie można go bezpośrednio przekonwertować na CSV. Musisz zmienić to na coś takiego:

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

Oto mój kod do generowania CSV z tego:

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

Otrzymasz wynik jako:

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

2
to jest praca, ale przepraszam, czy mogę dostać coś, co nie jest twardym kodem. Lepiej, że mogę użyć f.writerow (a), a a to pewna zmienna, którą zadeklarowałem przed podziękowaniem
little_fish

Dla mnie działa to prawie idealnie. W eksportowanym pliku CSV niektóre pola są otoczone przez [u'i ']. Jakie jest obejście (niezwiązane z przetwarzaniem)? jeśli jest jeden ... :)
Dror

3
Poniżej pokazałem, jak to zrobić bardziej ogólnie, bez konieczności
programowania na stałe

4
Hej, ja próbowałem tego, ale ja dostaję TypeError: a bytes-like object is required, not 'str'naf.writerow(['pk', 'model', 'codename', 'name', 'content_type'])
Aditya Hariharan

8
dla python3 zmień wiersz z otwarciem pliku csv naf = csv.writer(open("test.csv", "w", newline=''))
PiotrK

118

Z pandas biblioteki , to jest tak proste, jak za pomocą dwóch poleceń!

pandas.read_json()

Aby przekonwertować ciąg JSON na obiekt pandy (szereg lub ramkę danych). Następnie, zakładając, że wyniki zostały zapisane jako df:

df.to_csv()

Który może albo zwrócić ciąg, albo zapisać bezpośrednio do pliku csv.

Na podstawie gadatliwości poprzednich odpowiedzi wszyscy powinniśmy podziękować pandom za skrót.


1
To fantastyczna odpowiedź (+1) - tak prosta i .to_csv()naprawdę potężna (na przykład filtrowanie kolumn za darmo). Muszę nauczyć się pand.
WoJ

3
Jak wskazano, ta odpowiedź nie działa w przypadku danych w tym pytaniu. orient='records'musi być ustawiony, ale każdy wiersz fieldsbędzie nadal dictoznaczeniem, co nie jest tym, czego żądał PO.
Trenton McKinney,

90

Zakładam, że Twój plik JSON zostanie zdekodowany na listę słowników. Najpierw potrzebujemy funkcji, która spłaszczy obiekty 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

Wynik uruchomienia tego fragmentu kodu w obiekcie JSON:

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

jest

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

Po zastosowaniu tej funkcji do każdego nagrania w tablicy wejściowej obiektów JSON:

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

i znalezienie odpowiednich nazw kolumn:

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

nie jest trudno uruchomić to przez moduł 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 ) )

Mam nadzieję, że to pomoże!


Korzystając z Pythona 3.6, musiałem stworzyć listę spłaszczonego JSON, aby ostatnia pętla działała: „input = list (map (lambda x: flattenjson (x,„ __ ”), input))”. Nie rozumiem jednak, dlaczego iterowalność nie wystarczy. Musiałem także określić kodowanie podczas otwierania pliku wyjściowego, ponieważ moje dane używają UTF8. To zdecydowanie pomogło, dziękuję !!
Alexis R

To wspaniale, dzięki Alec! Zmodyfikowałem go, aby działał z wieloma poziomami zagnieżdżania: stackoverflow.com/a/57228641/473201
phreakhead

35

JSON może reprezentować wiele różnych struktur danych - „obiekt” JS jest z grubsza podobny do słownika Pythona (z kluczami łańcuchowymi), „tablica” JS z grubsza przypomina listę Pythona i można zagnieżdżać je tak długo, jak końcowe „ elementy liści ”to liczby lub ciągi znaków.

CSV może zasadniczo reprezentować tylko tabelę 2-D - opcjonalnie z pierwszym wierszem „nagłówków”, tj. „Nazwami kolumn”, co może sprawić, że tabela będzie interpretowana jako lista dykt, zamiast zwykłej interpretacji, lista listy (ponownie, elementami „liścia” mogą być liczby lub ciągi znaków).

Tak więc w ogólnym przypadku nie można przetłumaczyć dowolnej struktury JSON na CSV. W kilku specjalnych przypadkach możesz (tablica tablic bez dalszego zagnieżdżania; tablice obiektów, które wszystkie mają dokładnie takie same klucze). Jaki szczególny przypadek dotyczy twojego problemu? Szczegóły rozwiązania zależą od tego, który konkretny przypadek masz. Biorąc pod uwagę zdumiewający fakt, że nawet nie wspominasz, który z nich ma zastosowanie, podejrzewam, że mogłeś nie wziąć pod uwagę ograniczenia, w rzeczywistości nie ma zastosowania żaden użyteczny przypadek, a twojego problemu nie można rozwiązać. Ale proszę wyjaśnij!


31

Ogólne rozwiązanie, które tłumaczy dowolną listę płaskich obiektów json na csv.

Przekaż plik input.json jako pierwszy argument w wierszu polecenia.

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

2
Ważny komentarz - ten kod podaje kolumny / nagłówki z pól w pierwszym rzędzie. Jeśli twoje dane JSON mają „postrzępione” kolumny, tzn. Powiedzmy, że wiersz 1 ma 5 kolumn, ale wiersz 2 ma 6 kolumn, musisz wykonać pierwsze przejście danych, aby uzyskać całkowity zestaw wszystkich kolumn i użyć go jako nagłówków.
Mike Repass,

Mając dane, które posiadałem, stanowiło to świetną część rozwiązania, którego potrzebowałem, ponieważ mój JSON nie był postrzępiony, działał wspaniale z niewielkimi poprawkami dla danych wyjściowych, ponieważ działałem w ramach istniejącego skryptu.
MichaelF

1
Ten kod zakłada również, że wartości będą wyprowadzane w tej samej kolejności, co klucze w wierszu nagłówka. Chociaż mogło to działać na szczęście, nie jest to w żaden sposób gwarantowane.
RyanHennig

Błąd kodowania. Masz pomysł, jak dodać kodowanie do utf-8?
Elad Tabak

25

Ten kod powinien działać dla Ciebie, przy założeniu, że Twoje dane JSON znajdują się w pliku o nazwie 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)

1
Hmmm, nie - csv_file.writerow( f.writerowoczywiście nie ma , zakładam, że popełniłeś literówkę!) Chce sekwencji, a nie dyktowania - w twoim przykładzie każdy przedmiot to dykt. To działałoby w innym specjalnym przypadku, jak wskazałem w mojej odpowiedzi - gdzie plik JSON ma tablicę tablic; nie działa dla szeregu obiektów, co jest szczególnym przypadkiem, który wydaje się próbować rozwiązać (ten wymaga csv.DictWriter- i oczywiście musisz wyodrębnić nazwy pól i zdecydować o kolejności w celu jej utworzenia) ! -).
Alex Martelli,

@DanLoewenherz To nie działa w najnowszych wersjach Pythona. TypeError: może łączyć tylko listę (nie „dict_values”) z listą
Apolo Radomer

18

Będzie łatwy w użyciu csv.DictWriter(), szczegółowa implementacja może wyglądać następująco:

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

Zauważ, że zakłada to, że wszystkie obiekty JSON mają te same pola.

Oto odniesienie, które może ci pomóc.


Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli zmieni się połączona strona. - Z recenzji
Mathieu,

3
@purplepsycho Znalazłem tę odpowiedź z komentarzem, który zasłużył na to, że jest tylko linkiem. Nowy użytkownik, który mógł nie wiedzieć, że ten link nie jest dobrą odpowiedzią, poprawił to. Głosowałem za głosem; być może mógłbyś również zachęcić nowego użytkownika do dalszego uczestnictwa w naszej społeczności?
Mawg mówi o przywróceniu Moniki

6

Miałem problem z zaproponowanym przez Dana rozwiązaniem , ale zadziałało to dla mnie:

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

Gdzie „test.json” zawierał:

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

Wystąpił błąd podczas próby uruchomienia programu na przykładowych danych C: \ curl> python json2csv.py Traceback (ostatnie ostatnie połączenie): plik „json2csv.py”, wiersz 11, w <module> f.writerow ([item ['pk '], item [' model ']] + item [' fields ']. values ​​()) TypeError: może łączyć tylko listę (nie „wartości_dict”) z listą
Mian Asbat Ahmad

Wypróbowałem go ponownie teraz w Pythonie 2.7.9 i działa dobrze dla mnie.
Amanda,

6

Użyj json_normalizez pandas:

  • Biorąc pod uwagę dostarczone dane, w pliku o nazwie test.json
  • encoding='utf-8' może nie być konieczne.
  • Poniższy kod korzysta z pathlibbiblioteki
    • .open jest metodą pathlib
    • Działa również ze ścieżkami innymi niż 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')

Wyjście 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

Inne zasoby dla bardziej zagnieżdżonych obiektów JSON:


4

Jak wspomniano w poprzednich odpowiedziach, trudność w konwersji jsona na csv polega na tym, że plik json może zawierać zagnieżdżone słowniki, a zatem może być wielowymiarową strukturą danych sprawdzającą csv, który jest strukturą danych 2D. Jednak dobrym sposobem na przekształcenie wielowymiarowej struktury w csv jest posiadanie wielu plików csv, które łączą się z kluczami głównymi.

W twoim przykładzie pierwsze wyjście csv ma ​​kolumny „pk”, „model”, „fields” jako kolumny. Wartości dla „pk” i „model” są łatwe do zdobycia, ale ponieważ kolumna „pola” zawiera słownik, powinien to być własny plik csv, a ponieważ „nazwa kodowa” wydaje się być kluczem podstawowym, można użyć jej jako danych wejściowych dla „pól” do wypełnienia pierwszego pliku csv. Drugi plik csv zawiera słownik z kolumny „pola” o nazwie kodowej jako kluczu podstawowym, którego można użyć do powiązania dwóch plików csv.

Oto rozwiązanie dla twojego pliku json, który konwertuje zagnieżdżone słowniki do 2 plików 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")

4

Wiem, że minęło sporo czasu, odkąd zadano to pytanie, ale pomyślałem, że mogę dodać do odpowiedzi innych i udostępnić post na blogu, który moim zdaniem wyjaśniłby rozwiązanie w bardzo zwięzły sposób.

Oto link

Otwórz plik do pisania

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

Utwórz obiekt piszący 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())

Zamknij plik, aby zapisać zawartość

employ_data.close()

3

Nie jest to zbyt mądry sposób, aby to zrobić, ale miałem ten sam problem i to zadziałało dla mnie:

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

3

Odpowiedź Aleca jest świetna, ale nie działa w przypadku wielu poziomów zagnieżdżenia. Oto zmodyfikowana wersja, która obsługuje wiele poziomów zagnieżdżania. To sprawia, że ​​nazwy nagłówków są nieco ładniejsze, jeśli zagnieżdżony obiekt już określa swój własny klucz (np. Dane 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)

2

Działa to stosunkowo dobrze. Spłaszcza plik Json, aby zapisać go do pliku CSV. Elementy zagnieżdżone są zarządzane :)

To dotyczy Pythona 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)

cieszyć się.


Plik .csv nie został wygenerowany, zamiast tego tekst csv został wyprowadzony do konsoli. Ponadto json.loadsnie działał, sprawiłem, że działał json.load, co ładnie daje obiekt listy. Po trzecie, zagnieżdżone elementy zostały utracone.
ZygD

2

Mój prosty sposób na rozwiązanie tego:

Utwórz nowy plik Python, taki jak: json_to_csv.py

Dodaj ten kod:

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

Po dodaniu tego kodu zapisz plik i uruchom na terminalu:

python json_to_csv.py input.txt output.csv

Mam nadzieję, że ci to pomoże.

DO ZOBACZENIA!


1
Ta próbka działa jak urok! dzięki za udostępnienie byłem w stanie przekonwertować mój plik json na CSV za pomocą tego skryptu python
Mostafa

2

Zaskakujące, okazało się, że żadna z zamieszczonych tutaj odpowiedzi poprawnie nie uwzględnia wszystkich możliwych scenariuszy (np. Zagnieżdżone dykty, zagnieżdżone listy, brak wartości itp.).

To rozwiązanie powinno działać we wszystkich scenariuszach:

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

2

Spróbuj tego

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

2

Ten kod działa dla każdego danego pliku 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()

1

Zmodyfikowano odpowiedź Aleca McGaila, aby obsługiwała JSON z listami w środku

    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

Dzięki!


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)

1

Jeśli weźmiemy pod uwagę poniższy przykład konwersji pliku w formacie json na plik w formacie csv.

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

Poniższy kod przekonwertuje plik json (data3.json) na plik 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')])

Powyższy kod został wykonany w lokalnie zainstalowanym pycharmie i pomyślnie przekonwertował plik json na plik csv. Mam nadzieję, że pomoże to w konwersji plików.


0

Ponieważ dane wydają się mieć format słownikowy, wydaje się, że powinieneś użyć csv.DictWriter (), aby faktycznie wypisać wiersze z odpowiednimi informacjami nagłówka. To powinno pozwolić na łatwiejszą konwersję. Parametr fieldnames poprawnie ustawiłby następnie kolejność, podczas gdy wyjście pierwszego wiersza, ponieważ nagłówki pozwoliłyby na jego odczytanie i przetworzenie później przez csv.DictReader ().

Na przykład użył Mike Repass

output = csv.writer(sys.stdout)

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

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

Jednak po prostu zmień początkową konfigurację na output = csv.DictWriter (zestaw plików, nazwy pól = dane [0] .keys ())

Zauważ, że ponieważ kolejność elementów w słowniku nie jest zdefiniowana, może być konieczne jawne utworzenie wpisów nazw pól. Gdy to zrobisz, writerow będzie działać. Zapisy działają wtedy tak, jak pierwotnie pokazano.


0

Niestety nie mam reputacji, aby wnieść niewielki wkład w niesamowitą odpowiedź @Alec McGail. Korzystałem z Python3 i musiałem przekonwertować mapę na listę po komentarzu @Alexis R.

Dodatkowo odkryłem, że pisarz csv dodaje do pliku dodatkowe CR (mam pustą linię dla każdej linii z danymi w pliku csv). Rozwiązanie było bardzo łatwe po odpowiedzi @Jason R. Coombs na ten wątek: CSV w Pythonie dodając dodatkowy znak powrotu karetki

Musisz po prostu dodać parametr lineterminator = '\ n' do csv.writer. To będzie:csv_w = csv.writer( out_file, lineterminator='\n' )


0

Możesz użyć tego kodu, aby przekonwertować plik json na plik csv Po przeczytaniu pliku przekształcam obiekt w ramkę danych pandy, a następnie zapisuję go w pliku 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)

nie uwzględnia to podpól (takich jak „pola” w przykładzie) - podobiekt znajduje się w jednej kolumnie zamiast zawartości podzielonej również na poszczególne kolumny.
Cribber

0

Mogę spóźnić się na przyjęcie, ale myślę, że poradziłem sobie z podobnym problemem. Miałem plik json, który wyglądał tak

Struktura plików JSON

Chciałem tylko wyodrębnić kilka kluczy / wartości z tych plików JSON. Więc napisałem następujący kod, aby wyodrębnić to samo.

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

Mam nadzieję, że to pomoże. Szczegółowe informacje na temat działania tego kodu można sprawdzić tutaj


0

To jest modyfikacja odpowiedzi @ MikeRepass. Ta wersja zapisuje CSV do pliku i działa zarówno dla Python 2, jak i 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())
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.