JSON to CSV Python — DictWriter + pandas Beispiele

·Backend Developer·Geprüft vonPriya Sharma·Veröffentlicht

Nutze das kostenlose JSON to CSV direkt im Browser – keine Installation erforderlich.

JSON to CSV online testen →

Nahezu jede Datenpipeline stößt irgendwann auf denselben Schritt: Eine API gibt JSON zurück, aber der nächste Verbraucher — ein Tabellenkalkulationsprogramm, ein Import-Skript, ein Redshift-COPY-Befehl — benötigt CSV. Die Konvertierung von JSON zu CSV in Python klingt trivial, bis man auf verschachtelte Objekte, inkonsistente Schlüssel oder Datetime-Werte trifft, die eine spezielle Behandlung erfordern. Python bietet zwei solide Wege: die eingebauten json + csv Module für Skripte ohne externe Abhängigkeiten, und pandas für das Abflachen verschachtelter Strukturen und größere Datensätze — oder den Online-JSON-zu-CSV-Konverter für schnelle Einzel-Konvertierungen ohne Code. Dieser Leitfaden behandelt beide Ansätze von Anfang bis Ende, mit ausführbaren Python-3.8+-Beispielen.

  • csv.DictWriter konvertiert eine Liste von Dicts ohne Abhängigkeiten in CSV — json.load() zum Parsen verwenden, dann writeheader() + writerows().
  • CSV-Dateien unter Windows immer mit newline="" öffnen, um leere Zeilen zwischen Datenzeilen zu verhindern.
  • pd.json_normalize() flacht verschachteltes JSON in ein flaches DataFrame ab, bevor to_csv() aufgerufen wird — behandelt mehrstufige Verschachtelungen automatisch.
  • index=False an DataFrame.to_csv() übergeben — ohne diese Option schreibt pandas eine unerwünschte Zeilennummern-Spalte.
  • Für Dateien über 500 MB ijson für das Streaming-JSON-Parsing in Kombination mit csv.DictWriter für konstante Speichernutzung verwenden.

Was ist JSON-zu-CSV-Konvertierung?

Die JSON-zu-CSV-Konvertierung transformiert ein Array von JSON-Objekten in ein tabellarisches Format, bei dem jedes Objekt zu einer Zeile und jeder Schlüssel zu einer Spaltenüberschrift wird. JSON ist hierarchisch — Objekte können beliebig tief verschachtelt sein. CSV ist flach — jeder Wert sitzt in einem Zeilen-Spalten-Raster. Die Konvertierung funktioniert reibungslos, wenn jedes Objekt denselben Satz von Schlüsseln auf oberster Ebene teilt. Verschachtelte Objekte, Arrays und inkonsistente Schlüssel machen die Sache komplizierter. Die Rohdaten bleiben identisch; nur die Struktur ändert sich.

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 — JSON ohne pandas in CSV konvertieren

Das csv-Modul ist in jeder Python-Installation enthalten. Kein pip install, keine Virtual-Environment-Verrenkungen. csv.DictWriter nimmt eine Liste von Dictionaries entgegen und schreibt jedes als CSV-Zeile, wobei Dict-Schlüssel auf Spaltenüberschriften abgebildet werden. Der fieldnames-Parameter steuert sowohl die Spaltenreihenfolge als auch, welche Schlüssel eingeschlossen werden.

Python 3.8+ — minimales json-zu-csv-Beispiel
import json
import csv

# Beispiel-JSON-Daten — ein Array von Bestellobjekten
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

Das Argument newline="" bei open() ist unter Windows nicht optional. Ohne es entstehen doppelte Wagenrückläufe — die in Excel als Leerzeilen zwischen jeder Datenzeile erscheinen. Unter macOS und Linux ist es harmlos, also immer angeben.

Der obige Code verwendet json.loads() für einen String. Verwende json.load() (ohne abschließendes s), wenn aus einem Datei-Handle gelesen wird. Das verwirrt ständig — die eine Funktion liest einen String, die andere ein Datei-Objekt.

Python 3.8+ — JSON-Datei lesen, CSV-Datei schreiben
import json
import csv

with open("server_metrics.json", encoding="utf-8") as jf:
    metrics = json.load(jf)  # json.load() für Datei-Objekte

# Explizite Feldnamen steuern die Spaltenreihenfolge
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)

# Es erscheinen nur die fünf angegebenen Spalten in genau dieser Reihenfolge

Das Setzen von extrasaction="ignore" verwirft stillschweigend alle Schlüssel in den Dicts, die nicht in der fieldnames-Liste stehen. Der Standard ist "raise", der einen ValueError auslöst, wenn ein Dict einen unerwarteten Schlüssel hat. Wähle das, was zu deiner Fehlertoleranz passt.

