JSON ke CSV di Python โ€” Contoh DictWriter + pandas

ยทBackend DeveloperยทDitinjau olehPriya SharmaยทDiterbitkan

Gunakan JSON to CSV gratis langsung di browser Anda โ€” tidak perlu instalasi.

Coba JSON to CSV Online โ†’

Hampir setiap pipeline data pada akhirnya mencapai langkah yang sama: API mengembalikan JSON, tetapi konsumen berikutnya โ€” spreadsheet, skrip impor, perintah Redshift COPY โ€” membutuhkan CSV. Mengonversi JSON ke CSV di Python terdengar mudah hingga Anda menghadapi objek bersarang, kunci yang tidak konsisten, atau nilai datetime yang memerlukan penanganan khusus. Python menyediakan dua jalur yang solid: modul bawaan json + csv untuk skrip tanpa dependensi, dan pandas untuk flattening bersarang dan dataset yang lebih besar โ€” atau konverter JSON ke CSV online untuk konversi sekali pakai yang cepat tanpa kode apa pun. Panduan ini mencakup kedua pendekatan secara lengkap, dengan contoh Python 3.8+ yang dapat dijalankan.

  • โœ“csv.DictWriter mengonversi daftar dict ke CSV tanpa dependensi โ€” gunakan json.load() untuk mem-parse, lalu writeheader() + writerows().
  • โœ“Selalu buka file CSV dengan newline="" di Windows untuk mencegah baris kosong di antara baris data.
  • โœ“pd.json_normalize() me-flatten JSON bersarang menjadi DataFrame flat sebelum memanggil to_csv() โ€” menangani nesting multi-level secara otomatis.
  • โœ“Teruskan index=False ke DataFrame.to_csv() โ€” tanpanya, pandas menulis kolom nomor baris yang tidak diinginkan.
  • โœ“Untuk file di atas 500 MB, gunakan ijson untuk streaming parsing JSON dikombinasikan dengan csv.DictWriter untuk penggunaan memori yang konstan.

Apa itu Konversi JSON ke CSV?

Konversi JSON ke CSV mengubah array objek JSON menjadi format tabular di mana setiap objek menjadi baris dan setiap kunci menjadi header kolom. JSON bersifat hierarkis โ€” objek dapat bersarang secara arbitrer. CSV bersifat flat โ€” setiap nilai berada dalam grid baris-kolom. Konversi berjalan bersih ketika setiap objek memiliki kumpulan kunci tingkat atas yang sama. Objek bersarang, array, dan kunci yang tidak konsisten adalah di mana hal-hal menjadi menarik. Data mentah tetap identik; hanya strukturnya yang berubah.

Before ยท json
After ยท json
[{"order_id":"ord_91a3","total":149.99,"status":"shipped"},
 {"order_id":"ord_b7f2","total":34.50,"status":"pending"}]
order_id,total,status
ord_91a3,149.99,shipped
ord_b7f2,34.50,pending

csv.DictWriter โ€” Konversi JSON ke CSV Tanpa Pandas

Modul csv disertakan dengan setiap instalasi Python. Tidak perlu pip install, tidak perlu kerumitan virtual environment. csv.DictWriter menerima daftar dictionary dan menulis setiap satu sebagai baris CSV, memetakan kunci dict ke header kolom. Parameter fieldnames mengontrol baik urutan kolom maupun kunci mana yang disertakan.

Python 3.8+ โ€” contoh minimal json ke csv
import json
import csv

# Data JSON contoh โ€” array objek pesanan
json_string = """
[
  {"order_id": "ord_91a3", "product": "Wireless Keyboard", "quantity": 2, "unit_price": 74.99},
  {"order_id": "ord_b7f2", "product": "USB-C Hub", "quantity": 1, "unit_price": 34.50},
  {"order_id": "ord_c4e8", "product": "Monitor Stand", "quantity": 3, "unit_price": 29.95}
]
"""

records = json.loads(json_string)

with open("orders.csv", "w", newline="", encoding="utf-8") as csvfile:
    writer = csv.DictWriter(csvfile, fieldnames=records[0].keys())
    writer.writeheader()
    writer.writerows(records)

# orders.csv:
# order_id,product,quantity,unit_price
# ord_91a3,Wireless Keyboard,2,74.99
# ord_b7f2,USB-C Hub,1,34.50
# ord_c4e8,Monitor Stand,3,29.95

Argumen newline="" pada open() tidak opsional di Windows. Tanpanya, Anda mendapatkan carriage return ganda โ€” yang muncul sebagai baris kosong di antara setiap baris data di Excel. Di macOS dan Linux tidak berbahaya, jadi sertakan saja selalu.

Kode di atas menggunakan json.loads() untuk string. Gunakan json.load() (tanpa s di akhir) saat membaca dari file handle. Hal ini sering membingungkan orang โ€” yang satu membaca string, yang lain membaca objek file.

Python 3.8+ โ€” baca file JSON, tulis file CSV
import json
import csv

with open("server_metrics.json", encoding="utf-8") as jf:
    metrics = json.load(jf)  # json.load() untuk objek file

# fieldnames eksplisit mengontrol urutan kolom
columns = ["timestamp", "hostname", "cpu_percent", "memory_mb", "disk_io_ops"]

