Чтение CSV-файлов в Python

Эта статья — детальный разбор именно чтения CSV: все способы, все полезные опции и реальные сценарии. Если нужно ещё и записывать, или собирать аналитику с pandas — смотрите Модуль csv — работа с CSV-файлами в Python и Работа с CSV-файлами в Python: практическое руководство.


Базовый шаблон

Самый минимальный код для чтения CSV:

import csv

with open('data.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

Что здесь важно:

  • open(..., newline='') — обязательно. Без этого csv неправильно обрабатывает переводы строк (особенно на Windows).

  • encoding='utf-8' — явная кодировка. Не полагайтесь на дефолт системы.

  • with — гарантия, что файл закроется.

  • csv.reader(f) возвращает итератор; читается лениво, строка за строкой.


Что возвращает csv.reader

Каждая строка — это список строк (list[str]). Все значения — текст, типов нет.

id,name,age
1,Айдос,21
2,Гульнара,19

--> [['id', 'name', 'age'],
     ['1', 'Айдос', '21'],
     ['2', 'Гульнара', '19']]

Преобразование типов — задача программиста:

import csv

with open('users.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    next(reader)  # пропустить заголовки
    for row in reader:
        id_, name, age = row
        age = int(age)
        print(name, age)

Чтение со словарями: csv.DictReader

DictReader берёт первую строку как заголовки и выдаёт каждую строку как словарь. Это удобнее, чем помнить индексы колонок.

import csv

with open('users.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['name'], row['age'])

Если заголовков в файле нет — задайте сами:

reader = csv.DictReader(f, fieldnames=['id', 'name', 'age'])

И поля заголовков всегда доступны через reader.fieldnames.


Пропуск заголовков

Способ 1 — через next:

import csv

with open('data.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    header = next(reader)
    for row in reader:
        ...

Способ 2 — собрать zip(header, row) в словарь вручную:

import csv

with open('data.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    header = next(reader)
    for row in reader:
        record = dict(zip(header, row))
        print(record)

Способ 3 (рекомендуемый): просто DictReader.


Другой разделитель

Файлы из Excel в локали с запятой как десятичным разделителем используют ;:

import csv

with open('export.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f, delimiter=';')
    for row in reader:
        print(row)

То же для DictReader:

reader = csv.DictReader(f, delimiter=';')

Если разделитель неизвестен — есть csv.Sniffer:

import csv

with open('mystery.csv', newline='', encoding='utf-8') as f:
    sample = f.read(2048)
    f.seek(0)
    dialect = csv.Sniffer().sniff(sample)
    reader = csv.reader(f, dialect)
    has_header = csv.Sniffer().has_header(sample)
    if has_header:
        next(reader)
    for row in reader:
        print(row)

Кодировки

Самый частый источник боли. Шпаргалка:

Источник                        Кодировка
---------------------------     ---------------
современная веб-выгрузка        utf-8
Excel "Сохранить как CSV UTF-8" utf-8-sig (с BOM)
Excel "CSV (разделители - запятые)" в RU-локали   cp1251 ; разделитель
1С, банк-клиент                 cp1251 или windows-1251
зарубежные госсайты             utf-8 или latin-1

При UnicodeDecodeError:

# пробуйте по очереди:
for enc in ('utf-8', 'utf-8-sig', 'cp1251', 'latin-1'):
    try:
        with open(path, encoding=enc, newline='') as f:
            next(csv.reader(f))
        print('Подходит:', enc)
        break
    except UnicodeDecodeError:
        continue

Пропуск некорректных строк

В реальных данных встречаются битые строки. Стандартный способ — обработать их в try/except:

import csv

with open('data.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for line_no, row in enumerate(reader, start=2):
        try:
            age = int(row['age'])
        except (ValueError, KeyError) as e:
            print(f'Пропускаю строку {line_no}: {e}')
            continue
        # ... обработка ...

start=2 — потому что строка 1 это заголовок.


Потоковая обработка больших файлов

csv.reader не загружает весь файл сразу — он лениво читает по одной строке. Это значит, что файл хоть на 100 ГБ обработается с памятью на одну строку:

import csv

total = 0
with open('huge.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        total += int(row['amount'])

print(total)

Не вызывайте list(reader) без необходимости — это сразу всё в память.


Практический пример: импорт пользователей в БД

import csv
import sqlite3

conn = sqlite3.connect('app.db')
cur = conn.cursor()
cur.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT, age INTEGER)')

with open('users.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    batch = []
    for row in reader:
        batch.append((int(row['id']), row['name'], int(row['age'])))
        if len(batch) >= 1000:
            cur.executemany('INSERT INTO users VALUES (?, ?, ?)', batch)
            batch.clear()
    if batch:
        cur.executemany('INSERT INTO users VALUES (?, ?, ?)', batch)

conn.commit()
conn.close()

Пачками по 1000 — намного быстрее, чем по одной строке.


Практический пример: выгрузка по фильтру

Прочитать продажи за май и посчитать, сколько штук каждого продукта продалось:

import csv
from collections import Counter

counter = Counter()
with open('sales.csv', newline='', encoding='utf-8') as f:
    for row in csv.DictReader(f):
        if row['date'].startswith('2026-05'):
            counter[row['product']] += int(row['amount'])

for product, qty in counter.most_common():
    print(f'{product}: {qty}')

Размер ячейки

По умолчанию csv ограничивает поле в 128 КБ. Если данные большие (например, JSON-строки в столбце) — увеличьте лимит:

import csv
import sys

csv.field_size_limit(min(sys.maxsize, 10**8))

Подводные камни

Предупреждение

  • Забыли ``newline=““`` — получаете лишние пустые строки на Windows.

  • Все значения строки. Никакого «умного» преобразования. Числа — через int()/float(), даты — через datetime.strptime.

  • Не игнорируйте кодировку. Без явного encoding Python берёт системный дефолт, который на разных машинах разный.

  • BOM в начале файла. Если первый ключ выглядит как 'id' — используйте encoding='utf-8-sig'.

  • ``DictReader`` и дубликаты столбцов. Если в заголовке две одинаковые колонки, останется только последняя. Проверяйте заголовки.


Смотрите также


Примечание

Лицензия и источники

Часть материала адаптирована из официальной документации Python (https://docs.python.org/3/library/csv.html), доступной под Python Software Foundation License Version 2 (PSF License). Адаптация, переработка, оригинальные примеры и пояснения — © AlashEd Wiki.