it-roy-ru.com

Как я могу конвертировать JSON в CSV?

У меня есть файл JSON, который я хочу преобразовать в файл CSV. Как я могу сделать это с Python?

Я старался:

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

Однако это не сработало. Я использую Django, и я получил ошибку:

file' object has no attribute 'writerow'

Итак, я попробовал следующее:

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

Я тогда получаю ошибку:

sequence expected

Пример файла 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
    }
  }
]
131
little_fish

Я не уверен, что этот вопрос уже решен или нет, но позвольте мне вставить то, что я сделал для справки.

Во-первых, ваш JSON имеет вложенные объекты, поэтому его обычно нельзя напрямую преобразовать в CSV . Вам нужно изменить это на что-то вроде этого:

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

Вот мой код для генерации CSV из этого:

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

Вы получите вывод как:

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
100
YOU

Я предполагаю, что ваш JSON-файл будет декодирован в список словарей. Сначала нам нужна функция, которая сгладит объекты 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

Результат выполнения этого фрагмента на вашем объекте 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
}

После применения этой функции к каждому dict во входном массиве объектов JSON:

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

и найти соответствующие имена столбцов:

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

нетрудно запустить это через модуль 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 ) )

Надеюсь, это поможет!

76
Alec McGail

С pandaslibrary , это так же просто, как с помощью двух команд!

pandas.read_json()

Преобразовать строку JSON в объект pandas (либо серию, либо фрейм данных). Затем, предполагая, что результаты были сохранены как df:

df.to_csv()

Который может либо вернуть строку, либо записать напрямую в csv-файл.

Основываясь на многословности предыдущих ответов, мы все должны поблагодарить панд за ярлык.

57
vmg

JSON может представлять самые разнообразные структуры данных - «объект» JS примерно похож на Python dict (со строковыми ключами), «массив» JS примерно похож на список Python, и вы можете вкладывать их до финала » Листовые элементы представляют собой числа или строки.

По сути, CSV может представлять собой только двумерную таблицу - необязательно с первой строкой «заголовков», то есть «имен столбцов», что может сделать таблицу интерпретируемой как список диктов, вместо обычной интерпретации, как список списки (опять же, «листовые» элементы могут быть числами или строками).

Таким образом, в общем случае вы не можете перевести произвольную структуру JSON в CSV. В некоторых особых случаях вы можете (массив массивов без дальнейшего вложения; массивы объектов, у которых все ключи в точности совпадают). Какой особый случай, если таковой имеется, относится к вашей проблеме? Детали решения зависят от того, какой особый случай у вас есть. Учитывая тот удивительный факт, что вы даже не упомянули, какое из них применимо, я подозреваю, что вы, возможно, не учли ограничения, на самом деле ни один из применимых случаев не применим, и вашу проблему невозможно решить. Но, пожалуйста, уточните!

34
Alex Martelli

Универсальное решение, которое переводит любой список json объектов flat в csv.

Передайте файл input.json в качестве первого аргумента в командной строке.

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())
25
Mike Repass

Этот код должен работать для вас, предполагая, что ваши данные JSON находятся в файле с именем data.json.

import json
import csv

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

with open("data.csv", "w") as file:
    csv_file = csv.writer(file)
    for item in data:
        csv_file.writerow([item['pk'], item['model']] + item['fields'].values())
21
Dan Loewenherz

Использовать csv.DictWriter() будет легко, подробная реализация может быть такой:

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

Обратите внимание, что это предполагает, что все ваши объекты JSON имеют одинаковые поля. 

Вот ссылка , которая может вам помочь.

15
ReturnHttp402

У меня были проблемы с предложенным Дэном решением , но это сработало для меня:

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

Где «test.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 } }
]
6
Amanda

Как упоминалось в предыдущих ответах, сложность преобразования json в csv заключается в том, что файл json может содержать вложенные словари и, следовательно, быть многомерной структурой данных, а csv - это 2D структура данных. Тем не менее, хороший способ превратить многомерную структуру в csv - это иметь несколько csv, которые связаны с первичными ключами.