with open("server_metrics.csv", "w", newline="", encoding="utf-8") as cf:
    writer = csv.DictWriter(cf, fieldnames=columns, extrasaction="ignore")
    writer.writeheader()
    writer.writerows(metrics)

# Hanya lima kolom yang ditentukan yang muncul, dalam urutan tersebut

Mengatur extrasaction="ignore" secara diam-diam mengabaikan kunci dalam dict yang tidak ada dalam daftar fieldnames. Default-nya adalah "raise", yang melempar ValueError jika ada dict dengan kunci yang tidak terduga. Pilih yang sesuai dengan toleransi Anda terhadap kejutan.

Catatan:csv.DictWriter vs csv.writer: DictWriter memetakan kunci dict ke posisi kolom secara otomatis. csv.writer menulis daftar mentah sebagai baris โ€” Anda yang menangani pengurutan kolom sendiri. DictWriter hampir selalu merupakan pilihan yang tepat untuk JSON-ke-CSV karena record JSON sudah berupa dictionary.

Modul csv Python dilengkapi dengan tiga dialect bernama: excel (delimiter koma, akhiran baris CRLF โ€” default), excel-tab (delimiter tab, akhiran CRLF), dan unix (akhiran baris LF, mengapit semua kolom non-numerik). Teruskan nama dialect sebagai argumen dialect ke csv.DictWriter. Anda juga dapat mendefinisikan dialect kustom dengan csv.register_dialect() ketika sistem target Anda memiliki aturan pengapitan atau delimiter yang tidak biasa. Untuk sebagian besar alur kerja JSON-ke-CSV, dialect excel sudah benar, tetapi beralih ke unix saat menulis file yang akan diproses oleh alat POSIX seperti awk atau sort.

Menangani Tipe Non-Standar: datetime, UUID, dan Decimal

JSON dari API sering mengandung tanggal sebagai string ISO, UUID sebagai string bertanda hubung, dan nilai moneter sebagai float. Ketika Anda mem-parse ini menjadi objek Python untuk diproses sebelum menulis CSV, Anda perlu mengonversinya kembali ke string. Modul csv memanggil str() pada setiap nilai, sehingga sebagian besar tipe bekerja langsung. Namun objek datetime menghasilkan representasi string default yang berantakan, dan nilai Decimal memerlukan pemformatan eksplisit untuk menghindari notasi ilmiah.

Python 3.8+ โ€” pra-proses datetime dan Decimal sebelum menulis CSV
import json
import csv
from datetime import datetime, timezone
from decimal import Decimal
from uuid import UUID

# Simulasi respons API yang telah di-parse dengan tipe Python
transactions = [
    {
        "txn_id": UUID("a1b2c3d4-e5f6-7890-abcd-ef1234567890"),
        "created_at": datetime(2026, 3, 15, 9, 30, 0, tzinfo=timezone.utc),
        "amount": Decimal("1249.99"),
        "currency": "USD",
        "merchant": "CloudHost Inc.",
    },
    {
        "txn_id": UUID("b2c3d4e5-f6a7-8901-bcde-f12345678901"),
        "created_at": datetime(2026, 3, 15, 14, 12, 0, tzinfo=timezone.utc),
        "amount": Decimal("87.50"),
        "currency": "EUR",
        "merchant": "DataSync GmbH",
    },
]

def prepare_row(record: dict) -> dict:
    """Konversi tipe non-string ke string yang ramah CSV."""
    return {
        "txn_id": str(record["txn_id"]),
        "created_at": record["created_at"].isoformat(),
        "amount": f"{record['amount']:.2f}",
        "currency": record["currency"],
        "merchant": record["merchant"],
    }