Hinweis:csv.DictWriter vs. csv.writer: DictWriter ordnet Dict-Schlüssel automatisch Spaltenpositionen zu. csv.writer schreibt rohe Listen als Zeilen — die Spaltenreihenfolge muss selbst verwaltet werden. DictWriter ist für JSON-zu-CSV fast immer die richtige Wahl, da JSON-Datensätze bereits Dictionaries sind.

Das csv-Modul wird mit drei benannten Dialekten geliefert: excel (Komma als Trennzeichen, CRLF-Zeilenenden — der Standard), excel-tab (Tabulator als Trennzeichen, CRLF-Enden) und unix (LF-Zeilenenden, alle nicht-numerischen Felder werden in Anführungszeichen gesetzt). Den Dialektnamen als dialect-Argument an csv.DictWriter übergeben. Mit csv.register_dialect() kann auch ein benutzerdefinierter Dialekt definiert werden, wenn das Zielsystem ungewöhnliche Anführungszeichen- oder Trennzeichenregeln hat. Für die meisten JSON-zu-CSV-Workflows ist der excel-Dialekt korrekt, aber auf unix wechseln, wenn Dateien von POSIX-Tools wie awk oder sort verarbeitet werden.

Umgang mit nicht-standardmäßigen Typen: datetime, UUID und Decimal

JSON von APIs enthält Datumsangaben häufig als ISO-Strings, UUIDs als Bindestriche-Strings und Geldbeträge als Floats. Wenn diese vor dem Schreiben der CSV in Python-Objekte umgewandelt werden, müssen sie wieder in Strings zurückkonvertiert werden. Das csv-Modul ruft str() für jeden Wert auf, sodass die meisten Typen einfach funktionieren. Aber datetime-Objekte erzeugen unübersichtliche Standard-String-Darstellungen, und Decimal-Werte müssen explizit formatiert werden, um wissenschaftliche Notation zu vermeiden.

Python 3.8+ — datetime und Decimal vor dem CSV-Schreiben vorverarbeiten
import json
import csv
from datetime import datetime, timezone
from decimal import Decimal
from uuid import UUID

# Simulation einer geparsten API-Antwort mit Python-Typen
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:
    """Nicht-String-Typen in CSV-freundliche Strings konvertieren."""
    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

Die Funktion prepare_row() ist hier der richtige Ansatz. Anstatt zu versuchen, csv.DictWriter benutzerdefinierte Typen beibringen zu wollen, normalisiert man jeden Datensatz vor dem Schreiben in Strings. Es empfiehlt sich, .isoformat() bei datetime-Objekten explizit aufzurufen, anstatt sich auf str() zu verlassen — das Ausgabeformat ist vorhersehbarer, und nachgelagerte Parser verarbeiten ISO 8601 zuverlässig.

Warnung:Wenn Decimal-Werte ohne Formatierung durchgelassen werden, können sehr kleine oder sehr große Zahlen in wissenschaftlicher Notation erscheinen (z. B. 1.5E+7). Decimal beim Schreiben von Finanzdaten in CSV immer mit einem expliziten f-String wie f"{value:.2f}" formatieren.

Ein alternatives Muster für Pipelines mit vielen benutzerdefinierten Typen ist die Erweiterung von json.JSONEncoder. Davon ableiten, die default()-Methode überschreiben, um für jeden benutzerdefinierten Typ einen JSON-serialisierbaren Wert zurückzugeben, und dann die Unterklasse als cls-Argument an json.dumps() übergeben. Das erneute Kodieren über den benutzerdefinierten Encoder vor dem CSV-Schreiben normalisiert alle Typen in einem Schritt, ohne einen zeilenweisen prepare_row()-Aufruf. Das oben gezeigte prepare_row()-Muster ist einfacher für Einzel-Skripte; der JSONEncoder-Unterklasse-Ansatz skaliert besser, wenn dasselbe Domänenmodell mit benutzerdefinierten Typen über viele Pipeline-Stufen oder Microservices hinweg geteilt wird.

csv.DictWriter — Parameterreferenz

Die vollständige Konstruktorsignatur lautet csv.DictWriter(f, fieldnames, restval="", extrasaction="raise", dialect="excel", **fmtparams). Die meisten davon haben sinnvolle Standardwerte. Die, die tatsächlich geändert werden, sind fieldnames, delimiter und extrasaction.