В вашем примере первый вывод csv содержит столбцы «pk», «model», «fields» в качестве столбцов. Значения для «pk» и «model» легко получить, но поскольку столбец «fields» содержит словарь, он должен быть собственным csv, а поскольку «codename» является первичным ключом, его можно использовать в качестве входных данных. для "полей", чтобы завершить первый CSV. Второй CSV содержит словарь из столбца «fields» с кодовым именем в качестве первичного ключа, который можно использовать для связывания 2 CSV.

Вот решение для вашего файла JSON, который конвертирует вложенные словари в 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")
4
dmathewwws

Я знаю, что прошло много времени с тех пор, как был задан этот вопрос, но я подумал, что мог бы добавить к ответу всех остальных и поделиться сообщением в блоге, которое, я думаю, объяснит решение в очень сжатой форме.

Вот ссылка

Откройте файл для записи

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

Создайте объект csv writer

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

Обязательно закройте файл, чтобы сохранить содержимое

employ_data.close()
4
user3768804

Мой простой способ решить это:

Создайте новый файл Python, например: json_to_csv.py

Добавьте этот код: 

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

После добавления этого кода сохраните файл и запустите на терминале:

python json_to_csv.py input.txt output.csv

Я надеюсь, что это поможет вам.

ДО ВСТРЕЧИ!

2
Gabriel Pires

Это работает относительно хорошо .... Это выравнивает JSON, чтобы записать его в CSV-файл ..... Вложенные элементы управляются :)

Это для питона 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)

наслаждаться.

2
Loïc
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
Dnyaneshwar Shendurwadkar

Попробуй это

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())
1
Hasee Amarathunga

Это не очень умный способ сделать это, но у меня была та же проблема, и это сработало для меня:

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()
1
Juan Luis Martinez

Изменен ответ Алек МакГейл для поддержки JSON со списками внутри

    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

Спасибо!

1
Sawan Vaidya

Вы можете использовать этот код для преобразования json-файла в csv-файл После прочтения файла я конвертирую объект в pandas dataframe, а затем сохраняю его в 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)
0
Terminator17

Удивительно, но я обнаружил, что ни один из ответов, опубликованных здесь, до сих пор правильно не рассматривал все возможные сценарии (например, вложенные диктовки, вложенные списки, значения None и т.д.).

Это решение должно работать во всех сценариях:

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
0
Max Berman

Поскольку данные представляются в формате словаря, может показаться, что вы должны использовать csv.DictWriter () для вывода строк с соответствующей информацией заголовка. Это должно позволить преобразованию быть обработанным несколько легче. Параметр fieldnames затем установил бы порядок должным образом, в то время как вывод первой строки в качестве заголовков позволил бы его прочитать и обработать позже csv.DictReader ().

Например, Майк Репасс использовал

output = csv.writer(sys.stdout)

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

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

Однако просто измените начальную настройку на output = csv.DictWriter (набор файлов, имена полей = data [0] .keys ())

Обратите внимание, что поскольку порядок элементов в словаре не определен, возможно, вам придется явно создавать записи с именами полей. Как только вы это сделаете, писатель будет работать. Затем записи работают так, как показано на рисунке.

0
sabbahillel

К сожалению, у меня нет репутации, чтобы внести небольшой вклад в удивительный ответ @Alec McGail . Я использовал Python3 и мне нужно было преобразовать карту в список после комментария @Alexis R. 

Кроме того, я обнаружил, что писатель CSV добавляет дополнительный CR в файл (у меня есть пустая строка для каждой строки с данными внутри файла CSV). Решение было очень простым после ответа @Jason R. Coombs на эту ветку: CSV в Python с добавлением дополнительного возврата каретки

Вам просто нужно добавить параметр lineterminator = '\ n' в csv.writer. Это будет: csv_w = csv.writer( out_file, lineterminator='\n' )

0
derwyddon