ฉันจะแปลง JSON เป็น CSV ได้อย่างไร


184

ฉันมีไฟล์ 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:
    csv_file.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:
    f.writerow(item)  # ← changed

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
csv_file.writerow (รายการ) ต้องการให้รายการเป็นรายการสตริงหรือตัวเลขอย่างง่าย ลองแปลงแต่ละวัตถุ json เป็นรายการแบบเรียบเช่น {"pk": 22, "model": "auth.permission"} จะกลายเป็น [22, auth.permission]
ปราบปราม

1
วิธีง่าย ๆ สำหรับการใช้jqงานดังที่อธิบายไว้ที่นี่: stackoverflow.com/questions/32960857//
มิคาเอลเอลเลียต

ทางเลือกของบุคคลที่สาม: json-csv.com (สำหรับการแปลงแบบครั้งเดียว) หรือjson-csv.com/apiเพื่อให้ทำงานอัตโนมัติด้วย Python นี่เป็นวิธีง่ายๆสำหรับโครงสร้าง JSON ที่ซับซ้อนมากขึ้น
สแต็คแมน

คำตอบ:


129

ขั้นแรกให้ 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
นี่คือการทำงาน แต่ขอโทษก่อนที่ฉันจะได้รับสิ่งที่ไม่ยากรหัสฉันสิ่งที่มัน id ดีกว่าฉันสามารถใช้ f.writerow (a) และ a เป็นตัวแปรที่ฉันประกาศก่อนขอบคุณก่อน
little_fish

สำหรับฉันมันใช้งานได้เกือบสมบูรณ์แบบ ใน CSV ที่ส่งออกบางส่วนของเขตข้อมูลถูกล้อมรอบด้วยและ[u' ']วิธีแก้ปัญหา (ไม่ใช่การประมวลผลภายหลัง) คืออะไร หากมีอย่างใดอย่างหนึ่ง ... :)
Dror

3
ด้านล่างฉันได้แสดงวิธีการทำโดยทั่วไปโดยไม่ต้องเขียนโค้ดให้
ยุ่งยาก

4
เฮ้ฉันได้ลองแล้ว แต่ฉันกำลังจะTypeError: a bytes-like object is required, not 'str'ไปf.writerow(['pk', 'model', 'codename', 'name', 'content_type'])
Aditya Hariharan

8
สำหรับ python3 เปลี่ยนบรรทัดด้วยการเปิดไฟล์ csv ไปที่f = csv.writer(open("test.csv", "w", newline=''))
PiotrK

119

กับpandas ห้องสมุด , นี้เป็นเรื่องง่ายเหมือนการใช้สองคำสั่ง!

pandas.read_json()

ในการแปลงสตริง JSON เป็นออบเจกต์แพนด้า (ทั้งชุดหรือดาต้าเฟรม) จากนั้นสมมติว่าผลลัพธ์ถูกเก็บเป็นdf:

df.to_csv()

ซึ่งสามารถส่งคืนสตริงหรือเขียนโดยตรงไปยังไฟล์ csv

ขึ้นอยู่กับความละเอียดของคำตอบก่อนหน้านี้เราทุกคนควรขอแพนด้าทางลัด


1
นี่เป็นคำตอบที่ยอดเยี่ยม (+1) - ง่ายและ.to_csv()มีประสิทธิภาพมาก (ตัวอย่างเช่นการกรองคอลัมน์ฟรี) ฉันต้องเรียนรู้แพนด้า
WoJ

3
ตามที่ระบุไว้คำตอบนี้ใช้ไม่ได้กับข้อมูลในคำถามนี้ orient='records'จะต้องตั้งค่า แต่แต่ละแถวfieldsจะยังคงเป็น a dictซึ่งไม่ใช่สิ่งที่ OP ร้องขอ
Trenton McKinney

90

ฉันสมมติว่าไฟล์ 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 ) )

ฉันหวังว่านี่จะช่วยได้!