Parameter
Typ
Standard
Beschreibung
f
file object
(erforderlich)
Beliebiges Objekt mit einer write()-Methode — typischerweise von open()
fieldnames
sequence
(erforderlich)
Liste der Schlüssel, die die Spaltenreihenfolge in der CSV-Ausgabe festlegt
restval
str
""
Wert, der geschrieben wird, wenn einem Dict ein Schlüssel aus fieldnames fehlt
extrasaction
str
"raise"
"raise" löst ValueError bei unbekannten Schlüsseln aus; "ignore" verwirft sie stillschweigend
dialect
str / Dialect
"excel"
Vordefinierte Formatierungsregeln — "excel", "excel-tab" oder "unix"
delimiter
str
","
Einzelnes Zeichen zur Feldtrennung — "\t" für TSV-Ausgabe verwenden
quotechar
str
"
Zeichen zum Einschließen von Feldern, die das Trennzeichen enthalten
quoting
int
csv.QUOTE_MINIMAL
Steuert, wann Anführungszeichen gesetzt werden — MINIMAL, ALL, NONNUMERIC, NONE
lineterminator
str
"\r\n"
Zeichenkette nach jeder Zeile — auf "\n" überschreiben für Unix-kompatible Ausgabe

pandas — JSON mit DataFrames in CSV konvertieren

Wenn bereits in einer pandas-lastigen Codebasis gearbeitet wird oder das JSON verschachtelte Objekte enthält, die abgeflacht werden müssen, ist der pandas-Ansatz deutlich weniger Code als die stdlib-Version. Der Kompromiss: pandas ist eine ~30-MB-Abhängigkeit. Für ein Wegwerf-Skript ist das in Ordnung. Für ein Docker-Image, das in die Produktion geht, hält der stdlib-Ansatz die Dinge schlanker.

Python 3.8+ — pandas read_json dann to_csv
import pandas as pd

# JSON-Array direkt in einen DataFrame einlesen
df = pd.read_json("warehouse_inventory.json")

# In CSV schreiben — index=False verhindert die automatisch generierten Zeilennummern
df.to_csv("warehouse_inventory.csv", index=False)

# Das war's. Zwei Zeilen. pandas erkennt Spaltentypen automatisch.

Das Flag index=False ist eines dieser Dinge, die man jedes Mal nachschlagen muss. Ohne es schreibt pandas eine 0, 1, 2, ...-Spalte als erste Spalte der CSV. Das will niemand.

Verschachteltes JSON mit json_normalize abflachen

Echte API-Antworten sind selten flach. Bestellungen enthalten Lieferadressen, Benutzer enthalten verschachtelte Einstellungen, Telemetrieereignisse enthalten verschachtelte Metadaten. pd.json_normalize() durchläuft verschachtelte Dictionaries und flacht sie in Spalten mit punktgetrennten Namen ab.

Python 3.8+ — verschachteltes JSON mit json_normalize abflachen
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 flacht verschachtelte Dicts ab — sep steuert das Trennzeichen
df = pd.json_normalize(orders, sep="_")
df.to_csv("flat_orders.csv", index=False)

# Resultierende Spalten:
# order_id, placed_at, customer_name, customer_email, customer_tier,
# shipping_method, shipping_address_city, shipping_address_state,
# shipping_address_zip, total

Der Parameter sep="_" steuert, wie verschachtelte Schlüsselnamen verbunden werden. Der Standard ist ".", was Spalten wie customer.name erzeugt. Unterstriche sind vorzuziehen, da Punkte in Spaltennamen bei SQL-Importen und manchen Tabellenkalkulationsformeln Probleme bereiten.

Für API-Antworten, die das Datensatz-Array unter einem verschachtelten Schlüssel verpacken, den Parameter record_path verwenden. Wenn die Antwort wie {"data": {"orders": [...]}} aussieht, record_path=["data", "orders"] übergeben, um zur richtigen Liste zu navigieren. Der optionale meta-Parameter ermöglicht es, übergeordnete Felder neben den verschachtelten Datensätzen zu extrahieren — nützlich, wenn die Antwort Paginierungsinformationen auf oberster Ebene (Seitennummer, Gesamtanzahl) enthält, die als Spalte in jeder Zeile erscheinen sollen. Zusammen behandeln record_path und meta die meisten realen verschachtelten API-Antwortstrukturen ohne benutzerdefinierte Vorverarbeitung.

DataFrame.to_csv() — Parameterreferenz

DataFrame.to_csv() hat über 20 Parameter. Dies sind die relevanten für JSON-zu-CSV-Workflows.

