CSV vs JSON: which format to use
Pick CSV for flat tabular records and JSON when fields are nested. CSV is one row per item with a fixed set of columns; it opens directly in a spreadsheet and is ideal for prices, product listings, or contact rows. JSON keeps arrays and nested objects intact, so it is the right choice when a record has variable-length lists (tags, images, reviews) or sub-objects that would not fit cleanly into columns.
| Need | Use | Why |
|---|---|---|
| Open in Excel/Google Sheets | CSV | Native, one row per record |
| Preserve nested fields | JSON | Arrays and objects survive intact |
| Append millions of records | JSON Lines | One JSON object per line, append-safe |
A common mistake is forcing nested data into CSV: a list field gets stringified or dropped. If a record has both flat and nested parts, write the full record to JSON for fidelity and a flattened subset to CSV for analysis. See exporting to Excel for the .xlsx variant.
Encoding and escaping pitfalls
The two failures that corrupt CSV exports are wrong encoding and unescaped delimiters; the csv module and UTF-8 handle both if configured right. Always open files with encoding="utf-8" and newline="" so the csv module controls line endings. When the file is destined for Excel on Windows, use encoding="utf-8-sig" to write a byte-order mark (BOM) so accented characters and non-Latin scripts render instead of showing mojibake.
- Commas and quotes in values: never join fields by hand. The
csvwriter wraps any field containing a comma, double-quote, or newline in quotes and doubles internal quotes automatically. - Inconsistent keys: use
csv.DictWriterwithextrasaction="ignore"so a record with a missing or extra key does not throw. - JSON unicode: set
ensure_ascii=Falseinjson.dumpto keep readable UTF-8 instead of\uXXXXescapes, andindent=2only for human-readable files (omit it for compact machine files).
CSV flattens structure: a nested list becomes a string. If you must keep a nested field in CSV, serialize just that cell with json.dumps() so it round-trips losslessly.
Streaming large datasets
For large jobs, write each record as it arrives instead of building one giant list in memory. Keep the output file open and call writer.writerow() (CSV) or write one JSON object per line (JSON Lines / NDJSON) per scraped item. This caps memory at one record and lets the job resume or append without rewriting the whole file.
JSON Lines is the scalable cousin of JSON: each line is a standalone JSON object, so you can append with mode "a", stream-read it back line by line, and never need to load the entire array. Plain json.dump of a list, by contrast, requires the whole dataset in RAM and a full rewrite to add records.
- Append, do not overwrite: open in append mode for incremental runs; write the CSV header only once.
- Deduplicate: track a key (URL or id) in a set, or post-process with
sort -u/ pandasdrop_duplicates(). - Pagination: reuse one Scrappey
sessionacross pages so cookies and session state persist, and flush each page to disk before fetching the next.
Pair this with dynamic content scraping when the source renders rows in the browser, so the data you stream out is already complete.