ใช้ Python 3.6 ฉันต้องทำรายการของ JSON ที่แบนเพื่อให้ลูปสุดท้ายทำงาน: "input = list (map (lambda x: flattenjson (x," __ "), input)) ฉันไม่เข้าใจว่าทำไม iterable ไม่พอแม้ว่า ฉันต้องระบุการเข้ารหัสเมื่อเปิดไฟล์เอาต์พุตเนื่องจากข้อมูลของฉันใช้ UTF8 มันช่วยได้แน่นอนขอบคุณ !!
Alexis R

นี่มันเยี่ยมมากขอบคุณอเล็กซ์! ฉันแก้ไขเพื่อให้ทำงานกับการซ้อนหลายระดับ: stackoverflow.com/a/57228641/473201
phreakhead

35

JSON สามารถแสดงโครงสร้างข้อมูลที่หลากหลาย - JS "object" นั้นคล้ายกับ Python dict (พร้อมด้วยคีย์สตริง), "array" ของ JS "โดยประมาณเหมือนกับรายการ Python และคุณสามารถซ้อนมันได้ตราบใดที่" องค์ประกอบ leaf "เป็นตัวเลขหรือสตริง

CSV สามารถแสดงเฉพาะตาราง 2-D ซึ่งเป็นทางเลือกโดยมีแถวแรกของ "ส่วนหัว" คือ "ชื่อคอลัมน์" ซึ่งสามารถทำให้ตารางตีความได้เป็นรายการของ dicts แทนที่จะเป็นการตีความปกติรายการของ รายการ (องค์ประกอบ "leaf" อีกครั้งสามารถเป็นตัวเลขหรือสตริงได้)

ดังนั้นในกรณีทั่วไปคุณไม่สามารถแปลโครงสร้าง JSON ตามอำเภอใจเป็น CSV ได้ ในบางกรณีพิเศษคุณสามารถทำได้ (อาร์เรย์ของอาร์เรย์ที่ไม่มีการซ้อนเพิ่มเติม; อาร์เรย์ของวัตถุที่มีคีย์เดียวกันทั้งหมด) กรณีพิเศษใดที่นำไปใช้กับปัญหาของคุณ รายละเอียดของการแก้ปัญหาขึ้นอยู่กับกรณีพิเศษที่คุณมี ด้วยข้อเท็จจริงที่น่าประหลาดใจที่คุณไม่ได้กล่าวถึงข้อใดที่มีผลบังคับใช้ฉันคิดว่าคุณอาจไม่ได้พิจารณาถึงข้อ จำกัด ไม่ว่ากรณีใด ๆ ที่ใช้งานได้จริงและปัญหาของคุณไม่สามารถแก้ไขได้ แต่โปรดอธิบายให้ชัดเจน!


31

วิธีการแก้ปัญหาทั่วไปซึ่งแปลว่ารายการใด ๆ ของ 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())

2
ความคิดเห็นที่สำคัญ - รหัสนี้ infers คอลัมน์ / ส่วนหัวจากเขตข้อมูลในแถวแรก หากข้อมูล json ของคุณมีคอลัมน์ 'jagged' เช่นสมมติว่า row1 มี 5 คอลัมน์ แต่ row2 มี 6 คอลัมน์คุณต้องทำการส่งผ่านข้อมูลแรกเพื่อรับชุดทั้งหมดของคอลัมน์ทั้งหมดและใช้เป็นส่วนหัว
Mike Repass

ด้วยข้อมูลที่ฉันมีนี่เป็นส่วนที่ดีของวิธีแก้ปัญหาที่ฉันต้องการเนื่องจาก JSON ของฉันไม่ขรุขระมันทำงานได้อย่างมหัศจรรย์ด้วยการปรับแต่งเล็กน้อยสำหรับเอาต์พุตเนื่องจากฉันเรียกใช้ภายในสคริปต์ที่มีอยู่
MichaelF

1
รหัสนี้ยังสันนิษฐานว่าค่าจะถูกส่งออกในลำดับเดียวกันกับคีย์ในแถวส่วนหัว ในขณะที่อาจทำงานได้ด้วยโชค แต่ก็ไม่รับประกัน
RyanHennig

รับข้อผิดพลาดการเข้ารหัส มีความคิดวิธีการเพิ่มการเข้ารหัสใน utf-8 ไหม?
Elad Tabak