Parameter
Typ
Standard
Beschreibung
path_or_buf
str / Path / None
None
Dateipfad oder Puffer — None gibt die CSV als String zurück
sep
str
","
Feldtrennzeichen — "\t" für TSV verwenden
index
bool
True
Zeilenindex als erste Spalte schreiben — fast immer auf False setzen
columns
list
None
Spalten in der Ausgabe einschränken und neu anordnen
header
bool / list
True
Spaltennamen schreiben — False setzen beim Anhängen an bestehende Datei
encoding
str
"utf-8"
Ausgabe-Kodierung — "utf-8-sig" für Excel-Kompatibilität unter Windows verwenden
na_rep
str
""
Zeichenkettendarstellung für fehlende Werte (NaN, None)
quoting
int
csv.QUOTE_MINIMAL
Steuert, wann Felder mit Anführungszeichen versehen werden
Python 3.8+ — to_csv mit häufigen Parameter-Überschreibungen
import pandas as pd

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

# TSV-Ausgabe mit expliziter Kodierung und Behandlung fehlender Werte
df.to_csv(
    "telemetry_events.tsv",
    sep="\t",
    index=False,
    encoding="utf-8",
    na_rep="NULL",
    columns=["event_id", "timestamp", "source", "severity", "message"],
)

# Auf stdout schreiben für das Weiterleiten in Shell-Skripten
print(df.to_csv(index=False))

# Als String zurückgeben (keine Datei geschrieben)
csv_string = df.to_csv(index=False)
print(len(csv_string), "Zeichen")

JSON aus einer Datei und API-Antwort in CSV konvertieren

Die zwei häufigsten realen Szenarien: JSON aus einer Datei auf dem Datenträger lesen und konvertieren, oder JSON von einer HTTP-API abrufen und das Ergebnis als CSV speichern. In der Entwicklung kann man auf Fehlerbehandlung verzichten. In der Produktion wird diese Entscheidung zu einem Alarm um 2 Uhr morgens. Dateien könnten nicht existieren, APIs könnten 4xx- oder 5xx-Statuscodes statt JSON zurückgeben, der Antwortinhalt könnte ein Fehlerobjekt statt eines Arrays sein, oder das JSON könnte durch ein Netzwerk-Timeout abgeschnitten sein. Die folgenden Muster behandeln all diese Fälle explizit, protokollieren Fehler auf stderr und geben eine Zeilenanzahl zurück, damit Aufrufer Null-Zeilen-Ausgaben erkennen und entsprechend alarmieren können.

Datei auf dem Datenträger — Lesen, Konvertieren, Speichern

Python 3.8+ — JSON-Datei mit Fehlerbehandlung in CSV konvertieren
import json
import csv
import sys

def json_file_to_csv(input_path: str, output_path: str) -> int:
    """Eine JSON-Datei mit einem Array von Objekten in CSV konvertieren.
    Gibt die Anzahl der geschriebenen Zeilen zurück.
    """
    try:
        with open(input_path, encoding="utf-8") as jf:
            data = json.load(jf)
    except FileNotFoundError:
        print(f"Fehler: {input_path} nicht gefunden", file=sys.stderr)
        return 0
    except json.JSONDecodeError as exc:
        print(f"Fehler: ungültiges JSON in {input_path}: {exc.msg} in Zeile {exc.lineno}", file=sys.stderr)
        return 0

    if not isinstance(data, list) or not data:
        print(f"Fehler: erwartet ein nicht-leeres JSON-Array in {input_path}", file=sys.stderr)
        return 0

    # Alle eindeutigen Schlüssel über alle Datensätze sammeln — behandelt inkonsistente Schemata
    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"{rows} Zeilen in deploy_logs.csv geschrieben")

HTTP-API-Antwort — Abrufen und Konvertieren

Python 3.8+ — JSON von API abrufen und als CSV speichern
import json
import csv
import urllib.request
import urllib.error

