Урок 3 из 8 · 20 мин · обновлено

Таблицы: чтение и запись Excel и CSV

Как читать и записывать таблицы в Python: CSV через модуль csv с правильной кодировкой и разделителем, файлы Excel через openpyxl — листы, строки, ячейки и новые книги.

CSV: самый простой формат таблиц

Кассовая программа «Канцмаркета» выгружает продажи в файл CSV — обычный текст, где каждая строка — строка таблицы, а значения разделены знаком. Откройте такой файл в блокноте, и увидите:

Текст
дата;товар;количество;цена
20.10.2026;Тетрадь 48 л.;12;95
20.10.2026;Ручка гелевая;30;45
21.10.2026;Тетрадь 48 л.;8;95
21.10.2026;Маркер;5;120

Две особенности, на которых часто спотыкаются новички:

  • разделитель. В английских программах — запятая, в русских — обычно точка с запятой, потому что запятая занята дробными числами;
  • кодировка. Русские буквы в файле записаны в какой-то кодировке. Сейчас это почти всегда UTF-8. Если файл сохранял Excel, в начале стоит невидимая метка, поэтому читать его надёжнее с кодировкой utf-8-sig.

Читаем CSV

В Python есть встроенный модуль csv. Удобнее всего DictReader: он превращает каждую строку в словарь, где ключи — заголовки столбцов.

Python
import csv

total = 0
with open("продажи_магазин1.csv", encoding="utf-8-sig", newline="") as f:
    for row in csv.DictReader(f, delimiter=";"):
        amount = int(row["количество"]) * int(row["цена"])
        total += amount
        print(row["дата"], row["товар"], amount)

print("Выручка:", total)
Результат
20.10.2026 Тетрадь 48 л. 1140
20.10.2026 Ручка гелевая 1350
21.10.2026 Тетрадь 48 л. 760
21.10.2026 Маркер 600
Выручка: 3850

Обратите внимание на int(): из CSV все значения приходят строками. Без превращения в число "12" * 2 даст не 24, а "1212". Для дробных чисел используйте float(), а запятую в «45,50» сначала замените на точку: float(value.replace(",", ".")).

with open(...) сам закроет файл, когда блок закончится. newline="" модуль csv просит указывать всегда — так он правильно обрабатывает переносы строк.

Записываем CSV

Запись устроена зеркально — через DictWriter:

Python
import csv

rows = [
    {"товар": "Тетрадь 48 л.", "остаток": 140},
    {"товар": "Маркер", "остаток": 18},
]
with open("остатки.csv", "w", encoding="utf-8-sig", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["товар", "остаток"], delimiter=";")
    writer.writeheader()
    writer.writerows(rows)

Получится файл, который Excel откроет сразу с правильными колонками и русскими буквами:

Текст
товар;остаток
Тетрадь 48 л.;140
Маркер;18

Excel через openpyxl

Магазины присылают продажи уже в Excel — файлы .xlsx. Их читает библиотека openpyxl, которую мы поставили в уроке 1. Устройство файла Excel повторяет то, что вы видите в программе:

  • книга (workbook) — весь файл;
  • лист (worksheet) — вкладка внизу;
  • ячейка (cell) — пересечение строки и столбца, например B2.

Лист «Продажи» в файле второго магазина устроен так же, как CSV выше: в строке 1 заголовки «Дата», «Товар», «Количество», «Цена» в столбцах A–D, со строки 2 — продажи, по одной в строке.

Читаем его:

Python
from openpyxl import load_workbook

wb = load_workbook("магазин_2.xlsx")
ws = wb["Продажи"]

for date, product, qty, price in ws.iter_rows(min_row=2, values_only=True):
    print(date, product, qty * price)
Результат
20.10.2026 Ручка гелевая 1800
21.10.2026 Блокнот А5 2100
22.10.2026 Тетрадь 48 л. 1425
  • wb["Продажи"] — лист по названию; первый лист книги можно взять как wb.active;
  • min_row=2 пропускает строку заголовков;
  • values_only=True отдаёт значения, а не объекты ячеек, поэтому строку можно сразу разложить по переменным.

В отличие от CSV, числа из Excel приходят уже числами: qty * price работает без int(). Даты в нашем файле записаны текстом. Если в ячейке настоящая дата Excel, openpyxl вернёт объект datetime — как с ним работать, разберём в уроке 5.

К отдельной ячейке обращаются по адресу: ws["B2"].value вернёт «Ручка гелевая». Записать значение так же просто: ws["E1"] = "Сумма", после чего книгу нужно сохранить: wb.save("магазин_2.xlsx").

Попробуйте сами. Дополните скрипт для CSV так, чтобы он считал выручку не общей суммой, а по каждому товару, и печатал результат. Подсказка: понадобится словарь.

Решение
Python
import csv

by_product = {}
with open("продажи_магазин1.csv", encoding="utf-8-sig", newline="") as f:
    for row in csv.DictReader(f, delimiter=";"):
        amount = int(row["количество"]) * int(row["цена"])
        product = row["товар"]
        by_product[product] = by_product.get(product, 0) + amount

for product, amount in by_product.items():
    print(product, amount)
Результат
Тетрадь 48 л. 1900
Ручка гелевая 1350
Маркер 600

by_product.get(product, 0) возвращает уже накопленную сумму или 0, если товар встретился впервые. Этот приём — основа отчёта, который мы соберём в следующем уроке.

Мини-тест · 4 вопроса

Проверьте себя

Выберите вариант, который кажется вам правильным. В конце вы увидите свой результат и объяснение к каждому вопросу.

  1. CSV из кассовой программы открылся в Python одной колонкой: «20.10.2026;Тетрадь 48 л.;12;95». Что поправить?

  2. row["количество"] из CSV равно "12". Почему row["количество"] * 2 даёт "1212"?

  3. Что делает ws.iter_rows(min_row=2, values_only=True)?

  4. Зачем при записи CSV указывают encoding="utf-8-sig"?