Пошаговая инструкция по созданию автоматизированного конвейера на Airflow, Selenium и Scikit-learn.

Вступление: Автоматизируем рутину

Привет, Хабр! Каждый, кто хоть раз искал подержанную технику, знает эту боль: часы ручного мониторинга Avito, десятки страниц и попытки на глаз определить, адекватна ли цена. Выгодные предложения улетают за минуты.

Я решил подойти к этой задаче как инженер и создать личного ассистента, который бы делал всю грязную работу за меня: 24/7 сканировал Avito, сам оценивал адекватность цены и присылал мне в Telegram только самые сливки.

Так родилась идея проекта Intelligent Deal Finder. В этой статье я познакомлю вас со своим проектом, который решает эту задачу. Эта статья будет ознакомительной.

Часть 1: Архитектура и технологический стек

Любой сложный проект начинается с плана. Я разбил систему на пять логических блоков, которые будут работать в связке:

  1. Парсер: Модуль для сбора сырых данных с Avito.

  2. Хранилище: База данных для накопления объявлений.

  3. Мозг: ML-модель для оценки адекватности цены.

  4. Оркестратор: Система, которая будет запускать все по расписанию.

  5. Уведомитель: Бот для доставки результатов.

Технологический стек выбрал проверенный и надежный: PythonSeleniumPostgreSQLScikit-learnApache Airflow и Docker.

Часть 2: Сбор и подготовка данных — залог успеха

Основа любой ML-системы — это качественные данные. Мой пайплайн начинается с парсера на Selenium, который заходит на Avito, собирает объявления и передает их дальше.

Ключевой момент — качество данных. Заголовки на Avito могут быть очень грязными. Чтобы не усложнять модель, я принял простое, но эффективное решение: работать только с идеальными заголовками, которых большинство. Я написал строгий фильтр, который пропускает дальше только те объявления, чей заголовок в точности соответствует формату "iPhone [Модель], [Память] ГБ/ТБ".

# Фильтр, который отсекает все лишнее
perfect_title_pattern = r'^iPhone[\w\s]+,\s\d+\s(?:ГБ|ТБ)$'
df = df[df['title'].str.match(perfect_title_pattern, na=False)]

Такой подход позволил сразу отсечь шум и работать с чистым, структурированным датасетом, что, как мы увидим дальше, оказалось решающим фактором.

Часть 3: Создание мозга — предсказательная модель

Имея на руках несколько тысяч идеально отфильтрованных объявлений, я приступил к созданию модели. Гипотеза была проста: на таком чистом рынке цена в первую очередь определяется моделью телефона и объемом его памяти.

Я взял эти два признака, применил к ним стандартный One-Hot Encoding из Pandas и обучил модель RandomForestRegressor из Scikit-learn. Результат оказался на удивление точным:

  • R² (коэффициент детерминации): 0.91

  • MAE (средняя абсолютная ошибка): ~4,708 рублей

R² = 0.91 означает, что модель, зная лишь модель и память, уже способна объяснить 91% вариативности цен! Это доказывает, что тщательная фильтрация данных на входе — ключ к успеху.

Часть 4: Ставим все на рельсы — MLOps с Airflow и Docker

Теперь, когда у нас есть работающая модель, нужно заставить всю систему работать автоматически. Для этого я использовал Apache Airflow.

Я создал простой DAG (process_avito_ads) из трех шагов, которые выполняются последовательно:

  1. gather_data_task: Запускает парсер, фильтрует данные по идеальному заголовку и сохраняет их в PostgreSQL.

  2. predict_and_filter_task: Применяет к новым данным нашу обученную модель и отбирает объявления, где предсказанная_цена - реальная_цена больше заданного порога (например, 5000 рублей).

  3. send_notifications_task: Отправляет отфильтрованный список выгодных предложений в Telegram.

Весь проект, включая Airflow, PostgreSQL и сам код приложения, я упаковал в Docker Compose. Это позволяет одной командой docker-compose up --build -d развернуть всю инфраструктуру на любой машине.

Заключение: Результат и следующие шаги

И вот, ради чего все затевалось. После всей настройки я запустил DAG и через несколько минут получил первое уведомление в Telegram.

Система работает! Она автономно сканирует рынок и доставляет мне только самую ценную информацию, экономя уйму времени.