def api_response_to_csv(url: str, output_path: str) -> int:
    """JSON von einem REST-API-Endpunkt abrufen und als CSV schreiben."""
    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"Fehler: API hat Status {resp.status} zurückgegeben")
                return 0
            body = resp.read().decode("utf-8")
    except urllib.error.URLError as exc:
        print(f"Fehler: {url} konnte nicht erreicht werden: {exc.reason}")
        return 0

    try:
        records = json.loads(body)
    except json.JSONDecodeError as exc:
        print(f"Fehler: API hat ungültiges JSON zurückgegeben: {exc.msg}")
        return 0

    if not isinstance(records, list) or not records:
        print("Fehler: erwartet ein nicht-leeres JSON-Array von der 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"{rows} Deployments in CSV exportiert")
Hinweis:Das obige Beispiel verwendet urllib aus der Standardbibliothek, um das Skript abhängigkeitsfrei zu halten. Wenn requests installiert ist, den urllib-Abschnitt durch resp = requests.get(url, timeout=30); records = resp.json() ersetzen — der restliche CSV-Schreibcode bleibt identisch.

JSON-zu-CSV-Konvertierung über die Kommandozeile

Manchmal benötigt man nur einen Einzeiler im Terminal. Pythons -c-Flag ermöglicht eine schnelle Konvertierung ohne eine Skript-Datei zu erstellen. Für komplexere Transformationen zuerst durch jq leiten, um die Daten umzustrukturieren, und dann konvertieren.

bash — Einzeiler-JSON-zu-CSV-Konvertierung
# Python-Einzeiler: liest JSON von stdin, schreibt CSV auf 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)
"

# Ausgabe in eine Datei speichern
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 — eigenständiges CLI-Skript mit argparse
# Als json2csv.py speichern und ausführen: python3 json2csv.py input.json -o output.csv
python3 -c "
import json, csv, argparse, sys

parser = argparse.ArgumentParser(description='JSON-Array in CSV konvertieren')
parser.add_argument('input', help='Pfad zur JSON-Datei')
parser.add_argument('-o', '--output', default=None, help='Ausgabe-CSV-Pfad (Standard: stdout)')
parser.add_argument('-d', '--delimiter', default=',', help='CSV-Trennzeichen')
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'{len(data)} Zeilen in {args.output} geschrieben', file=sys.stderr)
" "$@"
bash — jq + csvkit für komplexe Transformationen
# csvkit installieren: pip install csvkit

# jq wählt Felder aus, in2csv übernimmt die CSV-Formatierung
cat api_response.json | jq '[.[] | {id: .order_id, customer: .customer.name, total}]' | in2csv -f json > orders.csv

# Miller (mlr) ist eine weitere Option für JSON-zu-CSV
mlr --json2csv cat orders.json > orders.csv

Miller (mlr) ist eine eigenständige Binärdatei, die JSON, CSV und TSV als erstklassige Formate behandelt, ohne Python-Laufzeitumgebung. Das Flag --json2csv konvertiert JSON-Eingaben in einem einzigen Durchgang in CSV, und Miller-Verben können verkettet werden, um Spalten im selben Befehl vor der Ausgabe zu filtern, zu sortieren oder umzubenennen. Installation über Homebrew unter macOS ( brew install miller) oder den Linux-Paketmanager. Besonders nützlich in CI-Pipelines, wo schnelle JSON-zu-CSV-Konvertierung ohne Python-Umgebung gewünscht wird.

Hochleistungs-Alternative — pandas mit pyarrow

Für Datensätze im Bereich von Zehnmillionen von Zeilen liest und schreibt pandas mit dem pyarrow-Backend deutlich schneller als mit dem Standard. Die C-basierte Arrow-Engine verarbeitet spaltenweise Daten effizienter als das zeilenweise csv-Modul von Python. Die API bleibt gleich — nur der engine-Parameter wird gesetzt.

bash — pyarrow installieren
pip install pyarrow
Python 3.8+ — pandas mit pyarrow für schnelleres CSV-Schreiben
import pandas as pd

# JSON mit pyarrow-Engine einlesen (schnelleres Parsen für große Dateien)
df = pd.read_json("sensor_readings.json", engine="pyarrow")

# to_csv hat keinen engine-Parameter, aber die DataFrame-Operationen
# zwischen Lesen und Schreiben profitieren von pyarrows Spaltenlayout
df.to_csv("sensor_readings.csv", index=False)

# Für wirklich große Exporte Parquet statt CSV in Betracht ziehen
# — binäres Format, 5–10x kleiner, erhält Typen
df.to_parquet("sensor_readings.parquet", engine="pyarrow")

Wenn mehr als einige hundert MB JSON verarbeitet werden und der finale Empfänger Parquet akzeptiert, CSV komplett überspringen. Parquet ist kleiner, erhält Spaltentypen, und sowohl Redshift als auch BigQuery laden es nativ. CSV ist ein verlustbehaftetes Format — jeder Wert wird zu einem String.

Terminal-Ausgabe mit Syntax-Hervorhebung

Die rich-Bibliothek rendert Tabellen mit Rahmen, Ausrichtung und Farbe im Terminal — nützlich, um eine Konvertierung während der Entwicklung in der Vorschau zu sehen, ohne die Ausgabedatei zu öffnen.

