openpyxl можно освоить на одном небольшом проекте, если сразу видеть вход, действие и результат. openpyxl автоматизирует повторяемую работу с XLSX: чтение листов, объединение строк, формулы, стили и сохранение отдельного отчёта. Ниже вы соберёте работающий пример и проверите обычный и граничный сценарии.
Пять таблиц могут иметь разный порядок колонок, пустые строки, дубли и формулы, которые библиотека не пересчитывает сама. Поэтому отделим настройку, входные данные, основное действие и проверку. В этой статье вы соберёте скрипт, который собирает входные XLSX из папки, проверяет заголовки и создаёт один отчёт с итогами. Проверка: все корректные строки объединены, дубли по номеру заказа удалены, сумма совпадает с контрольным расчётом, исходники не изменены.
найти XLSX во входной папке. Не расширяйте проект до первого успешного запуска.
сломанный файл получает понятную ошибку. Проверяйте значение, а не отсутствие ошибки.
После успеха добавьте листы Сводка и Ошибки, не теряя исходную строку. Так копирование станет практикой.
Как устроен учебный проект openpyxl
openpyxl разделяет подготовку, основное действие, проверку ответа и сохранение результата. Держите ввод, логику и отображение раздельно: тогда каждый этап можно проверить отдельно.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Поиск | найти XLSX во входной папке | выходной файл не попадает во вход |
| Проверка | сопоставить обязательные заголовки | сломанный файл получает понятную ошибку |
| Сборка | прочитать строки и убрать дубли по order_id | каждый заказ встречается один раз |
| Отчёт | записать таблицу, формулу и стили | result.xlsx открывается и фильтруется |
Контрольные точки: поиск, проверка, сборка и отчёт. Следующий шаг начинается после совпадения с ожидаемым результатом.

От входных данных до видимого результата. Сначала проверяется вход, затем действие и только потом интерфейс.
Собираем рабочий пример шаг за шагом
Материал сверялся с официальной документацией сервиса 21 октября 2026 года. Создайте окружение, установите openpyxl и подготовьте каталог input. Скрипт и result.xlsx храните вне него. Проверьте текущую папку через pwd или Get-Location. Вставьте пример целиком, выполните один раз, затем разбирайте по частям.
from pathlib import Path
from openpyxl import load_workbook, Workbook
from openpyxl.styles import Font, PatternFill
REQUIRED = ['order_id', 'date', 'manager', 'amount']
def read_rows(filename: Path):
book = load_workbook(filename, data_only=True, read_only=True)
sheet = book.active
headers = [cell.value for cell in next(sheet.iter_rows())]
if not set(REQUIRED).issubset(headers):
raise ValueError(f'{filename.name}: нет обязательных колонок')
indexes = {name: headers.index(name) for name in REQUIRED}
for row in sheet.iter_rows(values_only=True):
if row[indexes['order_id']] is None: continue
yield {name: row[index] for name, index in indexes.items()}
def build_report(files, output='result.xlsx'):
unique = {}
for filename in files:
for row in read_rows(filename): unique[str(row['order_id'])] = row
book = Workbook(); sheet = book.active; sheet.title = 'Отчёт'
sheet.append(REQUIRED)
for row in unique.values(): sheet.append([row[name] for name in REQUIRED])
sheet['F1'] = 'Итого'; sheet['F2'] = f'=SUM(D2:D{sheet.max_row})'
for cell in sheet[1]: cell.font = Font(bold=True); cell.fill = PatternFill('solid', fgColor='D9EAD3')
sheet.freeze_panes = 'A2'; sheet.auto_filter.ref = f'A1:D{sheet.max_row}'
book.save(output)
files = sorted(Path('input').glob('*.xlsx'))
build_report(files)- result.xlsx содержит только уникальные order_id и исходные значения четырёх колонок.
- Заголовок закреплён, фильтр включён, ячейка F2 содержит формулу общей суммы.
- Повторный запуск даёт тот же предсказуемый результат.
- Пустой ввод получает понятное сообщение вместо падения.
Код держит подготовку отдельно от внешнего действия, поэтому ошибку можно найти на конкретном шаге. Найдите в примере вход, проверку и место формирования результата.