25

รหัสนี้ควรจะทำงานให้คุณสมมติว่า 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)

1
อืมไม่มี - csv_file.writerow(ไม่มีf.writerowแน่นอนฉันคิดว่าคุณพิมพ์ผิดที่นั่น!) ต้องการลำดับไม่ใช่ dict - และในตัวอย่างของคุณแต่ละรายการเป็น dict สิ่งนี้จะใช้ได้กับกรณีพิเศษอื่น ๆ ตามที่ฉันระบุไว้ในคำตอบของฉัน - ที่ไฟล์ JSON มีอาร์เรย์หลายอาร์เรย์ มันใช้ไม่ได้กับอาเรย์ของวัตถุซึ่งเป็นกรณีพิเศษที่คุณพยายามแก้ (ซึ่งต้องใช้csv.DictWriter- และแน่นอนว่าคุณต้องแยกชื่อฟิลด์และตัดสินใจสั่งซื้อเพื่อสร้างอินสแตนซ์ -)
Alex Martelli

@DanLoewenherz ไม่สามารถใช้งานได้กับ Python เวอร์ชันล่าสุด TypeError: สามารถเชื่อมโยงรายการเท่านั้น (ไม่ใช่ "dict_values") เพื่อแสดงรายการ
Apolo Radomer

18

มันจะใช้งานง่ายการใช้งาน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 ของคุณทั้งหมดมีฟิลด์เหมือนกัน

นี่คือข้อมูลอ้างอิงที่อาจช่วยคุณได้


แม้ว่าลิงก์นี้อาจตอบคำถามได้ดีกว่าหากรวมส่วนสำคัญของคำตอบไว้ที่นี่และให้ลิงก์สำหรับการอ้างอิง คำตอบสำหรับลิงก์เท่านั้นอาจไม่ถูกต้องหากหน้าเว็บที่เชื่อมโยงมีการเปลี่ยนแปลง - จากการทบทวน
Mathieu

3
@pleplepsycho ฉันพบคำตอบนี้ด้วย downvote ซึ่งสมควรได้รับการเชื่อมโยงเท่านั้น ผู้ใช้ใหม่ที่อาจไม่ทราบว่าลิงก์เท่านั้นไม่ใช่คำตอบที่ดี แต่ได้แก้ไขให้แล้ว ฉันโหวตขึ้น บางทีคุณก็ทำได้เช่นกันเพื่อกระตุ้นให้ผู้ใช้รายใหม่มีส่วนร่วมในชุมชนของเราต่อไป
Mawg กล่าวว่าคืนสถานะโมนิก้า

6

ฉันมีปัญหากับโซลูชันที่ 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 } }
]

มีข้อผิดพลาดในการลองใช้โปรแกรมของคุณกับข้อมูลตัวอย่าง C: \ curl> python json2csv.py การติดตามกลับ (การโทรล่าสุดครั้งล่าสุด): ไฟล์ "json2csv.py", บรรทัดที่ 11, ใน <module> f.writerow ([รายการ ['pk '], รายการ [' model ']] + รายการ [' field ']. values ​​()) TypeError: สามารถเชื่อมโยงรายการเท่านั้น (ไม่ใช่ "dict_values") เพื่อแสดงรายการ
Mian Asbat Ahmad

ลองอีกครั้งใน Python 2.7.9 และใช้งานได้ดีสำหรับฉัน
Amanda

6

ใช้json_normalizeจากpandas:

  • รับข้อมูลที่ให้ไว้ในไฟล์ชื่อ test.json
  • encoding='utf-8' อาจไม่จำเป็น
  • รหัสต่อไปนี้ใช้ประโยชน์จากpathlibไลบรารี
    • .open เป็นวิธีการของ pathlib
    • ทำงานกับพา ธ ที่ไม่ใช่ของ Windows ได้เช่นกัน
import pandas as pd
# As of Pandas 1.01, json_normalize as pandas.io.json.json_normalize is deprecated and is now exposed in the top-level namespace.
# from pandas.io.json import json_normalize
from pathlib import Path
import json

