Работа с CSV-файлами в Python: практическое руководство

CSV — формат, с которым рано или поздно столкнётся любой разработчик: выгрузка из 1С, экспорт из Google Sheets, отчёты из CRM, открытые данные госорганов. Это руководство собирает в одном месте практические рецепты обработки CSV: стандартный модуль csv, библиотека pandas и решения частых проблем (кодировки, разделители, типы данных).

Если только знакомитесь с модулем — начните с Модуль csv — работа с CSV-файлами в Python. Эта статья сосредоточена на прикладных задачах.


Какой инструмент выбрать

Задача                                         Что брать
----------------------------------------------- ---------------------
просто прочитать/записать файл                 csv (stdlib)
потоковая обработка миллионов строк            csv (stdlib)
аналитика, группировки, агрегаты               pandas
join, merge, преобразования таблиц             pandas
мелкие фильтры в скрипте                       csv (stdlib)
нужны графики и статистика                     pandas + matplotlib

Главное правило: модуль csv — для построчной обработки и минимальной зависимости от сторонних библиотек. pandas — когда нужны таблицы целиком и аналитика.


Подготовка: пример данных

Будем работать с файлом sales.csv:

date,product,city,amount,price
2026-05-01,Arduino UNO,Алматы,3,15000
2026-05-01,Robot Phobo,Астана,1,49000
2026-05-02,Arduino UNO,Шымкент,2,15000
2026-05-02,ESP32,Алматы,5,8500
2026-05-03,Robot Phobo,Алматы,1,49000

Часть 1. Стандартный модуль csv

Чтение со словарями

import csv

with open('sales.csv', newline='', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['product'], '—', row['amount'])

Подсчёт суммы продаж

import csv

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

print(f'Общая выручка: {total:,} тг')

Заметьте: значения из CSV всегда строки. Преобразование в число — на нас.

Группировка вручную

Кто больше всех продаёт по городам:

import csv
from collections import defaultdict

by_city = defaultdict(int)
with open('sales.csv', newline='', encoding='utf-8') as f:
    for row in csv.DictReader(f):
        by_city[row['city']] += int(row['amount']) * int(row['price'])

for city, total in sorted(by_city.items(), key=lambda x: -x[1]):
    print(f'{city}: {total:,} тг')

Фильтр + запись в новый файл

import csv

with open('sales.csv', newline='', encoding='utf-8') as src, \
     open('sales_almaty.csv', 'w', newline='', encoding='utf-8') as dst:

    reader = csv.DictReader(src)
    writer = csv.DictWriter(dst, fieldnames=reader.fieldnames)
    writer.writeheader()

    for row in reader:
        if row['city'] == 'Алматы':
            writer.writerow(row)

Часть 2. pandas — табличный подход

Установка:

pip install pandas

Чтение CSV в DataFrame

import pandas as pd

df = pd.read_csv('sales.csv')
print(df.head())

Вывод:

        date     product     city  amount  price
0 2026-05-01 Arduino UNO   Алматы       3  15000
1 2026-05-01 Robot Phobo   Астана       1  49000
2 2026-05-02 Arduino UNO  Шымкент       2  15000
3 2026-05-02       ESP32   Алматы       5   8500
4 2026-05-03 Robot Phobo   Алматы       1  49000

pandas сам распознал заголовки и попытался угадать типы.

Полезные параметры read_csv

df = pd.read_csv(
    'sales.csv',
    sep=',',                       # разделитель
    encoding='utf-8',              # кодировка
    parse_dates=['date'],          # сразу превратить в datetime
    dtype={'amount': int, 'price': int},
    na_values=['', 'NA', 'NULL'],  # что считать пропуском
    thousands=' ',                 # для чисел вида "1 500 000"
)

Новая колонка

df['revenue'] = df['amount'] * df['price']
print(df[['product', 'revenue']])

Фильтрация

almaty = df[df['city'] == 'Алматы']
big = df[df['revenue'] > 30000]

Группировка и агрегаты

by_city = df.groupby('city')['revenue'].sum().sort_values(ascending=False)
print(by_city)

Вывод:

city
Алматы     135500
Астана      49000
Шымкент     30000
Name: revenue, dtype: int64

Сразу несколько метрик:

stats = df.groupby('product').agg(
    sales=('amount', 'sum'),
    revenue=('revenue', 'sum'),
    avg_price=('price', 'mean'),
)
print(stats)

Запись CSV

df.to_csv('sales_with_revenue.csv', index=False, encoding='utf-8')

index=False — иначе pandas запишет номера строк отдельной колонкой.


Проблема: кодировка

Самая частая ошибка при работе с CSV — UnicodeDecodeError. Виноваты не вы, виноват источник: Excel и российские госсайты часто отдают файлы в cp1251 или utf-8-sig (с BOM).

# Файл из Excel — почти всегда utf-8-sig или cp1251
df = pd.read_csv('export.csv', encoding='utf-8-sig')
df = pd.read_csv('export.csv', encoding='cp1251')

Подобрать вручную можно через библиотеку chardet:

# pip install chardet
import chardet

with open('mystery.csv', 'rb') as f:
    raw = f.read(10000)
print(chardet.detect(raw))
# {'encoding': 'windows-1251', 'confidence': 0.98, ...}

Проблема: разделитель

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

df = pd.read_csv('export.csv', sep=';')

Если разделитель неизвестен — pandas может угадать (sep=None, engine='python').


Проблема: большие файлы

Файл на 5 ГБ в память не лезет. Решения:

Чтение по частям:

import pandas as pd

total = 0
for chunk in pd.read_csv('huge.csv', chunksize=100_000):
    total += chunk['amount'].sum()
print(total)

Только нужные колонки:

df = pd.read_csv('huge.csv', usecols=['date', 'amount'])

Подходящие типы данных:

df = pd.read_csv('huge.csv', dtype={'id': 'int32', 'flag': 'int8'})

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

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

  • Кодировка по умолчанию. Открывайте всегда с явной encoding=.

  • Числа как строки. В модуле csv всё строки. В pandas тип зависит от содержимого — если в столбце вдруг попалась нечисловая ячейка, весь столбец станет object.

  • NaN-ы в pandas. Пустые ячейки превращаются в NaN. Помните об этом при сравнениях: NaN == NaN это False.

  • Excel и .csv. Excel при сохранении меняет кодировку, разделитель, может добавить BOM. Лучше попросить экспорт в .xlsx и читать pd.read_excel.

  • Не парсите CSV руками через split(„,“). Внутри значений бывают запятые в кавычках — стандартный парсер их обработает, а ваш — нет.


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


Примечание

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

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