Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Экспорт данных в Excel и CSV из Python

Экспорт отчётов в Excel и CSV из Python: форматы, кодировки и большие выгрузки

Практика выгрузок: openpyxl/xlsxwriter против csv, UTF-8 BOM для Excel, типы данных и формулы, стриминг больших файлов, выгрузка как фоновая задача — рабочие рецепты.

Прямой ответ

Выбор формата выгрузки определяется получателем: CSV — когда данные пойдут в другую систему или их много (простой, потоковый, компактный), XLSX — когда файл откроет человек в Excel (форматирование, листы, формулы, фильтры). Два правила, которые закрывают 80% проблем: CSV для Excel сохраняется в UTF-8 с BOM (encoding="utf-8-sig" — иначе кириллица превратится в кракозябры), а большие выгрузки генерируются потоково и в фоне (не в обработчике HTTP-запроса и не целиком в памяти). Инструменты: csv-модуль/pandas для CSV, openpyxl (чтение+запись) или xlsxwriter (запись, быстрее и богаче по форматированию) для XLSX.

CSV: простота с тремя минами

csv.writer/csv.DictWriter или df.to_csv(...) — технически тривиально; мины — в деталях. Кодировка: UTF-8 без BOM корректен, но Excel «из коробки» трактует его как локальную (кракозябры); utf-8-sig решает (системный разбор кодировок — в статье про Unicode); разделитель — запятая или ; (европейский Excel ждёт точку с запятой). Типы: даты — в ISO (2026-10-20, не 20.10.26 — иначе каждый получатель интерпретирует по-своему); числа — с точкой-разделителем (или честный warning, что Excel локализуется); «+7...» и «00123» Excel «исправит» при открытии — для идентификаторов/телефонов это потеря данных (лечится кавычкой-префиксом или XLSX с явным текстовым форматом). Размер: CSV потоков (csv.writer поверх курсора БД) масштабируется на миллионы строк, XLSX — до лимита 1 048 576 строк на лист и заметно медленнее генерируется.

XLSX: когда и чем писать

XLSX оправдан для «человеческих» отчётов: листы по разделам, заголовки с фильтрами (ws.auto_filter.ref), ширины колонок, числовые форматы (деньги/даты отображаются как надо), условное форматирование, сводные диаграммы. Библиотеки: openpyxl — чтение и запись, стандарт де-факто; xlsxwriter — только запись, но быстрее на больших файлах и богаче API форматирования/графиков (выбор для генерации отчётов); pandas-обёртка (df.to_excel(engine="xlsxwriter")) — быстрый путь для табличных данных. Производительность: обычный режим держит файл в памяти — на сотнях тысяч строк включайте потоковые режимы (openpyxl write_only / xlsxwriter constant_memory) или переходите на CSV. Формулы записывать можно (ws["C2"] = "=SUM(A2:B2)"), но пересчитываются они при открытии в Excel — файл, открытый не-Excel-читателем, увидит пустые значения.

Выгрузка как операция: фон, прогресс, доставка

Отчёт на 200k строк генерируется секунды-минуты — в HTTP-запросе это таймаут: выгрузка уходит в фоновую задачу (Celery-паттерн), готовый файл — в хранилище, пользователю — ссылка/письмо (email-механика). Дисциплина операции: идемпотентность (повторный запрос не плодит десять копий), срок жизни файлов (TTL в хранилище — отчёты с персональными данными не должны лежать вечно), честный прогресс для длинных выгрузок, и лимиты (максимум строк, частота запросов — «выгрузить всё» регулярно кладёт БД). Для регулярных отчётов — расписание вместо ручного запуска (скедулеры).

Данные для выгрузки: где их брать правильно

Источник выгрузки — отдельное решение: «SELECT * из прода» под отчёт нагружает боевую БД — разумнее реплика/выгрузка в parquet и генерация из неё (форматы — в статье про CSV/parquet); тяжёлые агрегации — на стороне БД или DuckDB (аналитика из Python), не в pandas на живом сервисе. Структура отчёта — контракт с получателем: стабильные имена колонок (их парсят скрипты получателя, даже если «это для людей»), строка метаданных (период, дата генерации, версия формата), отдельный лист/файл с описанием колонок для нетривиальных отчётов. «Отчёт поехал» в 90% случаев — молча изменившийся формат выгрузки; версионирование формата лечит.

Частные случаи, которые экономят часы

Чтение чужого XLSX: pd.read_excel(..., dtype=str) для осмотра (типы Excel-ячеек коварны: даты как числа, «текст-число»), затем явные преобразования. Несколько листов: ExcelWriter с несколькими to_excel(sheet_name=...). Огромный CSV получателю: сразу договоритесь о кодировке/разделителе/кавычках в письме-спецификации (RFC 4180 — база); «мы потом подберём» превращается в недели переписки. Файл «не влезает в Excel» — не проблема Excel-получателя: предложите CSV/parquet или разбивку по периодам; лимит строк листа обойти нельзя. Персональные данные в выгрузках — доступ к эндпоинту выгрузки авторизуется строже обычных экранов (файл уносят целиком).

Практический сценарий: ежедневная выгрузка по расписанию

Соберём регулярный отчёт целиком. Ночью планировщик запускает задачу: данные читаются не из боевой БД, а из реплики (или из свежего parquet-среза — тяжёлый SELECT в пик убивает прод); pandas собирает итоговую таблицу — агрегации делаются на стороне БД/DuckDB, в Python приезжает только результат. Формируются два файла: report_2026-10-20.xlsx для людей (заголовок с периодом и датой генерации, листы «Сводка» и «Детали», автофильтр, денежные колонки с числовым форматом, ширина колонок под содержимое) и report_2026-10-20.csv в UTF-8 с BOM и ISO-датами — для тех, кто грузит данные в свои системы. Оба уезжают в хранилище с TTL тридцать дней (в отчёте персональные данные — вечно лежать они не должны), получателям уходит письмо со ссылками; отправка — через фоновую очередь с ретраем. Контроль качества встроен в задачу: число строк в ожидаемом диапазоне, сумма итога бьётся с контрольным запросом, при аномалии — алерт вместо рассылки (отчёт с ошибкой хуже отсутствия отчёта — его успели принять как истину). Формат версионируется: при изменении колонок — строка schema v2 в шапке и уведомление получателей. Такой отчёт живёт годами и переживает смену разработчика — потому что каждый шаг описан кодом, а не «делалось руками по понедельникам».

FAQ

openpyxl или xlsxwriter? Читать XLSX — только openpyxl; писать отчёты с форматированием — xlsxwriter (быстрее, удобнее API); писать и редактировать существующие — openpyxl. В проекте часто живут оба по ролям.

Почему Excel показывает «###» или 1,23E+11? Колонка узка (###) или длинное число переведено в научный формат (Excel портит числа длиннее 15 разрядов — артикулы/карты теряют точность необратимо). Лечится текстовым форматом колонки в XLSX; в CSV — кавычкой-префиксом.

Как выгрузить результат pandas быстро и правильно? Для машины-получателя — to_parquet/to_csv (индекс off, даты ISO); для человека — to_excel с xlsxwriter-форматированием заголовков. Одна и та же таблица в двух форматах — нормальная практика.

Стоит ли генерировать PDF-отчёты? Для «посмотреть и распечатать» — да (weasyprint/reportlab), но PDF — тупик для данных (их не импортировать). Пара «XLSX для работы + PDF для презентации» закрывает оба сценария без самописных таблиц в PDF.

Источники: документация openpyxl, XlsxWriter и csv (docs.python.org) — ссылки в шапке.