# set path to file
p = Path(r'c:\some_path_to_file\test.json')

# read json
with p.open('r', encoding='utf-8') as f:
    data = json.loads(f.read())

# create dataframe
df = pd.json_normalize(data)

# dataframe view
 pk            model  fields.codename           fields.name  fields.content_type
 22  auth.permission     add_logentry     Can add log entry                    8
 23  auth.permission  change_logentry  Can change log entry                    8
 24  auth.permission  delete_logentry  Can delete log entry                    8
  4  auth.permission        add_group         Can add group                    2
 10  auth.permission      add_message       Can add message                    4

# save to csv
df.to_csv('test.csv', index=False, encoding='utf-8')

เอาต์พุต CSV:

pk,model,fields.codename,fields.name,fields.content_type
22,auth.permission,add_logentry,Can add log entry,8
23,auth.permission,change_logentry,Can change log entry,8
24,auth.permission,delete_logentry,Can delete log entry,8
4,auth.permission,add_group,Can add group,2
10,auth.permission,add_message,Can add message,4

แหล่งข้อมูลอื่น ๆ สำหรับออบเจ็กต์ JSON ที่ซ้อนกันมาก:


4

ดังที่กล่าวไว้ในคำตอบก่อนหน้าความยากลำบากในการแปลง json เป็น csv นั้นเป็นเพราะไฟล์ json สามารถมีพจนานุกรมที่ซ้อนกันและดังนั้นจึงเป็นโครงสร้างข้อมูลหลายมิติโองการ csv ซึ่งเป็นโครงสร้างข้อมูล 2D อย่างไรก็ตามวิธีที่ดีในการเปลี่ยนโครงสร้างหลายมิติเป็น csv คือการมี csv หลายตัวที่เชื่อมโยงกับคีย์หลัก

ในตัวอย่างของคุณเอาต์พุต csv แรกมีคอลัมน์ "pk", "model", "field" เป็นคอลัมน์ของคุณ ค่าสำหรับ "pk" และ "model" นั้นง่าย แต่เนื่องจากคอลัมน์ "field" มีพจนานุกรมจึงควรเป็น csv ของตัวเองและเนื่องจาก "codename" ปรากฏเป็นคีย์หลักคุณสามารถใช้เป็นอินพุตได้ สำหรับ "ฟิลด์" เพื่อทำ csv แรกให้สมบูรณ์ csv ที่สองมีพจนานุกรมจากคอลัมน์ "field" ที่มีชื่อรหัสว่าเป็นคีย์หลักที่สามารถใช้ในการผูก 2 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")

4

ฉันรู้มานานแล้วตั้งแต่มีการถามคำถามนี้ แต่ฉันคิดว่าฉันอาจเพิ่มคำตอบของคนอื่นและแบ่งปันโพสต์บล็อกที่ฉันคิดว่าอธิบายวิธีแก้ปัญหาอย่างกระชับ

นี่คือลิงค์

เปิดไฟล์เพื่อเขียน

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

3

มันไม่ได้เป็นวิธีที่ฉลาดมากที่จะทำ แต่ฉันมีปัญหาเดียวกันและสิ่งนี้ได้ผลสำหรับฉัน:

import csv

f = open('data.json')
data = json.load(f)
f.close()

new_data = []

for i in data:
   flat = {}
   names = i.keys()
   for n in names:
      try:
         if len(i[n].keys()) > 0:
            for ii in i[n].keys():
               flat[n+"_"+ii] = i[n][ii]
      except:
         flat[n] = i[n]
   new_data.append(flat)  

f = open(filename, "r")
writer = csv.DictWriter(f, new_data[0].keys())
writer.writeheader()
for row in new_data:
   writer.writerow(row)
f.close()

3

คำตอบของ Alecนั้นยอดเยี่ยม แต่มันไม่ได้ผลในกรณีที่มีการซ้อนกันหลายระดับ ต่อไปนี้เป็นเวอร์ชันที่แก้ไขซึ่งสนับสนุนการซ้อนหลายระดับ นอกจากนี้ยังทำให้ชื่อส่วนหัวเป็นบิตที่ดีกว่าหากวัตถุซ้อนกันระบุรหัสของตนเองแล้ว (เช่นข้อมูล Firebase Analytics / BigTable / BigQuery):

