Pergunta

Eu tenho um arquivo JSON que eu quero converter para um arquivo CSV. Como posso fazer isso com Python?

Eu tentei:

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

No entanto, não funcionou. Eu estou usando Django e o erro que eu recebi é:

file' object has no attribute 'writerow'

Assim, então eu tentei o seguinte:

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

Então eu recebo o erro:

sequence expected

arquivo JSON Amostra:

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

Nenhuma solução correta

Outras dicas

Eu não tenho certeza essa questão já está ou não resolvido, mas deixe-me colar o que eu fiz para referência.

objetos Primeiro, o JSON tem aninhados, por isso normalmente não podem ser diretamente convertida para CSV. Você precisa mudar isso para algo como isto:

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

Aqui está o meu código para gerar CSV de que:

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

Você receberá saída como:

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

Com a pandas biblioteca , isso é tão fácil quanto usar dois comandos!

pandas.read_json()

Para converter uma string JSON para um objeto de pandas (ou uma série ou trama de dados). Então, assumindo que os resultados foram armazenados como df:

df.to_csv()

O que pode retornar uma string ou escrever diretamente para um arquivo CSV.

Com base no detalhamento de respostas anteriores, todos nós devemos agradecer pandas para o atalho.

Estou assumindo que o arquivo JSON irá decodificar em uma lista de dicionários. Em primeiro lugar, precisamos de uma função que vai achatar o JSON objetos:

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

O resultado da execução deste trecho em seu objeto 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
}

Depois de aplicar esta função para cada Dict na matriz de entrada de objetos JSON:

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

e encontrar os nomes das colunas relevantes:

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

não é difícil de executar este através do módulo de 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 ) )

Espero que isso ajude!

JSON pode representar uma grande variedade de estruturas de dados - um "objeto" JS é mais ou menos como um dicionário Python (com chaves de cadeia), a JS "array" mais ou menos como uma lista Python, e você pode aninhar-los enquanto os elementos finais "folha" são números ou strings.

CSV pode essencialmente representam apenas uma tabela 2-D - opcionalmente com uma primeira fila de "colectores", isto é, "nomes de coluna", o que pode tornar o interpretável tabela como uma lista de dicts, em vez da interpretação normal, uma lista de listas (de novo, elementos "folha" podem ser números ou strings).

Assim, no caso geral, você não pode traduzir uma estrutura JSON arbitrária para um arquivo CSV. Em alguns casos especiais que você pode (array de arrays sem mais nidificação; matrizes de objetos que todos têm exatamente as mesmas chaves). Que caso especial, se for o caso, se aplica ao seu problema? Os detalhes da solução dependerá de qual caso especial que você tem. Dado o fato surpreendente que você nem sequer mencionar qual se aplica, eu suspeito que você pode não ter considerado a restrição, nenhum dos casos utilizável na verdade se aplica, e seu problema é impossível de resolver. Mas por favor, esclarecer!

A solução genérica que se traduz qualquer lista json de apartamento objetos para CSV.

Passe o arquivo input.json como primeiro argumento na linha de comando.

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

Este código deve funcionar para você, assumindo que os seus dados JSON é em um arquivo chamado 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)

Vai ser fácil de usar csv.DictWriter(), a implementação detalhada pode ser assim:

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

Note que isto assume que todos os seus objetos JSON têm os mesmos campos.

Aqui está a referência que pode ajudá-lo.

Eu estava tendo problemas com de Dan solução proposta , mas isso funcionou para mim:

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

Onde "test.json" continha o seguinte:

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

Como mencionado nas respostas anteriores a dificuldade em converter json para CSV é porque um arquivo JSON pode conter dicionários aninhados e, portanto, ser uma estrutura de dados multidimensional versos um arquivo CSV, que é uma estrutura de dados 2D. No entanto, uma boa maneira de transformar uma estrutura multidimensional para um arquivo CSV é ter vários CSVs que unem com chaves primárias.

No seu exemplo, a primeira saída CSV tem a colunas "pk", "modelo", "campos" como suas colunas. Os valores de "pk" e "modelo" são fáceis de obter, mas porque a coluna "campos" contém um dicionário, que deve ser o seu próprio CSV e porque "codinome" aparece à chave primária seja, você pode usar como entrada para "campos" para completar a primeira CSV. O segundo csv contém o dicionário da coluna "campos" com nome de código como a chave primária que pode ser usado para amarrar os 2 CSVs juntos.

