Перейти к содержимому

Разрешить сайту считать ваши посещения с помощью Яндекс Метрики? Для этого она сохранит в браузере файлы cookie. Как сайт использует cookie

VC
Кейс 25 из 25 · Веб · Инструменты

Настольная программа собирает промо-страницу из описания или по ссылке

Этот инструмент я сделал для собственной работы. Раньше каждая промо-страница была копией предыдущей: служебные теги, тексты, картинки и цвета правили вручную. Теперь программа собирает страницу из шаблона и описания или берёт содержимое готовой страницы по ссылке, а готовый архив сама выгружает на хостинг.

Тип проекта
Собственный инструмент · внутренняя разработка
Технологии
Python · tkinter · Pillow
Срок
Около месяца доработок, 26 коммитов
Итог
Описание или ссылка → страница на хостинге
01 · Проблема

Каждая новая страница была копией предыдущей

Промо-страницу под новый товар или новый язык делали всегда одинаково: копировали папку предыдущей, проходили вручную по всей разметке и переписывали всё, что относилось к старому проекту. Заголовок, meta description, весь блок og:* (он отвечает за то, как ссылка выглядит в соцсетях), значок сайта, файл настроек с названием магазина и ценами, вводные тексты, вопросы опроса, отзывы, блок предложения — и только потом изображения.

С изображениями ошибались чаще всего. У шаблона есть постоянные места: логотип на первом экране, логотип в шапке, значок сайта, фон страницы, фото товара, картинка для соцсетей. Файлы из источника приходят вперемешку с декоративными иконками, аватарами и значками, и на место логотипа то и дело попадало не то. К тому же за весом файлов никто не следил: исходник на несколько мегабайт уходил на живой сайт как есть.

Последний шаг тоже был ручным: собрать папку в архив, зайти в панель хостинга, создать группу, загрузить zip и разобраться с совпадением имён, если такая страница уже была. Один раз это терпимо. Но когда страниц несколько в неделю и у каждой есть варианты по языку и цветам, работа сводится к обслуживанию собственных копий.

02 · Решение

Настольная программа разбирает источник и собирает страницу

Программа — обычное окно на tkinter, стандартной библиотеке Python для оконных интерфейсов. В ней есть вкладки: проект, содержимое, цвета, изображения, опрос, отзывы, публикация, журнал. Сервер и сборка не нужны: программа открывается двойным щелчком, файлы запуска для macOS и Windows лежат в репозитории. Работа идёт в одну сторону: источник разбирается, шаблон заполняется, результат отправляется на хостинг.

01
Источник

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

02
Разбор

Заголовки, служебные теги, названия, цены, тексты, вопросы, отзывы, цвета из CSS

03
Места в шаблоне

Логотип, значок сайта, фон и фото товара программа находит по разметке; поправить можно вручную в её окне

04
Сборка

Шаблон и содержимое собираются в папку, картинки сжимаются, разметка проверяется автоматически

05
Публикация

Архив собирается в памяти и уходит на хостинг через его API: группа, имя по шаблону, при совпадении имени — перезапись

Два семейства шаблонов в одном интерфейсе

В репозитории два шаблона: template_1 на Bootstrap и template_2 — статическая сборка на Astro со стилями в духе Tailwind. Разметка, имена файлов и набор мест под содержимое у них разные. Поэтому при переключении шаблона программа перестраивает вкладки: у каждого шаблона свои места под изображения, свой набор цветов и свои правила подстановки. Для пользователя порядок работы остаётся тем же.

Страница по ссылке: встроенный загрузчик

Источником может быть папка на компьютере или адрес уже существующей страницы. Загрузчик написан на стандартной библиотеке Python и ведёт себя как аккуратный браузер:

  • учитывает <base href>, когда восстанавливает относительные пути
  • собирает файлы страницы из img/link/script/source/srcset и из url(...) во встроенных стилях
  • проходит по CSS вглубь, включая url() и @import, чтобы не потерять шрифты и фоны
  • скачивает файлы только с того же сайта; файлы с внешних CDN остаются ссылками
  • перед разбором вырезает содержимое <script>: иначе строки внутри встроенного JS принимаются за src=