Что отличает устойчивый проект от случайного запуска. Явные границы делают ошибку локальной и понятной.
Что происходит внутри и почему это работает
read_only снижает память при чтении, data_only возвращает сохранённый результат формулы, а отдельный словарь unique делает правило дублей явным. Логику держите отдельно от вывода: функция получает аргумент и возвращает значение, а интерфейс показывает его. openpyxl записывает формулы, но не вычисляет их как Excel. Для проверки суммы посчитайте её в Python, а формулу оставьте пользователю.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| Чтение | проверяет заголовки и выдаёт строки | исходный файл не изменяется |
| Нормализация | сопоставляет колонки по имени | порядок столбцов не важен |
| Запись | создаёт новый workbook и оформление | итог проверен отдельно |
Правило дублей нужно выбрать до кода: оставить первый, последний или считать конфликт ошибкой. В примере последний файл побеждает, но отчёт должен явно фиксировать это решение. Не прячьте поток в одном обработчике: сохраните вход, проверьте его, вызовите операцию и только затем обновите интерфейс.
Проверяем проект и добавляем свою функцию
Добавьте лист Ошибки со строками, где amount не число, и лист Сводка с итогом по менеджерам. До правки запишите ожидаемое поведение одним предложением. После граничного теста повторите обычный сценарий.
- Сохраните ожидаемый результат: все корректные строки объединены, дубли по номеру заказа удалены, сумма совпадает с контрольным расчётом, исходники не изменены.
- Измените правило: добавьте листы Сводка и Ошибки, не теряя исходную строку. Сначала предскажите итог.
- Передайте граничное значение и убедитесь, что приложение не падает.
- Верните корректные данные и объясните роли трёх основных частей.
- выходной файл не попадает во вход
- сломанный файл получает понятную ошибку
- каждый заказ встречается один раз
- result.xlsx открывается и фильтруется
Полезное улучшение сохраняет исходный сценарий и добавляет одну новую проверяемую возможность. Полезная правка проходит от нового ввода до видимого результата.

Четыре проверки перед следующим шагом. Каждый следующий этап начинается после наблюдаемого результата.
Что запомнить и куда двигаться дальше
Перед рабочим запуском сделайте резервную копию, зафиксируйте правило дублей и сравните Python-сумму с Excel-итогом. Для закрепления откройте в анализе CSV через pandas, в отчёте Ozon Seller и в выгрузке Wildberries.
Как изучить тему в Кодике
Сначала разберите входные данные и один успешный вызов, затем изучайте дополнительные параметры. Сначала восстановите главную функцию и проверьте её на трёх значениях.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1. Основа | Path, функции, генераторы и словари Python | Объясните вход и выход функции. |
| 2. Инструмент | Workbook, worksheet, iter_rows и data_only | Повторите команду по памяти. |
| 3. Проект | Объединение, проверку заголовков и стили | Проверьте два сценария. |
| 4. Рефакторинг | Сводные листы, большие файлы и журнал ошибок | Разделите ввод, логику и вывод. |
Перепишите ключевую функцию по памяти и проверьте её на корректном, пустом и ошибочном вводе. Базовый синтаксис закрепите через курс Python.
Следующий запуск читает собственный отчёт. Разделите каталоги.
Изменение порядка ломает данные. Ищите индекс по заголовку.
Библиотека сохраняет формулу, но не является движком Excel.
Ошибка уничтожает данные. Всегда создавайте новый файл.
Что получится в итоге

Финальный экран показывает результат, состояние запроса и понятное сообщение об ошибке без раскрытия секретов.
Зачем data_only=True?
Он читает сохранённое значение формулы вместо её текста, если результат уже вычислен Excel.
Почему заголовки ищут по имени?
Тогда перестановка столбцов не смешивает поля.
Что проверять первым, если openpyxl не запускается?
Версию среды, текущую папку, команду запуска и первую строку ошибки.
Как понять, что проект openpyxl работает?
Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай.
Можно ли начать с готового кода?
Да. Добейтесь результата, измените одно правило и восстановите ключевую функцию без копирования.
Выберите одно улучшение и проведите его от ввода до результата.
Если не хватает основы, перейдите курс Python, затем восстановите ключевую функцию без подсказки.