Aqui está uma solução para o seu arquivo JSON que converte um dicionários aninhados para 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")

Eu sei que tem sido um longo tempo desde que esta pergunta foi feita, mas eu pensei que eu poderia acrescentar a resposta de todos os outros e compartilhar um post de blog que eu acho que explicar a solução de uma forma muito concisa.

Aqui está a ligação

Abrir um arquivo para escrever

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

Criar o objeto csv escritor

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

Certifique-se de fechar o arquivo, a fim de salvar o conteúdo

employ_data.close()

Isso funciona relativamente bem. Ele achata a json para escrevê-lo para um arquivo CSV. elementos aninhados são geridos:)

Isso é para 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)

desfrutar.

A minha maneira simples de resolver isso:

Crie um novo arquivo Python como: json_to_csv.py

Adicione este código:

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

Depois de adicionar este código, salve o arquivo e execute no terminal:

python json_to_csv.py input.txt output.csv

Espero que isso ajuda você.

SeeYa!

Não é uma maneira muito inteligente de fazer isso, mas eu tive o mesmo problema e isso funcionou para mim:

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

Modified resposta de Alec McGail para suportar JSON com listas dentro

    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

Obrigado!

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)

Tente este

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

Esse código funciona para qualquer arquivo 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()
A resposta de

Alec é grande, mas ele não funciona no caso em que existem vários níveis de aninhamento. Aqui está uma versão modificada que suporta múltiplos níveis de aninhamento. Ele também faz os nomes de cabeçalho de um pouco mais agradáveis ??se o objeto aninhado já especifica sua própria chave (por exemplo Firebase Analytics / BigTable / BigQuery de dados):

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

Uma vez que os dados parecem estar em um formato de dicionário, parece que você deve realmente usar csv.DictWriter () para realmente saída das linhas com as informações de cabeçalho apropriado. Isso deve permitir a conversão para ser tratado um pouco mais fácil. O parâmetro fieldnames, então, definir a ordem corretamente enquanto a saída da primeira linha como os cabeçalhos iria permitir que ele seja lido e processado mais tarde por csv.DictReader ().

Por exemplo, Mike Repasse usado

output = csv.writer(sys.stdout)

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

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

No entanto apenas mudar a configuração inicial para produção = csv.DictWriter (filesetting, fieldnames = dados [0] .Keys ())

Note que desde que a ordem dos elementos em um dicionário não está definido, você pode ter que criar FieldNames entradas explicitamente. Depois de fazer isso, o writerow vai funcionar. As gravações, em seguida, trabalho como inicialmente mostrado.

Infelizmente eu não enouthg reputação para fazer uma pequena contribuição para a incrível resposta @Alec McGail. Eu estava usando Python3 e eu necessária para converter o mapa para uma lista seguinte comentário @Alexis R.

Adicionalmente eu descobri o escritor CSV foi a adição de um CR extra para o arquivo (eu tenho uma linha em branco para cada linha com os dados dentro do arquivo CSV). A solução foi muito fácil seguir a resposta @ Jason R. Coombs para este tópico: CSV em Python adicionando um retorno extra transporte

Você precisa simplesmente adicionar o lineterminator = '\ n' parâmetro para o csv.writer. Será: csv_w = csv.writer( out_file, lineterminator='\n' )

Surpreendentemente, descobri que nenhuma das respostas postadas aqui até agora corretamente lidar com todos os cenários possíveis (por exemplo, dicts aninhadas, listas aninhadas, nenhum valores, etc).

Esta solução deve funcionar em todos os cenários:

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

Você pode usar esse código para converter um arquivo JSON para arquivo CSV Depois de ler o arquivo, eu estou convertendo o objeto para pandas trama de dados e, em seguida, salvar este para um arquivo 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)

Eu poderia estar atrasado para a festa, mas eu acho, eu tenho lidado com o problema similar. Eu tinha um arquivo JSON que olhou como este

JSON Estrutura File

Eu só queria extrair algumas chaves / valores destes arquivo JSON. Então, eu escrevi o código a seguir para extrair o mesmo.

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

Espero que isso vai ajudar. Para detalhes sobre como este trabalho de código você pode verificar aqui

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top