"""Converts JSON with nested fields into a flattened CSV file.
"""

import sys
import json
import csv
import os

import jsonlines

from orderedset import OrderedSet

# from https://stackoverflow.com/a/28246154/473201
def flattenjson( b, prefix='', delim='/', val=None ):
  if val == None:
    val = {}

  if isinstance( b, dict ):
    for j in b.keys():
      flattenjson(b[j], prefix + delim + j, delim, val)
  elif isinstance( b, list ):
    get = b
    for j in range(len(get)):
      key = str(j)

      # If the nested data contains its own key, use that as the header instead.
      if isinstance( get[j], dict ):
        if 'key' in get[j]:
          key = get[j]['key']

      flattenjson(get[j], prefix + delim + key, delim, val)
  else:
    val[prefix] = b

  return val

def main(argv):
  if len(argv) < 2:
    raise Error('Please specify a JSON file to parse')

  filename = argv[1]
  allRows = []
  fieldnames = OrderedSet()
  with jsonlines.open(filename) as reader:
    for obj in reader:
      #print obj
      flattened = flattenjson(obj)
      #print 'keys: %s' % flattened.keys()
      fieldnames.update(flattened.keys())
      allRows.append(flattened)

  outfilename = filename + '.csv'
  with open(outfilename, 'w') as file:
    csvwriter = csv.DictWriter(file, fieldnames=fieldnames)
    csvwriter.writeheader()
    for obj in allRows:
      csvwriter.writerow(obj)



if __name__ == '__main__':
  main(sys.argv)

2

มันใช้งานได้ค่อนข้างดี มันแบน 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)

สนุก.


ไฟล์. csv ไม่ได้ถูกสร้างขึ้นแทนข้อความ csv ถูกส่งออกไปยังคอนโซล นอกจากนี้ยังjson.loadsไม่ทำงานฉันทำให้มันทำงานด้วยjson.loadซึ่งให้ผลเป็นรายการวัตถุอย่างดี ประการที่สามองค์ประกอบที่ซ้อนกันหายไป
ZygD

2

วิธีง่ายๆในการแก้ปัญหานี้:

สร้างไฟล์ 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

ฉันหวังว่านี่จะช่วยคุณได้

แล้วเจอกัน!


1
ตัวอย่างนี้ใช้งานได้อย่างมีเสน่ห์! ขอบคุณที่แบ่งปันฉันสามารถแปลงไฟล์ json ของฉันเป็น CSV โดยใช้สคริปต์ python นี้
Mostafa

2

น่าแปลกที่ฉันพบว่าไม่มีคำตอบใดถูกโพสต์ที่นี่เพื่อจัดการกับสถานการณ์ที่เป็นไปได้ทั้งหมดอย่างถูกต้อง (เช่น dicts ที่ซ้อนกัน, รายการที่ซ้อนกัน, ไม่มีค่า, ฯลฯ )

โซลูชันนี้ควรทำงานได้ในทุกสถานการณ์:

def flatten_json(json):
    def process_value(keys, value, flattened):
        if isinstance(value, dict):
            for key in value.keys():
                process_value(keys + [key], value[key], flattened)
        elif isinstance(value, list):
            for idx, v in enumerate(value):
                process_value(keys + [str(idx)], v, flattened)
        else:
            flattened['__'.join(keys)] = value

    flattened = {}
    for key in json.keys():
        process_value([key], json[key], flattened)
    return flattened

2

ลองสิ่งนี้

import csv, json, sys

input = open(sys.argv[1])
data = json.load(input)
input.close()

output = csv.writer(sys.stdout)

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

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

2

รหัสนี้ใช้ได้กับไฟล์ json ที่กำหนด

# -*- coding: utf-8 -*-
"""
Created on Mon Jun 17 20:35:35 2019
author: Ram
"""

import json
import csv

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



# create the csv writer object
pt_data1 = open('pt_data1.csv', 'w')
csvwriter = csv.writer(pt_data1)