bash — rich installieren
pip install rich
Python 3.8+ — CSV-Ausgabe im Terminal mit rich in der Vorschau anzeigen
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="Server-Metriken Vorschau", 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)
# Rendert eine farblich hervorgehobene Tabelle mit Rahmen im Terminal
Warnung:Rich ist nur für die Terminal-Anzeige. Nicht zum Erzeugen von CSV-Dateien verwenden — es fügt ANSI-Escape-Codes hinzu, die die Ausgabe korrumpieren. In Dateien mit csv.DictWriter oder DataFrame.to_csv() schreiben und rich nur für die Vorschau verwenden.

Arbeiten mit großen JSON-Dateien

json.load() liest die gesamte Datei in den Arbeitsspeicher. Bei einer 200-MB-JSON-Datei bedeutet das ~200 MB Rohtext plus Python-Objekt-Overhead — leicht 500 MB+ Heap-Nutzung. Für Dateien über 100 MB die Eingabe mit ijson streamen und CSV-Zeilen während des Lesens schreiben.

bash — ijson installieren
pip install ijson

JSON-Array mit ijson in CSV streamen

Python 3.8+ — großes JSON-Array mit konstantem Speicher in CSV streamen
import ijson
import csv

def stream_json_to_csv(json_path: str, csv_path: str) -> int:
    """Ein großes JSON-Array in CSV konvertieren, ohne alles in den Arbeitsspeicher zu laden."""
    with open(json_path, "rb") as jf, open(csv_path, "w", newline="", encoding="utf-8") as cf:
        # ijson.items liefert jedes Element des obersten Arrays einzeln
        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"{rows} Datensätze in CSV gestreamt")

NDJSON / JSON Lines — Ein Objekt pro Zeile

NDJSON (Newline-Delimited JSON), auch JSON Lines oder .jsonl genannt, speichert ein gültiges JSON-Objekt pro Zeile ohne umschließendes Array. Dieses Format ist verbreitet in Log-Pipelines, Event-Streams (Kafka, Kinesis) und Massen-Exporten von Diensten wie Elasticsearch und BigQuery. Da jede Zeile ein eigenständiges JSON-Objekt ist, kann eine NDJSON-Datei mit einer einfachen Python for-Schleife über das Datei-Handle verarbeitet werden — keine ijson-Bibliothek nötig. Der Speicher bleibt unabhängig von der Dateigröße konstant, was dies zum einfachsten Streaming-Ansatz macht, wenn die Quelldaten bereits im JSON-Lines-Format vorliegen.

Python 3.8+ — NDJSON zeilenweise in CSV konvertieren
import json
import csv

def ndjson_to_csv(ndjson_path: str, csv_path: str) -> int:
    """Eine newline-delimited JSON-Datei zeilenweise in CSV konvertieren."""
    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  # fehlerhafte Zeilen überspringen

    return count

rows = ndjson_to_csv("access_log.ndjson", "access_log.csv")
print(f"{rows} Log-Einträge in CSV konvertiert")
Hinweis:Auf Streaming umsteigen, wenn die JSON-Datei 100 MB überschreitet. Ein 1-GB-JSON-Array, das mit json.load() geladen wird, kann 3–5 GB RAM verbrauchen, bedingt durch Python-Objekt-Overhead. Mit ijson bleibt der Speicher unabhängig von der Dateigröße konstant. Für eine schnelle Konvertierung einer kleinen Datei diese einfach in den JSON-zu-CSV-Konverter einfügen.

Häufige Fehler

Fehlendes newline='' in open() — leere Zeilen unter Windows

Problem: Das csv-Modul schreibt \r\n-Zeilenenden. Ohne newline='' fügt Pythons Textmodus unter Windows ein weiteres \r hinzu, was doppelzeilige Ausgabe erzeugt.

Lösung: Immer newline='' beim Öffnen einer Datei zum CSV-Schreiben übergeben. Unter macOS/Linux ist es harmlos.