Этот проект — отличный пример того, как, объединив парсинг, Data Science и MLOps-инструменты, можно создать полезный и работающий продукт. В следующей статье я планирую подробнее рассказать о проблемах, с которыми я сталкивался, о гипотезах и инсайтах.

Весь код проекта доступен на GitHub. Буду рад вашим комментариям и вопросам.

Комментарии (10)


  1. Magi
    14.10.2025 11:01

    Ссылка битая.


    1. agmike
      14.10.2025 11:01

      В профиле автора написано "ML-разработчик (стажер). Предполагаю, в связи с этим, что репозиторий может быть приватным)


    1. K1ree8 Автор
      14.10.2025 11:01

      открыто


  1. kenomimi
    14.10.2025 11:01

    Самые сливки сидят как раз в хреновых заголовках. Потому что если у продавца хватило ума написать хороший заголовок (или оставить правильно угаданный автоматический), то и ценник он поставит плюс-минус рыночный. Зато те, кто два слова связать не может, чаще всего и в анализ рынка не могут, и местами сливают технику по цене сильно ниже рынка. Риски тут тоже выше, но нормальный перекуп знает матчасть, его не обманешь.


    1. K1ree8 Автор
      14.10.2025 11:01

      Так как я работал с айфонами - у них там стандартные заголовки "Модель, Память". Авито предлагает пользователям релевантные заголовки при создании объявления. Обычно все его и оставляют. Но есть те, кто что-то еще добавляет. Ну вот пару примеров:
      iPhone 14 Plus 256gb все родное Sim+Sim
      iPhone 14 Plus, 256 гб,nanoSim/eSim
      iPhone 14 pro 128 гб Space black SIM+eSIM
      iPhone 14 Pro 128gb Deep Purple Sim+eSim
      iPhone 14 pro 128gb dual sim
      iPhone 14 Pro / 128 gb / Deep Purple / Sim + Esim
      iPhone 14 Pro 128gb Sim+eSim
      iPhone 14 pro 256gb dual sim
      iPhone 14 Pro Deep Purple 256GB (sim+esim)
      iPhone 14 pro 256 гб dual-sim
      iPhone 14 Pro 256 GB Space Gray, dual SIM (2x SIM)
      iPhone 14 pro 256 гб sim+esim
      iPhone 14 Pro 256gb Deep Purple eSim


      Вот и на кой так усложнять, если вот человеческие заголовки:

      Я предполагаю, то что как раз такие пользователи "знают цену", и пытаются ее "отобразить" в заголовке. Но так как цель моего проекта - это "выявлять недооцененные товары у частных продавцов бывшего пользования для последующей перепродажи" - для меня не выгодно, чтобы они знали его цену) И вот можно сказать это такой "фильтр" от шарющих. Обычные бы пользователи не стали бы париться. Ну вот большинство и не париться.


      1. K1ree8 Автор
        14.10.2025 11:01

        И вот это мне позволило сделать "простую" модель. Я достал из стандартного заголовка признаки: модель, память. И там с помощью OHE получилась бинарная табличка с 49 признаками: все модели и объемы (64 ГБ, 128 ГБ, 256 ГБ, 512 ГБ, 1 ТБ). И только из этих штук у меня получилась крутая модель. Я также пробовал работать с описанием и рейтингом продавца, но значительных улучшений не принесло. Даже немного путало. И я остановился на такой простенькой модели. Но с таким же успехом я бы мог просто взять средние или медиану по каждой вариации модель+память - и да, но я все еще работаю с проектом. Возможно я найду ещё какие-нибудь инсайты и закономерности на рынке.


  1. therealspeaker
    14.10.2025 11:01

    Необходимо учитывать представителей "Барклая 8", у которых стоимость в объявлении никогда не соответствует действительной.


    1. K1ree8 Автор
      14.10.2025 11:01

      Да были моменты, когда такие вот уникомы, например, ставили цену 9999999₽. Либо наоборот ставили цену 100 рублей и писали - обмен. Я их отбрасывал с помощью квантилей. А так обычно цены +/- адекватные


  1. stuzhik
    14.10.2025 11:01

    avitobotmailing в докерхаб ????


  1. K1ree8 Автор
    14.10.2025 11:01

    Я открыл репозиторий