count = 0

for pt in data:

      if count == 0:

             header = pt.keys()

             csvwriter.writerow(header)

             count += 1

      csvwriter.writerow(pt.values())

pt_data1.close()

1

แก้ไขคำตอบของ Alec McGail เพื่อสนับสนุน 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
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

หากเราพิจารณาตัวอย่างด้านล่างสำหรับการแปลงไฟล์รูปแบบ json เป็นไฟล์ที่จัดรูปแบบ csv

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

โค้ดด้านล่างจะแปลงไฟล์ json (data3.json) เป็นไฟล์ csv (data3.csv)

import json
import csv
with open("/Users/Desktop/json/data3.json") as file:
    data = json.load(file)
    file.close()
    print(data)

fname = "/Users/Desktop/json/data3.csv"

with open(fname, "w", newline='') as file:
    csv_file = csv.writer(file)
    csv_file.writerow(['dept',
                       'class',
                       'subclass'])
    for item in data["item_data"]:
         csv_file.writerow([item.get('item_data').get('dept'),
                            item.get('item_data').get('class'),
                            item.get('item_data').get('subclass')])

โค้ดที่กล่าวถึงข้างต้นได้รับการดำเนินการใน pycharm ที่ติดตั้งในเครื่องและได้ทำการแปลงไฟล์ json เป็นไฟล์ csv สำเร็จแล้ว หวังว่านี้ช่วยในการแปลงไฟล์


0

เนื่องจากข้อมูลดูเหมือนว่าอยู่ในรูปแบบพจนานุกรมจึงควรปรากฏว่าคุณควรใช้ csv.DictWriter () เพื่อส่งออกบรรทัดด้วยข้อมูลส่วนหัวที่เหมาะสม สิ่งนี้จะช่วยให้การจัดการการแปลงค่อนข้างง่ายขึ้น จากนั้นพารามิเตอร์ fieldname จะตั้งค่าคำสั่งซื้ออย่างเหมาะสมในขณะที่เอาต์พุตของบรรทัดแรกเป็นส่วนหัวจะอนุญาตให้สามารถอ่านและประมวลผลได้ในภายหลังโดย csv.DictReader ()

ตัวอย่างเช่น Mike Repass ใช้

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

น่าเสียดายที่ฉันไม่ได้มีชื่อเสียงพอที่จะมีส่วนร่วมเล็กน้อยในคำตอบ @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

คุณสามารถใช้รหัสนี้เพื่อแปลงไฟล์ 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)

สิ่งนี้จะไม่นำฟิลด์ย่อย (เช่น "ฟิลด์" ในตัวอย่าง) มาพิจารณา - วัตถุย่อยอยู่ในหนึ่งคอลัมน์แทนที่จะเป็นเนื้อหาที่แยกออกเป็นแต่ละคอลัมน์เช่นกัน
Cribber

0

ฉันอาจไปงานปาร์ตี้สาย แต่ฉันคิดว่าฉันได้จัดการกับปัญหาที่คล้ายกัน ฉันมีไฟล์ json ซึ่งมีลักษณะเช่นนี้

โครงสร้างไฟล์ JSON

ฉันต้องการแยกคีย์ / ค่าเพียงเล็กน้อยจากไฟล์ 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()

ฉันหวังว่านี่จะช่วยได้ สำหรับรายละเอียดเกี่ยวกับวิธีการทำงานของรหัสนี้คุณสามารถตรวจสอบได้ที่นี่


0

นี่คือการแก้ไขคำตอบของ @ MikeRepass รุ่นนี้เขียน CSV ลงในไฟล์และใช้ได้กับทั้ง Python 2 และ Python 3

import csv,json
input_file="data.json"
output_file="data.csv"
with open(input_file) as f:
    content=json.load(f)
try:
    context=open(output_file,'w',newline='') # Python 3
except TypeError:
    context=open(output_file,'wb') # Python 2
with context as file:
    writer=csv.writer(file)
    writer.writerow(content[0].keys()) # header row
    for row in content:
        writer.writerow(row.values())
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.