Исходная ситуация: в отделе закупок ежедневно отслеживаются новые тендеры по 6 электронным торговым площадкам (ETP). Сейчас это делается вручную в браузере с фильтрами, из-за чего часть релевантных закупок пропускается, а данные из разных ETP не приводятся к единому виду. Техническая среда и ограничения: Linux-сервер (Ubuntu 22.04), доступ по SSH. Разрешено использовать Python 3.11, Playwright или Selenium, requests/httpx, PostgreSQL 14 (БД уже есть). Docker можно, но не обязателен. Нельзя использовать платные антикапча-сервисы и нельзя хранить учетные данные от личных кабинетов в открытом виде. Доступ к ETP только как гость, без авторизации. У части сайтов контент подгружается JavaScript, присутствуют антибот-защиты и лимиты на частоту запросов. Предметная область: тендеры/закупки. Требуется собирать карточки закупок и лоты, нормализовать категории и суммы, сохранять историю изменений. Что должно получиться: автономный парсер, который по расписанию собирает данные с 6 заданных ETP (список доменов и примеры ссылок на выдачу предоставлю), приводит их к общей схеме и складывает в PostgreSQL, а также отправляет уведомления в Telegram при появлении новых релевантных закупок. Этапы и ключевые требования: 1) Анализ источников - для каждой ETP определить способ загрузки (XHR/GraphQL/HTML/JS-render), точки входа выдачи и карточки, набор полей, ограничения по скорости. 2) Реализация сборщика - отдельные модули-адаптеры по каждому источнику с единым интерфейсом. Должны поддерживаться повторы, backoff, таймауты, ограничение параллелизма, ротация User-Agent, работа через прокси (прокси предоставлю) и устойчивость к частичным сбоям. 3) Нормализация данных - единая модель в БД: закупка, лот, заказчик, регион, даты (публикация/окончание), НМЦ/валюта, статус, ссылка, площадка, текстовое описание, CPV/ОКПД2 (если есть), а также вычисляемое поле релевантности по ключевым словам и исключающим словам (список предоставлю). Суммы привести к числу, даты к UTC, удалить дубль-объявления между ETP по набору эвристик (ИНН заказчика + сумма + даты + похожесть названия). 4) Хранение истории - при изменении статуса или даты окончания должна фиксироваться новая запись в таблице истории с timestamp и изменёнными полями. 5) Уведомления - Telegram-бот присылает сообщение о новых релевантных закупках, не более 1 уведомления на закупку, с краткими полями и ссылкой. Также команда /health возвращает статистику последнего прогона (сколько собрано по источникам, сколько ошибок, время). 6) Эксплуатация - запуск по cron или systemd timer, логирование в файл, понятные сообщения об ошибках по каждому источнику. Конкретный результат: репозиторий с исходным кодом, конфигурацией (env/ini/yaml), SQL-миграциями схемы, инструкцией запуска на Ubuntu, а также примером конфигурации фильтров релевантности. Измеримые критерии приёмки: - На тестовом прогоне за 24 часа парсер собирает не менее 95% объявлений из выдачи по каждому источнику в пределах первых 3 страниц (сверка по ручному подсчету на выборке из 30 объявлений на источник). - Дубли в БД не превышают 2% от общего числа записей за прогон (проверка по уникальному ключу и эвристикам дедупликации). - Повторный запуск на тех же фильтрах не создаёт новые записи закупок, если на источниках нет изменений, а история пополняется только при реальных изменениях полей. - Время полного прогона по всем источникам не более 45 минут на сервере 2 vCPU/4 GB RAM при ограничении до 3 параллельных задач. - Логи содержат раздельную статистику по источникам и коды причин ошибок (таймаут, блок, парсинг, структура изменилась). Дополнительно: список ETP, примеры URL, ключевые слова и доступ к тестовой БД предоставлю после согласования подхода и структуры данных.