with open("transactions.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["txn_id", "created_at", "amount", "currency", "merchant"])
    writer.writeheader()
    for txn in transactions:
        writer.writerow(prepare_row(txn))

# transactions.csv:
# txn_id,created_at,amount,currency,merchant
# a1b2c3d4-e5f6-7890-abcd-ef1234567890,2026-03-15T09:30:00+00:00,1249.99,USD,CloudHost Inc.
# b2c3d4e5-f6a7-8901-bcde-f12345678901,2026-03-15T14:12:00+00:00,87.50,EUR,DataSync GmbH

Fungsi prepare_row() adalah pendekatan yang tepat di sini. Daripada mencoba mengajarkan csv.DictWriter tentang tipe kustom, Anda menormalkan setiap record ke string sebelum menulis. Saya lebih suka memanggil .isoformat() secara eksplisit pada objek datetime daripada mengandalkan str() โ€” format outputnya lebih dapat diprediksi, dan parser downstream menangani ISO 8601 dengan andal.

Peringatan:Jika Anda membiarkan nilai Decimal melewati tanpa pemformatan, angka yang sangat kecil atau sangat besar mungkin ditampilkan dalam notasi ilmiah (mis., 1.5E+7). Selalu format Decimal dengan f-string eksplisit seperti f"{value:.2f}" saat menulis data keuangan ke CSV.

Pola alternatif untuk pipeline dengan banyak tipe kustom adalah memperluas json.JSONEncoder. Buat subclass-nya, timpa metode default() untuk mengembalikan nilai yang dapat diserialisasi JSON untuk setiap tipe kustom, lalu teruskan subclass sebagai argumen cls ke json.dumps(). Re-encoding melalui encoder kustom sebelum menulis ke CSV menormalkan semua tipe dalam satu langkah tanpa panggilan prepare_row() per baris. Pola prepare_row() yang ditunjukkan di atas lebih sederhana untuk skrip sekali pakai; pendekatan subclass JSONEncoder lebih skalabel ketika model domain yang sama dengan tipe kustom dibagikan ke banyak tahap pipeline atau microservice.

Referensi Parameter csv.DictWriter

Tanda tangan konstruktor lengkapnya adalah csv.DictWriter(f, fieldnames, restval="", extrasaction="raise", dialect="excel", **fmtparams). Sebagian besar memiliki default yang masuk akal. Yang benar-benar akan Anda ubah adalah fieldnames, delimiter, dan extrasaction.

Parameter
Tipe
Default
Deskripsi
f
objek file
(wajib)
Objek apa pun yang memiliki metode write() โ€” biasanya dari open()
fieldnames
sequence
(wajib)
Daftar kunci yang menentukan urutan kolom pada output CSV
restval
str
""
Nilai yang ditulis saat dict tidak memiliki kunci dari fieldnames
extrasaction
str
"raise"
"raise" melempar ValueError untuk kunci ekstra; "ignore" mengabaikannya secara diam-diam
dialect
str / Dialect
"excel"
Aturan pemformatan bawaan โ€” "excel", "excel-tab", atau "unix"
delimiter
str
","
Karakter tunggal pemisah kolom โ€” gunakan "\t" untuk output TSV
quotechar
str
"
Karakter yang digunakan untuk mengapit kolom yang mengandung delimiter
quoting
int
csv.QUOTE_MINIMAL
Mengontrol kapan pengapitan diterapkan โ€” MINIMAL, ALL, NONNUMERIC, NONE
lineterminator
str
"\r\n"
String yang ditambahkan setelah setiap baris โ€” timpa dengan "\n" untuk output gaya Unix

pandas โ€” Konversi JSON ke CSV dengan DataFrame

Jika Anda sudah bekerja di codebase yang banyak menggunakan pandas, atau JSON Anda memiliki objek bersarang yang perlu di-flatten, pendekatan pandas jauh lebih sedikit kode dibandingkan versi stdlib. Trade-off-nya: pandas adalah dependensi ~30 MB. Untuk skrip sekali pakai, itu tidak masalah. Untuk Docker image yang Anda kirim ke produksi, pendekatan stdlib membuat segalanya lebih ringan.

Python 3.8+ โ€” pandas read_json lalu to_csv
import pandas as pd

# Baca array JSON langsung ke DataFrame
df = pd.read_json("warehouse_inventory.json")

# Tulis ke CSV โ€” index=False mencegah nomor baris yang dibuat otomatis
df.to_csv("warehouse_inventory.csv", index=False)

# Hanya itu. Dua baris. pandas menyimpulkan tipe kolom secara otomatis.

Flag index=False adalah salah satu hal yang selalu Anda cari setiap saat. Tanpanya, pandas menulis kolom 0, 1, 2, ... sebagai kolom pertama CSV Anda. Tidak ada yang menginginkan itu.

Me-flatten JSON Bersarang dengan json_normalize

Respons API nyata jarang flat. Pesanan mengandung alamat pengiriman, pengguna mengandung preferensi bersarang, event telemetri mengandung metadata bersarang. pd.json_normalize() menelusuri dictionary bersarang dan me-flatten-nya menjadi kolom dengan nama berpisahkan titik.

Python 3.8+ โ€” flatten JSON bersarang menggunakan json_normalize
import json
import pandas as pd

api_response = """
[
  {
    "order_id": "ord_91a3",
    "placed_at": "2026-03-15T09:30:00Z",
    "customer": {
      "name": "Sarah Chen",
      "email": "s.chen@example.com",
      "tier": "premium"
    },
    "shipping": {
      "method": "express",
      "address": {
        "city": "Portland",
        "state": "OR",
        "zip": "97201"
      }
    },
    "total": 299.95
  },
  {
    "order_id": "ord_b7f2",
    "placed_at": "2026-03-15T14:12:00Z",
    "customer": {
      "name": "James Park",
      "email": "j.park@example.com",
      "tier": "standard"
    },
    "shipping": {
      "method": "standard",
      "address": {
        "city": "Austin",
        "state": "TX",
        "zip": "73301"
      }
    },
    "total": 87.50
  }
]
"""

orders = json.loads(api_response)

# json_normalize me-flatten dict bersarang โ€” sep mengontrol delimiter
df = pd.json_normalize(orders, sep="_")
df.to_csv("flat_orders.csv", index=False)

# Kolom yang dihasilkan:
# order_id, placed_at, customer_name, customer_email, customer_tier,
# shipping_method, shipping_address_city, shipping_address_state,
# shipping_address_zip, total

Parameter sep="_" mengontrol bagaimana nama kunci bersarang digabungkan. Default-nya adalah ".", yang menghasilkan kolom seperti customer.name. Saya lebih suka garis bawah karena titik dalam nama kolom menyebabkan masalah dengan impor SQL dan beberapa formula spreadsheet.

Untuk respons API yang membungkus array record di bawah kunci bersarang, gunakan parameter record_path. Jika respons terlihat seperti {"data": {"orders": [...]}}, teruskan record_path=["data", "orders"] untuk menavigasi ke daftar yang tepat. Parameter opsional meta memungkinkan Anda menarik kolom tingkat atas bersama record bersarang โ€” berguna ketika respons menyertakan info paginasi tingkat atas (nomor halaman, total jumlah) yang Anda inginkan sebagai kolom di setiap baris. Bersama-sama, record_path dan meta menangani sebagian besar bentuk respons API bersarang di dunia nyata tanpa pra-pemrosesan kustom.

Referensi Parameter DataFrame.to_csv()

DataFrame.to_csv() memiliki lebih dari 20 parameter. Berikut adalah yang penting untuk alur kerja JSON-ke-CSV.

Parameter
Tipe
Default
Deskripsi
path_or_buf
str / Path / None
None
Path file atau buffer โ€” None mengembalikan CSV sebagai string
sep
str
","
Delimiter kolom โ€” gunakan "\t" untuk TSV
index
bool
True
Tulis indeks baris sebagai kolom pertama โ€” hampir selalu diset ke False
columns
list
None
Pilih dan urutkan kolom pada output
header
bool / list
True
Tulis nama kolom โ€” set False saat menambahkan ke file yang sudah ada
encoding
str
"utf-8"
Encoding output โ€” gunakan "utf-8-sig" untuk kompatibilitas Excel di Windows
na_rep
str
""
Representasi string untuk nilai kosong (NaN, None)
quoting
int
csv.QUOTE_MINIMAL
Mengontrol kapan kolom dikutip
Python 3.8+ โ€” to_csv dengan override parameter umum
import pandas as pd

df = pd.read_json("telemetry_events.json")

# Output TSV dengan encoding eksplisit dan penanganan nilai kosong
df.to_csv(
    "telemetry_events.tsv",
    sep="\t",
    index=False,
    encoding="utf-8",
    na_rep="NULL",
    columns=["event_id", "timestamp", "source", "severity", "message"],
)

# Tulis ke stdout untuk piping dalam shell script
print(df.to_csv(index=False))

# Kembalikan sebagai string (tidak ada file yang ditulis)
csv_string = df.to_csv(index=False)
print(len(csv_string), "karakter")

Konversi JSON ke CSV dari File dan Respons API

Dua skenario paling umum di dunia nyata: membaca JSON dari file di disk dan mengonversinya, atau mengambil JSON dari API HTTP dan menyimpan hasilnya sebagai CSV. Dalam pengembangan Anda dapat lolos tanpa penanganan error. Dalam produksi, pilihan itu menjadi peringatan pukul 2 pagi. File mungkin tidak ada, API mungkin mengembalikan kode status 4xx atau 5xx alih-alih JSON, body respons mungkin berupa objek error bukan array, atau JSON mungkin terpotong karena timeout jaringan. Pola di bawah menangani semua kasus ini secara eksplisit, mencatat error ke stderr, dan mengembalikan jumlah baris sehingga pemanggil dapat mendeteksi output baris nol dan memberi peringatan.

File di Disk โ€” Baca, Konversi, Simpan

Python 3.8+ โ€” konversi file JSON ke CSV dengan penanganan error
import json
import csv
import sys

def json_file_to_csv(input_path: str, output_path: str) -> int:
    """Konversi file JSON yang berisi array objek ke CSV.
    Mengembalikan jumlah baris yang ditulis.
    """
    try:
        with open(input_path, encoding="utf-8") as jf:
            data = json.load(jf)
    except FileNotFoundError:
        print(f"Error: {input_path} tidak ditemukan", file=sys.stderr)
        return 0
    except json.JSONDecodeError as exc:
        print(f"Error: JSON tidak valid di {input_path}: {exc.msg} pada baris {exc.lineno}", file=sys.stderr)
        return 0

    if not isinstance(data, list) or not data:
        print(f"Error: diharapkan array JSON yang tidak kosong di {input_path}", file=sys.stderr)
        return 0

    # Kumpulkan semua kunci unik di semua record โ€” menangani skema yang tidak konsisten
    all_keys: list[str] = []
    seen: set[str] = set()
    for record in data:
        for key in record:
            if key not in seen:
                all_keys.append(key)
                seen.add(key)

    with open(output_path, "w", newline="", encoding="utf-8") as cf:
        writer = csv.DictWriter(cf, fieldnames=all_keys, restval="", extrasaction="ignore")
        writer.writeheader()
        writer.writerows(data)

    return len(data)

rows = json_file_to_csv("deploy_logs.json", "deploy_logs.csv")
print(f"Menulis {rows} baris ke deploy_logs.csv")

Respons API HTTP โ€” Ambil dan Konversi

Python 3.8+ โ€” ambil JSON dari API dan simpan sebagai CSV
import json
import csv
import urllib.request
import urllib.error

def api_response_to_csv(url: str, output_path: str) -> int:
    """Ambil JSON dari endpoint REST API dan tulis sebagai CSV."""
    try:
        req = urllib.request.Request(url, headers={"Accept": "application/json"})
        with urllib.request.urlopen(req, timeout=30) as resp:
            if resp.status != 200:
                print(f"Error: API mengembalikan status {resp.status}")
                return 0
            body = resp.read().decode("utf-8")
    except urllib.error.URLError as exc:
        print(f"Error: tidak dapat menjangkau {url}: {exc.reason}")
        return 0

    try:
        records = json.loads(body)
    except json.JSONDecodeError as exc:
        print(f"Error: API mengembalikan JSON yang tidak valid: {exc.msg}")
        return 0

    if not isinstance(records, list) or not records:
        print("Error: diharapkan array JSON yang tidak kosong dari API")
        return 0

    with open(output_path, "w", newline="", encoding="utf-8") as cf:
        writer = csv.DictWriter(cf, fieldnames=records[0].keys())
        writer.writeheader()
        writer.writerows(records)

    return len(records)

rows = api_response_to_csv(
    "https://api.internal.example.com/v2/deployments?status=completed",
    "completed_deployments.csv",
)
print(f"Mengekspor {rows} deployment ke CSV")
Catatan:Contoh di atas menggunakan urllib dari standard library untuk menjaga skrip bebas dependensi. Jika Anda memiliki requests terinstal, ganti bagian urllib dengan resp = requests.get(url, timeout=30); records = resp.json() โ€” kode penulisan CSV lainnya tetap identik.

Konversi JSON ke CSV via Command-Line

Terkadang Anda hanya membutuhkan satu baris di terminal. Flag -c Python memungkinkan Anda menjalankan konversi cepat tanpa membuat file skrip. Untuk transformasi yang lebih kompleks, arahkan melalui jq terlebih dahulu untuk membentuk ulang data, lalu konversi.

bash โ€” konversi json ke csv satu baris
# Python satu baris: membaca JSON dari stdin, menulis CSV ke stdout
cat orders.json | python3 -c "
import json, csv, sys
data = json.load(sys.stdin)
w = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
w.writeheader()
w.writerows(data)
"

# Simpan output ke file
cat orders.json | python3 -c "
import json, csv, sys
data = json.load(sys.stdin)
w = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
w.writeheader()
w.writerows(data)
" > orders.csv
bash โ€” skrip CLI mandiri dengan argparse
# Simpan sebagai json2csv.py dan jalankan: python3 json2csv.py input.json -o output.csv
python3 -c "
import json, csv, argparse, sys

parser = argparse.ArgumentParser(description='Konversi array JSON ke CSV')
parser.add_argument('input', help='Path ke file JSON')
parser.add_argument('-o', '--output', default=None, help='Path CSV output (default: stdout)')
parser.add_argument('-d', '--delimiter', default=',', help='Delimiter CSV')
args = parser.parse_args()

with open(args.input) as f:
    data = json.load(f)

out = open(args.output, 'w', newline='') if args.output else sys.stdout
writer = csv.DictWriter(out, fieldnames=data[0].keys(), delimiter=args.delimiter)
writer.writeheader()
writer.writerows(data)
if args.output:
    out.close()
    print(f'Menulis {len(data)} baris ke {args.output}', file=sys.stderr)
" "$@"
bash โ€” menggunakan jq + csvkit untuk transformasi kompleks
# Instal csvkit: pip install csvkit

# jq me-flatten dan memilih kolom, in2csv menangani pemformatan CSV
cat api_response.json | jq '[.[] | {id: .order_id, customer: .customer.name, total}]' | in2csv -f json > orders.csv

# Miller (mlr) adalah opsi lain untuk JSON-ke-CSV
mlr --json2csv cat orders.json > orders.csv

Miller (mlr) adalah binary mandiri yang memperlakukan JSON, CSV, dan TSV sebagai format kelas pertama tanpa runtime Python yang diperlukan. Flag --json2csv mengonversi input JSON ke CSV dalam satu langkah, dan Anda dapat merangkai verb Miller untuk memfilter, mengurutkan, atau mengganti nama kolom dalam perintah yang sama sebelum menulis output. Instal via Homebrew di macOS (brew install miller) atau package manager Linux Anda. Ini sangat berguna dalam pipeline CI di mana Anda ingin konversi JSON-ke-CSV yang cepat tanpa menjalankan lingkungan Python.

Alternatif Performa Tinggi โ€” pandas dengan pyarrow

Untuk dataset dalam kisaran puluhan juta baris, pandas dengan backend pyarrow membaca dan menulis jauh lebih cepat daripada default. Engine Arrow berbasis C memproses data kolumnar lebih efisien daripada modul csv baris-per-baris Python. API-nya tetap sama โ€” Anda hanya mengatur parameter engine.

bash โ€” instal pyarrow
pip install pyarrow
Python 3.8+ โ€” pandas dengan pyarrow untuk penulisan CSV yang lebih cepat
import pandas as pd

# Baca JSON dengan engine pyarrow (parsing lebih cepat untuk file besar)
df = pd.read_json("sensor_readings.json", engine="pyarrow")

# to_csv tidak memiliki parameter engine, tetapi operasi DataFrame
# antara baca dan tulis mendapat manfaat dari layout kolumnar pyarrow
df.to_csv("sensor_readings.csv", index=False)

# Untuk ekspor yang benar-benar besar, pertimbangkan menulis ke Parquet alih-alih CSV
# โ€” format biner, 5-10x lebih kecil, mempertahankan tipe
df.to_parquet("sensor_readings.parquet", engine="pyarrow")

Jika Anda memproses lebih dari beberapa ratus MB JSON dan konsumen akhir menerima Parquet, lewati CSV sama sekali. Parquet lebih kecil, mempertahankan tipe kolom, dan baik Redshift maupun BigQuery memuatnya secara native. CSV adalah format yang lossy โ€” setiap nilai menjadi string.

Output Terminal dengan Syntax Highlighting

Library rich merender tabel dengan border, perataan, dan warna di terminal โ€” berguna untuk melihat pratinjau konversi selama pengembangan tanpa membuka file output.

bash โ€” instal rich
pip install rich
Python 3.8+ โ€” pratinjau output CSV di terminal dengan rich
import json
from rich.console import Console
from rich.table import Table

json_string = """
[
  {"hostname": "web-prod-1", "cpu_percent": 72.3, "memory_mb": 3840, "uptime_hours": 720},
  {"hostname": "web-prod-2", "cpu_percent": 45.1, "memory_mb": 2560, "uptime_hours": 168},
  {"hostname": "db-replica-1", "cpu_percent": 91.7, "memory_mb": 7680, "uptime_hours": 2160}
]
"""

records = json.loads(json_string)
console = Console()

table = Table(title="Pratinjau Metrik Server", show_lines=True)
for key in records[0]:
    table.add_column(key, style="cyan" if key == "hostname" else "white")

for row in records:
    table.add_row(*[str(v) for v in row.values()])

console.print(table)
# Merender tabel bersorot warna dengan border di terminal
Peringatan:Rich hanya untuk tampilan terminal. Jangan gunakan untuk membuat file CSV โ€” ia menambahkan kode escape ANSI yang akan merusak output. Tulis ke file dengan csv.DictWriter atau DataFrame.to_csv(), dan gunakan rich hanya untuk pratinjau.

Bekerja dengan File JSON Besar

json.load() membaca seluruh file ke dalam memori. Untuk file JSON 200 MB, itu berarti ~200 MB teks mentah ditambah overhead objek Python โ€” dengan mudah 500 MB+ penggunaan heap. Untuk file di atas 100 MB, stream input dengan ijson dan tulis baris CSV saat Anda berjalan.

bash โ€” instal ijson
pip install ijson

Streaming Array JSON ke CSV dengan ijson

Python 3.8+ โ€” stream array JSON besar ke CSV dengan memori konstan
import ijson
import csv

def stream_json_to_csv(json_path: str, csv_path: str) -> int:
    """Konversi array JSON besar ke CSV tanpa memuatnya semua ke memori."""
    with open(json_path, "rb") as jf, open(csv_path, "w", newline="", encoding="utf-8") as cf:
        # ijson.items menghasilkan setiap elemen array tingkat atas satu per satu
        records = ijson.items(jf, "item")

        first_record = next(records)
        fieldnames = list(first_record.keys())

        writer = csv.DictWriter(cf, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow(first_record)

        count = 1
        for record in records:
            writer.writerow(record)
            count += 1

    return count

rows = stream_json_to_csv("clickstream_2026_03.json", "clickstream_2026_03.csv")
print(f"Streaming {rows} record ke CSV")

NDJSON / JSON Lines โ€” Satu Objek Per Baris

NDJSON (Newline-Delimited JSON), juga disebut JSON Lines atau .jsonl, menyimpan satu objek JSON valid per baris tanpa array pembungkus. Format ini umum dalam pipeline log, stream event (Kafka, Kinesis), dan ekspor massal dari layanan seperti Elasticsearch dan BigQuery. Karena setiap baris adalah objek JSON yang mandiri, Anda dapat memproses file NDJSON dengan loop Python biasa for atas file handle โ€” tidak perlu library ijson. Memori tetap konstan terlepas dari ukuran file, menjadikan ini pendekatan streaming paling sederhana ketika data sumber Anda sudah dalam format JSON Lines.

Python 3.8+ โ€” konversi NDJSON ke CSV baris per baris
import json
import csv

def ndjson_to_csv(ndjson_path: str, csv_path: str) -> int:
    """Konversi file JSON newline-delimited ke CSV, satu baris sekaligus."""
    with open(ndjson_path, encoding="utf-8") as nf:
        first_line = nf.readline()
        first_record = json.loads(first_line)
        fieldnames = list(first_record.keys())

        with open(csv_path, "w", newline="", encoding="utf-8") as cf:
            writer = csv.DictWriter(cf, fieldnames=fieldnames)
            writer.writeheader()
            writer.writerow(first_record)

            count = 1
            for line in nf:
                line = line.strip()
                if not line:
                    continue
                try:
                    record = json.loads(line)
                    writer.writerow(record)
                    count += 1
                except json.JSONDecodeError:
                    continue  # lewati baris yang cacat

    return count

rows = ndjson_to_csv("access_log.ndjson", "access_log.csv")
print(f"Mengonversi {rows} entri log ke CSV")
Catatan:Beralih ke streaming ketika file JSON melebihi 100 MB. Array JSON 1 GB yang dimuat dengan json.load() dapat mengonsumsi 3โ€“5 GB RAM karena overhead objek Python. Dengan ijson, memori tetap flat terlepas dari ukuran file. Jika Anda hanya perlu konversi cepat file kecil, tempel saja ke konverter JSON ke CSV sebagai gantinya.

Kesalahan Umum

โŒ Lupa newline='' di open() โ€” baris kosong di Windows

Masalah: Modul csv menulis akhiran baris \r\n. Tanpa newline='', mode teks Python menambahkan \r lagi di Windows, menghasilkan output dengan spasi ganda.

Solusi: Selalu teruskan newline='' saat membuka file untuk penulisan CSV. Tidak berbahaya di macOS/Linux.

Before ยท Python
After ยท Python
with open("output.csv", "w") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Baris kosong di antara setiap baris data di Windows
with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Output bersih di semua platform
โŒ Lupa index=False di pandas to_csv()

Masalah: Tanpa index=False, pandas menambahkan kolom nomor baris auto-increment (0, 1, 2, ...) yang mencemari CSV dengan data yang tidak pernah ada di JSON asli.

Solusi: Teruskan index=False ke to_csv(). Jika Anda benar-benar membutuhkan kolom indeks, beri nama secara eksplisit dengan df.index.name = 'row_num'.

Before ยท Python
After ยท Python
df = pd.read_json("events.json")
df.to_csv("events.csv")
# CSV mendapat kolom ekstra yang tidak bernama: ,event_id,timestamp,...
# Koma terdepan merusak banyak parser CSV
df = pd.read_json("events.json")
df.to_csv("events.csv", index=False)
# CSV bersih: event_id,timestamp,...
โŒ Menggunakan records[0].keys() saat record memiliki kunci yang tidak konsisten

Masalah: Jika objek JSON memiliki kunci yang berbeda (beberapa record memiliki kolom opsional), menggunakan kunci record pertama sebagai fieldnames secara diam-diam melewatkan kolom yang hanya muncul di record berikutnya.

Solusi: Kumpulkan semua kunci unik di semua record sebelum membuat DictWriter.

Before ยท Python
After ยท Python
records = json.load(f)
writer = csv.DictWriter(out, fieldnames=records[0].keys())
# Melewatkan kolom "discount" yang hanya muncul di records[2]
records = json.load(f)
all_keys = list(dict.fromkeys(k for r in records for k in r))
writer = csv.DictWriter(out, fieldnames=all_keys, restval="")
# Setiap kunci dari setiap record disertakan sebagai kolom
โŒ Menulis dict bersarang langsung ke CSV tanpa flattening

Masalah: csv.DictWriter memanggil str() pada dict bersarang, menghasilkan kolom dengan nilai seperti "{'city': 'Portland'}"โ€” repr Python mentah, bukan data sebenarnya.

Solusi: Flatten objek bersarang terlebih dahulu menggunakan pd.json_normalize() atau fungsi flattening kustom.

Before ยท Python
After ยท Python
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
writer = csv.DictWriter(f, fieldnames=["id", "meta"])
writer.writerows(records)
# kolom meta berisi: {'source': 'web', 'region': 'us-west'}
import pandas as pd
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
df = pd.json_normalize(records, sep="_")
df.to_csv("events.csv", index=False)
# Kolom: id, meta_source, meta_region

csv.DictWriter vs pandas โ€” Perbandingan Cepat

Metode
JSON Bersarang
Tipe Kustom
Streaming
Dependensi
Perlu Instalasi
csv.DictWriter
โœ— (flatten manual)
โœ—
โœ“ (baris per baris)
Tidak ada
Tidak (stdlib)
csv.writer
โœ—
โœ—
โœ“ (baris per baris)
Tidak ada
Tidak (stdlib)
pd.DataFrame.to_csv()
โœ— (hanya flat)
โœ“ (via dtypes)
โœ—
pandas + numpy
pip install
pd.json_normalize() + to_csv()
โœ“
โœ“ (via dtypes)
โœ—
pandas + numpy
pip install
csv.writer + json_flatten
โœ“
โœ—
โœ“
flatten_json
pip install
jq + csvkit (CLI)
โœ“ (via jq)
N/A
โœ“
jq, csvkit
Instalasi sistem

Gunakan csv.DictWriter ketika Anda membutuhkan nol dependensi, JSON Anda flat, dan skrip berjalan di lingkungan terbatas (container CI, fungsi Lambda, Python tertanam). Gunakan pd.json_normalize() + to_csv() ketika JSON bersarang, Anda perlu mengubah atau memfilter data sebelum ekspor, atau Anda sudah dalam alur kerja pandas. Untuk file yang tidak muat di memori, kombinasikan ijson dengan csv.DictWriter untuk streaming dengan memori konstan.

Untuk konversi cepat tanpa kode, gunakan konverter JSON ke CSV di ToolDeck tanpa setup Python apa pun.

Pertanyaan yang Sering Diajukan

Bagaimana cara mengonversi JSON ke CSV di Python tanpa pandas?

Gunakan modul bawaan json dan csv. Panggil json.load() untuk mem-parse file JSON menjadi daftar dict, ekstrak fieldnames dari kunci dict pertama, buat csv.DictWriter, panggil writeheader(), lalu writerows(). Pendekatan ini tidak memiliki dependensi eksternal dan berjalan di lingkungan Python 3.x mana pun. Pendekatan ini juga lebih cepat dari pandas untuk file kecil karena tidak ada overhead alokasi DataFrame. Jika objek JSON memiliki kunci yang tidak konsisten antar record, kumpulkan semua kunci unik terlebih dahulu dengan dict.fromkeys(k for r in records for k in r) sebelum meneruskannya sebagai fieldnames untuk menghindari kolom yang hilang.

Python
import json
import csv

with open("orders.json") as f:
    records = json.load(f)

with open("orders.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=records[0].keys())
    writer.writeheader()
    writer.writerows(records)

Bagaimana cara menangani JSON bersarang saat mengonversi ke CSV?

Array JSON flat langsung dipetakan ke baris CSV, tetapi objek bersarang perlu di-flatten terlebih dahulu. Dengan pandas, pd.json_normalize() menangani ini secara otomatis โ€” ia menggabungkan kunci bersarang dengan pemisah titik (misalnya, "address.city"). Tanpa pandas, tulis fungsi rekursif yang menelusuri dict dan menggabungkan kunci dengan delimiter. Untuk struktur bersarang dalam dengan beberapa level, json_normalize menangani semuanya dalam satu langkah. Parameter sep mengontrol karakter penghubung antar segmen kunci โ€” garis bawah biasanya lebih aman daripada titik default untuk impor SQL dan kompatibilitas formula spreadsheet.

Python
import pandas as pd

nested_data = [
    {"id": "ord_91a3", "customer": {"name": "Siti Rahayu", "email": "s.rahayu@contoh.com"}},
]
df = pd.json_normalize(nested_data, sep="_")
# Kolom: id, customer_name, customer_email
df.to_csv("flat_orders.csv", index=False)

Mengapa CSV saya memiliki baris kosong di antara baris data di Windows?

Modul csv menulis akhiran baris \r\n secara default. Di Windows, membuka file dalam mode teks menambahkan \r lagi, menghasilkan \r\r\n โ€” yang ditampilkan sebagai baris kosong. Solusinya adalah selalu meneruskan newline="" ke open(). Ini memberi tahu Python untuk tidak menerjemahkan akhiran baris, membiarkan modul csv menanganinya. Pola ini diperlukan terlepas dari sistem operasi โ€” tidak berbahaya di macOS dan Linux, dan kritis di Windows. Dokumentasi Python secara eksplisit menyebutkan ini di bagian modul csv sebagai cara yang benar untuk membuka file untuk penulisan CSV.

Python
# Salah โ€” baris kosong di Windows
with open("output.csv", "w") as f:
    writer = csv.writer(f)

# Benar โ€” newline="" mencegah \r ganda
with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)

Bagaimana cara menambahkan record JSON ke file CSV yang sudah ada?

Buka file dalam mode tambah ("a") dan buat DictWriter dengan fieldnames yang sama. Lewati writeheader() karena baris header sudah ada. Dengan pandas, gunakan to_csv(mode="a", header=False). Pastikan urutan kolom sesuai dengan file yang ada, atau data akan berada di kolom yang salah. Jika tidak yakin tentang urutan kolom dalam file yang ada, buka dulu dengan csv.DictReader dan baca fieldnames dari atribut fieldnames-nya sebelum membuat writer untuk penambahan.

Python
import csv

new_records = [
    {"order_id": "ord_f4c1", "total": 89.50, "status": "shipped"},
]

with open("orders.csv", "a", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["order_id", "total", "status"])
    writer.writerows(new_records)

Apa cara tercepat untuk mengonversi file JSON besar ke CSV di Python?

Untuk file di bawah 500 MB, pd.read_json() diikuti oleh to_csv() adalah pendekatan tercepat dalam satu panggilan โ€” pandas menggunakan kode C yang dioptimalkan secara internal. Untuk file di atas 500 MB, gunakan ijson untuk mem-stream record JSON dan tulis ke CSV dengan csv.DictWriter baris per baris. Ini menjaga penggunaan memori tetap konstan terlepas dari ukuran file. Untuk file NDJSON (satu objek JSON per baris), Anda tidak perlu ijson sama sekali โ€” loop Python biasa atas file handle memproses setiap baris secara independen dan mencapai memori konstan tanpa library pihak ketiga.

Python
# Cepat untuk file yang muat di memori
import pandas as pd
df = pd.read_json("large_dataset.json")
df.to_csv("large_dataset.csv", index=False)

# Streaming untuk file yang tidak muat di memori
import ijson, csv
with open("huge.json", "rb") as jf, open("huge.csv", "w", newline="") as cf:
    records = ijson.items(jf, "item")
    first = next(records)
    writer = csv.DictWriter(cf, fieldnames=first.keys())
    writer.writeheader()
    writer.writerow(first)
    for record in records:
        writer.writerow(record)

Bisakah saya menulis output CSV ke stdout alih-alih file di Python?

Ya. Teruskan sys.stdout sebagai objek file ke csv.writer() atau csv.DictWriter(). Ini berguna untuk mengarahkan output di shell script atau debugging cepat. Dengan pandas, panggil to_csv(sys.stdout, index=False) atau to_csv(None) untuk mendapatkan string yang bisa dicetak. Tidak perlu file sementara. Saat menulis ke stdout di Windows, panggil sys.stdout.reconfigure(newline="") terlebih dahulu untuk menghindari masalah carriage-return ganda, karena stdout dibuka dalam mode teks secara default.

Python
import csv
import sys
import json

data = json.loads('[{"host":"web-1","cpu":72.3},{"host":"web-2","cpu":45.1}]')
writer = csv.DictWriter(sys.stdout, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
# host,cpu
# web-1,72.3
# web-2,45.1

Alat Terkait

MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

PS
Priya SharmaPeninjau teknis

Priya is a data scientist and machine learning engineer who has worked across the full Python data stack โ€” from raw data ingestion and cleaning to model deployment and monitoring. She is passionate about reproducible research, Jupyter-based workflows, and the practical engineering side of ML. She writes about NumPy, Pandas, data serialisation, and the Python patterns that make data pipelines reliable at scale.