Before · Python
After · Python
with open("output.csv", "w") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Leere Zeilen zwischen jeder Datenzeile unter Windows
with open("output.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=columns)
    writer.writeheader()
    writer.writerows(data)
# Saubere Ausgabe auf allen Plattformen
index=False in pandas to_csv() vergessen

Problem: Ohne index=False fügt pandas eine automatisch hochzählende Zeilennummer-Spalte (0, 1, 2, ...) hinzu, die die CSV mit Daten verschmutzt, die nie im ursprünglichen JSON waren.

Lösung: index=False an to_csv() übergeben. Wenn tatsächlich eine Index-Spalte benötigt wird, diese explizit mit df.index.name = 'row_num' benennen.

Before · Python
After · Python
df = pd.read_json("events.json")
df.to_csv("events.csv")
# CSV erhält eine extra namenlose Spalte: ,event_id,timestamp,...
# Das führende Komma bricht viele CSV-Parser
df = pd.read_json("events.json")
df.to_csv("events.csv", index=False)
# Saubere CSV: event_id,timestamp,...
records[0].keys() verwenden, wenn Datensätze inkonsistente Schlüssel haben

Problem: Wenn JSON-Objekte unterschiedliche Schlüssel haben (manche Datensätze haben optionale Felder), werden durch die Verwendung der Schlüssel des ersten Datensatzes als fieldnames Spalten, die nur in späteren Datensätzen erscheinen, still verworfen.

Lösung: Alle eindeutigen Schlüssel über alle Datensätze sammeln, bevor der DictWriter erstellt wird.

Before · Python
After · Python
records = json.load(f)
writer = csv.DictWriter(out, fieldnames=records[0].keys())
# Verpasst das Feld "discount", das nur in records[2] erscheint
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="")
# Jeder Schlüssel aus jedem Datensatz wird als Spalte eingeschlossen
Verschachtelte Dicts direkt ohne Abflachen in CSV schreiben

Problem: csv.DictWriter ruft str() für verschachtelte Dicts auf, was Spalten mit Werten wie "{'city': 'Portland'}"erzeugt — rohe Python-Darstellung, keine echten Daten.

Lösung: Verschachtelte Objekte zuerst mit pd.json_normalize() oder einer benutzerdefinierten Abflach-Funktion abflachen.

Before · Python
After · Python
records = [{"id": "evt_1", "meta": {"source": "web", "region": "us-west"}}]
writer = csv.DictWriter(f, fieldnames=["id", "meta"])
writer.writerows(records)
# meta-Spalte enthält: {'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)
# Spalten: id, meta_source, meta_region

csv.DictWriter vs. pandas — Kurzvergleich

Methode
Verschachteltes JSON
Eigene Typen
Streaming
Abhängigkeiten
Installation
csv.DictWriter
✗ (manuelles Flatten)
✓ (Zeile für Zeile)
Keine
Nein (stdlib)
csv.writer
✓ (Zeile für Zeile)
Keine
Nein (stdlib)
pd.DataFrame.to_csv()
✗ (nur flach)
✓ (über dtypes)
pandas + numpy
pip install
pd.json_normalize() + to_csv()
✓ (über dtypes)
pandas + numpy
pip install
csv.writer + json_flatten
flatten_json
pip install
jq + csvkit (CLI)
✓ (über jq)
N/A
jq, csvkit
Systeminstallation

csv.DictWriter verwenden, wenn null Abhängigkeiten benötigt werden, das JSON flach ist und das Skript in einer eingeschränkten Umgebung läuft (CI-Container, Lambda-Funktionen, eingebettetes Python).pd.json_normalize() + to_csv() verwenden, wenn das JSON verschachtelt ist, Daten vor dem Export transformiert oder gefiltert werden müssen oder bereits in einem pandas-Workflow gearbeitet wird. Für Dateien, die nicht in den Arbeitsspeicher passen, ijson mit csv.DictWriter für konstantes Speicher-Streaming kombinieren.

Für schnelle, codefreie Konvertierungen erledigt der JSON-zu-CSV-Konverter auf ToolDeck es ohne Python-Setup.

Häufig gestellte Fragen

Wie konvertiere ich JSON ohne pandas in Python zu CSV?

Verwende die eingebauten Module json und csv. Rufe json.load() auf, um die JSON-Datei als Liste von Dicts zu parsen, extrahiere die Feldnamen aus den Schlüsseln des ersten Dicts, erstelle einen csv.DictWriter, rufe writeheader() und dann writerows() auf. Dieser Ansatz hat null externe Abhängigkeiten und funktioniert in jeder Python-3.x-Umgebung. Er läuft außerdem schneller als pandas bei kleinen Dateien, da kein DataFrame-Overhead anfällt. Wenn deine JSON-Objekte über verschiedene Datensätze hinweg unterschiedliche Schlüssel haben, sammle alle einzigartigen Schlüssel zuerst mit dict.fromkeys(k for r in records for k in r), bevor du sie als fieldnames übergibst, um fehlende Spalten zu vermeiden.

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)

Wie gehe ich mit verschachteltem JSON beim Konvertieren in CSV um?