Логотип, значок сайта и фон программа находит по разметке

Первая версия раскладывала картинки по местам, угадывая по имени и размеру файла, и подставляла в шапку случайные картинки. Теперь главное — разметка: значок сайта (фавикон) берётся из <link rel="icon">, логотип — из шапки и из alt/class со словами logo/brand, фон — из background-image: url(...) у body/html, картинки отзывов — из своих блоков. Угадывание по имени и весу осталось только запасным вариантом. Декоративные иконки, аватарки и значки внесены в список исключений и больше не оказываются на месте логотипа. Всё, что программа не смогла определить, видно в интерфейсе и правится вручную.

Цвета берутся с исходной страницы

Программа читает HTML вместе с подключёнными файлами CSS и достаёт цвета из переменных темы. Если цвет задан несколько раз, берётся последнее значение, потому что тема должна перекрывать базовые стили. Цвета из hex, rgb() и oklch() приводятся к одному виду. Серые и почти белые отбрасываются, а остальные распределяются по ролям: кнопка, текст кнопки, шапка, фон страницы, карточка, акцент. Дальше цвета видны в интерфейсе как обычные поля, и любой из них можно поправить.

Проект хранится в файле JSON

Всё о сборке сохраняется в файл проекта: выбранный шаблон, пути, всё содержимое, цвета, раскладка картинок по местам, вопросы, отзывы. Чтобы повторить страницу или сделать вариант, достаточно открыть проект и поправить пару полей. Файлы проектов лежат в репозитории рядом с кодом, поэтому у каждой сборки есть история версий.

Картинки сжимаются перед публикацией

Каждый файл, который попадает в шаблон, проходит через Pillow, библиотеку для работы с картинками. Она уменьшает картинку по большей стороне, сохраняет прозрачность у PNG и WebP и выбирает разумное качество. Если Pillow недоступен, файлы просто копируются, и сборка не прерывается. Вручную за такими мелочами на каждой странице не уследишь.

Перед публикацией программа проверяет разметку

У готовой страницы есть обязательные элементы, которые легко потерять при правке шаблона. Это скрытые метки, на место которых хостинг подставляет данные при показе страницы, и общий идентификатор события для аналитики в браузере и на сервере. Программа проверяет их перед выгрузкой: если чего-то нет, восстанавливает и пишет предупреждение в журнал. Правка шаблона не должна незаметно ломать учёт событий: когда статистика молча показывает нули, это замечают слишком поздно.

Публикация в одно действие, даже если имя уже занято

Готовая папка упаковывается в ZIP прямо в памяти (служебные файлы вроде .DS_Store отсеиваются), кодируется в base64 и отправляется на хостинг через его API. Существующие группы подгружаются в выпадающий список, а имя страницы собирается по шаблону вида {store} - {product} - {template} - {lang}. Если хостинг отвечает ошибкой 422 «имя занято», работа не прерывается: программа находит существующую запись и спрашивает, перезаписать ли её. Если согласиться, она отправляет запрос PUT по найденному id. Ключ доступа хранится вне репозитория, в локальном файле настроек, который может читать только владелец (права 600).

Правила оформления лежат рядом с кодом

В репозитории лежат три брифа. Первый описывает общие основы: шрифты, сетку, состояния элементов, мобильную версию и допустимый вес страницы. Ещё два написаны для каждого семейства шаблонов: в них разобран каждый CSS-селектор, перечислено, что убрать и что добавить, и есть список для проверки. Программа отвечает за структуру, брифы — за внешний вид. Без брифов программа просто быстрее тиражировала бы неудачную вёрстку.

03 · Технологии

Программа без сборки открывается двойным щелчком

Python 3 + tkinter

Приложение на компьютере: без сервера и без отдельного шага сборки

html.parser и регулярные выражения

Разбор исходной страницы: служебные теги, тексты, цены, вопросы, отзывы

urllib (стандартная библиотека)

Загрузка страницы по ссылке и обращения к API хостинга

Pillow

Предпросмотр в интерфейсе и сжатие картинок перед публикацией

zipfile + base64

Упаковка результата в памяти и выгрузка архива через API

Проекты в JSON

