Как конвертировать 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
    }
  }
]

Ответ 1

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

Во-первых, ваш 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

Ответ 2

Я предполагаю, что ваш 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 ) )

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

Ответ 3

С помощью библиотеки pandas , это так же просто, как использование двух команд!

pandas.read_json()

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

df.to_csv()

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

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

Ответ 4

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

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

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

Ответ 5

Общее решение, которое переводит любой json-список плоских объектов в 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())

Ответ 6

Этот код должен работать для вас, предполагая, что ваши данные 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:
        fields = list(item['fields'].values())
        csv_file.writerow([item['pk'], item['model']] + fields)

Ответ 7

Будет легко использовать 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 имеют одинаковые поля.

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

Ответ 8

У меня возникли проблемы с предлагаемым решением Dan, но это сработало для меня:

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 } }
]

Ответ 9

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

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

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

Ответ 10

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

Вот ссылка

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

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

Создайте объект записи 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())

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

employ_data.close()

Ответ 11

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

Что для 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)

пользоваться.

Ответ 12

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

Создайте новый файл 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

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

SeeYa!

Ответ 13

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

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

Ответ 14

Измененный ответ Алек МакГейл для поддержки 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

Спасибо!

Ответ 15

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)

Ответ 16

Попробуй это

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

Ответ 17

Этот код работает для любого данного файла 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()

Ответ 18

Ответ алек отличный, но он не работает в случае, когда есть несколько уровней вложенности. Здесь модифицированная версия, которая поддерживает несколько уровней вложенности. Это также делает имена заголовков более приятными, если во вложенном объекте уже указан собственный ключ (например, данные 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 /questions/60679/how-can-i-convert-json-to-csv/419975#419975
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)

Ответ 19

Поскольку данные, как представляется, находятся в формате словаря, кажется, что вы действительно должны использовать 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(наборы файлов, fieldnames = data [0].keys())

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

Ответ 20

К сожалению, у меня нет репутации, чтобы внести небольшой вклад в удивительный ответ @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' )

Ответ 21

Удивительно, но я обнаружил, что ни один из ответов, опубликованных здесь, до сих пор правильно не рассматривал все возможные сценарии (например, вложенные символы, вложенные списки, значения 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

Ответ 22

Вы можете использовать этот код для преобразования 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)

Ответ 23

import pandas as pd

df = pd.read_json('filename.json',encoding='utf-8')
df.to_csv('filename.csv',index=False)

Ответ 24

Возможно, я опоздал на вечеринку, но, думаю, я справился с подобной проблемой. У меня был файл JSON, который выглядел так

JSON File Structure

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

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

Я надеюсь, что это поможет. Подробнее о том, как работает этот код, вы можете проверить здесь.