Вопрос

У меня есть файл 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
    }
  }
]

Нет правильного решения

Другие советы

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

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

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

pandas.read_json()

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

df.to_csv()

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

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

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

После применения этой функции к каждому словарю во входном массиве объектов 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 ) )

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

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

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

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

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

Этот код должен работать для вас, предполагая, что ваши данные 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)

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

Здесь ссылка что может вам помочь.

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

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

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

В вашем примере первый вывод CSV содержит столбцы «pk», «model», «fields» в качестве столбцов.Значения для «pk» и «model» легко получить, но поскольку столбец «fields» содержит словарь, он должен быть отдельным CSV, а поскольку «codename» выглядит как первичный ключ, вы можете использовать его в качестве входных данных. для «полей» для завершения первого CSV.Второй CSV-файл содержит словарь из столбца «Поля» с кодовым именем в качестве первичного ключа, который можно использовать для связи двух 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")

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

Здесь связь

Открыть файл для записи

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

Это работает относительно хорошо.Он сглаживает 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)

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

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

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

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

ДО ВСТРЕЧИ!

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

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

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

Спасибо!

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)

Попробуй это

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

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

Ответ Алека это здорово, но оно не работает в случае, когда имеется несколько уровней вложенности.Вот модифицированная версия, поддерживающая несколько уровней вложенности.Это также делает имена заголовков немного приятнее, если вложенный объект уже указывает свой собственный ключ (например,Данные 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)

Поскольку данные, по-видимому, представлены в формате словаря, может показаться, что вам действительно следует использовать 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())

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

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

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

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

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

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

Возможно, я опоздал на вечеринку, но думаю, что сталкивался с подобной проблемой.У меня был файл 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()

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top