Flache JSON-Arrays lassen sich direkt auf CSV-Zeilen abbilden, aber verschachtelte Objekte müssen zuerst abgeflacht werden. Mit pandas erledigt pd.json_normalize() das automatisch — es verbindet verschachtelte Schlüssel mit einem Punkttrennzeichen (z. B. "address.city"). Ohne pandas schreibe eine rekursive Funktion, die das Dict durchläuft und Schlüssel mit einem Trennzeichen verkettet. Für tief verschachtelte Strukturen mit mehreren Ebenen verarbeitet json_normalize alles in einem Durchgang. Der sep-Parameter steuert das Verbindungszeichen zwischen Schlüsselsegmenten — ein Unterstrich ist in der Regel sicherer als der Standard-Punkt für SQL-Importe und Tabellenkalkulationsformeln.

Python
import pandas as pd

nested_data = [
    {"id": "ord_91a3", "customer": {"name": "Anna Müller", "email": "a.mueller@beispiel.de"}},
]
df = pd.json_normalize(nested_data, sep="_")
# Spalten: id, customer_name, customer_email
df.to_csv("flat_orders.csv", index=False)

Warum hat meine CSV unter Windows leere Zeilen zwischen den Datenzeilen?

Das csv-Modul schreibt standardmäßig \r\n-Zeilenenden. Unter Windows fügt das Öffnen der Datei im Textmodus ein weiteres \r hinzu, was \r\r\n erzeugt — das erscheint als Leerzeile. Die Lösung ist, immer newline="" an open() zu übergeben. Damit weist man Python an, keine Zeilenenden zu übersetzen und überlässt das dem csv-Modul. Dieses Muster ist unabhängig vom Betriebssystem erforderlich — es ist harmlos unter macOS und Linux, aber auf Windows unverzichtbar. Die Python-Dokumentation weist im Abschnitt zum csv-Modul ausdrücklich darauf hin, dass dies die korrekte Art ist, Dateien für CSV-Schreibvorgänge zu öffnen.

Python
# Falsch — leere Zeilen unter Windows
with open("output.csv", "w") as f:
    writer = csv.writer(f)

# Richtig — newline="" verhindert doppeltes \r
with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)

Wie hänge ich JSON-Datensätze an eine bestehende CSV-Datei an?

Öffne die Datei im Anhänge-Modus ("a") und erstelle einen DictWriter mit denselben Feldnamen. Überspringe writeheader(), da die Kopfzeile bereits vorhanden ist. Mit pandas verwende to_csv(mode="a", header=False). Stelle sicher, dass die Spaltenreihenfolge mit der bestehenden Datei übereinstimmt, sonst landen die Daten in den falschen Spalten. Wenn du die Spaltenreihenfolge in der bestehenden Datei nicht kennst, öffne sie zuerst mit csv.DictReader und lese die Feldnamen aus dem fieldnames-Attribut, bevor du den Writer zum Anhängen erstellst.

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)

Was ist der schnellste Weg, eine große JSON-Datei in Python in CSV zu konvertieren?

Für Dateien unter 500 MB ist pd.read_json() gefolgt von to_csv() der schnellste Einzelaufruf — pandas verwendet intern optimierten C-Code. Für Dateien über 500 MB verwende ijson, um JSON-Datensätze zu streamen und sie mit csv.DictWriter Zeile für Zeile in CSV zu schreiben. Dies hält die Speichernutzung unabhängig von der Dateigröße konstant. Für NDJSON-Dateien (ein JSON-Objekt pro Zeile) benötigst du ijson überhaupt nicht — eine einfache Python-for-Schleife über das Datei-Handle verarbeitet jede Zeile unabhängig und erreicht konstanten Speicherverbrauch ohne externe Bibliotheken.

Python
# Schnell für Dateien, die in den Arbeitsspeicher passen
import pandas as pd
df = pd.read_json("large_dataset.json")
df.to_csv("large_dataset.csv", index=False)

# Streaming für Dateien, die nicht in den Arbeitsspeicher passen
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)

Kann ich die CSV-Ausgabe in Python auf stdout schreiben statt in eine Datei?

Ja. Übergib sys.stdout als Datei-Objekt an csv.writer() oder csv.DictWriter(). Das ist nützlich für das Weiterleiten von Ausgaben in Shell-Skripten oder zum schnellen Debuggen. Mit pandas rufe to_csv(sys.stdout, index=False) auf oder to_csv(None), um einen String zu erhalten, den du ausgeben kannst. Keine temporäre Datei nötig. Beim Schreiben auf stdout unter Windows rufe zuerst sys.stdout.reconfigure(newline="") auf, um das Problem mit doppelten Wagenrückläufen zu vermeiden, da stdout standardmäßig im Textmodus geöffnet wird.

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

Verwandte Tools

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 SharmaTechnischer Prüfer

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.