Все настройки сборки лежат в файле: страницу можно повторить или сделать вариант

template_1 · Bootstrap

Первое семейство шаблонов со своим набором мест под содержимое

template_2 · Astro-экспорт

Второе семейство: статическая сборка на Astro со стилями в духе Tailwind

design-briefs/

Правила оформления: общие основы и бриф для каждого семейства

.app / run.sh / run.bat

Файлы запуска для macOS и Windows: программа открывается двойным щелчком

PythontkinterPillowhtml.parserurllibzipfileAdmin APIBootstrapAstroTailwind
04 · Результат

Страница собирается из проекта

Сборка страницы
10 шагов 1 прогон

ручную правку разметки заменил один запуск программы

Публикация
1 действие

архив, группа, имя и совпадение имён программа берёт на себя

Развитие инструмента
26

коммитов; правки приходили из реальных сборок

Типовые ошибки теперь ловятся до выгрузки

Забытый og:image, значок сайта от прошлого проекта, логотип не на своём месте, картинка на несколько мегабайт, фон, потерянный при переносе, — всё это раньше замечали глазами уже на живой странице. Теперь эти вещи либо вынесены в интерфейс отдельными полями, либо проверяются автоматически перед выгрузкой.

История коммитов — список найденных ошибок

Инструмент доводился на реальных сборках, и почти каждый коммит исправлял конкретную ошибку. Логотип из-за анимации увеличивался на доли пикселя. Относительные пути ломались при переносе. Совпадение имён при повторной выгрузке раньше просто прерывало работу. Мелкие иконки программа принимала за логотип. Такие вещи заранее не предусмотришь, они обнаруживаются в работе. Поэтому инструмент под свой процесс имеет смысл дорабатывать на живых задачах.

Ограничения

Это внутренний инструмент. Интерфейс не покрыт автоматическими тестами. Качество разбора напрямую зависит от того, насколько аккуратно свёрстан источник. На нестандартной странице программа заполняет часть полей неверно. Поэтому всё, что она определила, можно отредактировать, а журнал показывает каждый шаг. Пользователь всегда видит, что именно подставлено и откуда.

05 · Применимость

Где ещё работает тот же подход

За кейсом стоит типовая задача: «шаблон и содержимое → готовая страница → публикация без ручных шагов». Схема почти без изменений подходит везде, где однотипные страницы делают вручную:

  • → Страницы на нескольких языках и для нескольких брендов — одна сборка, разные проекты: язык, цвета, логотип, тексты
  • → Посадочные страницы для каждого товара из выгрузки каталога — собираются партиями, без ручной вёрстки
  • → Тиражирование сайтов сети или франшизы — общий шаблон, свои контакты, цвета и логотип на каждую точку
  • → Перенос существующей страницы на новый шаблон — загрузчик скачивает исходную страницу, а разбор достаёт из неё содержимое и цвета
  • → Подготовка вариантов для сравнительных тестов — те же тексты, другие цвета и раскладка картинок, публикация одной очередью
  • → Тот же код без интерфейса — как шаг автоматической сборки (CI): на входе проект в JSON, на выходе опубликованная страница
Что переиспользуется на следующих проектах
  • Загрузчик страницы: проход по CSS вглубь, файлы только с того же сайта, исходная структура папок
  • Раскладка изображений по местам: сначала по разметке, потом по имени и весу, и всегда с возможностью поправить вручную
  • Цвета из CSS-переменных: hex, rgb и oklch, тема перекрывает базовые стили, серые отсеиваются
  • Проект в JSON: сборку можно повторить, хранить её версии и брать за основу для варианта
  • Проверка обязательных меток в разметке перед публикацией: недостающие восстанавливаются, в журнал пишется предупреждение
  • Публикация на хостинг или в CMS через API: архив в памяти, base64, перезапись при совпадении имени
Похожая задача?

Если каждая страница — копия предыдущей, её можно собирать программой

Свой инструмент оправдывает себя там, где однотипные страницы делают каждую неделю. Начинать стоит с одного шаблона, одного формата источника и одного места публикации. Остальное добавляется по ходу реальной работы. Делать такие программы самостоятельно можно научиться на уроках по вайбкодингу.