logg-out.com

Первый прототип агрегатора недвижимости: что удалось автоматизировать

Первый прототип агрегатора недвижимости: что удалось автоматизировать

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

Зачем вообще нужен агрегатор недвижимости

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

Что стало основой первого прототипа

Первый прототип не был «большой платформой» в привычном смысле — это был компактный набор инструментов, который закрывал самые болезненные точки. Никакого монолита, только несколько ключевых модулей.

1. Сбор объявлений с нескольких площадок

Базовая функция — парсинг объявлений с популярных площадок недвижимости. Для первых экспериментов этого уже достаточно, чтобы увидеть рынок шире, чем на одной доске. Чаще всего открытых API у досок нет, поэтому приходится работать с HTML: писать адаптеры, которые через XPath или CSS-селекторы вытаскивают нужные поля, обрабатывать пагинацию и следить за структурой страницы. Это классический ETL-процесс: извлечь, преобразовать, загрузить.

Что собиралось в первую очередь:

  • заголовок объявления;
  • цена;
  • адрес или район;
  • количество комнат;
  • площадь;
  • этаж;
  • тип объекта;
  • ссылка на источник;
  • дата публикации или обновления;
  • фотографии;
  • признаки дублей и повторной публикации.

Именно наличие этих полей позволяет уже на старте строить нормальный поиск и не держать всё в голове. Без них аналитика превращается в гадание, а поиск — в бесконечный просмотр.

2. Единый формат данных

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

Поле Зачем нужно Проблема без нормализации
Цена Сравнение вариантов Нельзя сортировать и строить аналитику
Площадь Расчёт цены за м² Нельзя понять реальную стоимость
Район / адрес Геофильтрация Не работает поиск по локации
Комнаты Подбор по требованиям Смешиваются разные типы квартир
Источник Проверка и переход к объявлению Теряется контекст происхождения данных
Дата Отслеживание свежести Нельзя отсеять «мертвые» объявления

Технически это маппинг полей: для каждого источника задаётся правило, как извлечь значение и привести его к каноническому виду. Например, цена может приходить как «45 000 руб./мес» или «45000», поэтому нужно уметь вырезать число и определять валюту. Площадь может быть в квадратных метрах или в сотках — всё это требует конвертации и валидации. Без этого агрегатор превращается в свалку карточек. С нормализацией — в инструмент, которым уже можно пользоваться.

3. Фильтры по реальным критериям

Первый рабочий интерфейс не пытался быть красивым. Он должен был отвечать на простой вопрос: «Что мне подходит прямо сейчас?». Поэтому фильтры были такими:

  • цена от и до;
  • число комнат;
  • район или станция метро;
  • площадь;
  • тип сделки: аренда или продажа;
  • новостройка или вторичка;
  • дата обновления;
  • наличие фото;
  • возможность выбрать объявления только из свежей выдачи.

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

Что удалось автоматизировать в первом прототипе

Первый прототип сразу показал, где автоматизация даёт максимальный эффект. Ниже — конкретные модули, которые реально снимали рутину.

Автоматический сбор новых объявлений

Самый важный эффект — исчезла необходимость вручную открывать несколько сайтов и сравнивать одно и то же по кругу. Прототип начал сам собирать новые объявления по расписанию. Я использовал простой cron, запускающий скрипты каждые 15–30 минут. Для горячего рынка этого достаточно, чтобы не упустить свежие варианты.

Это дало сразу три преимущества:

  • объявления стали попадать в базу быстрее;
  • исчезли пропуски из-за человеческого фактора;
  • стало проще отслеживать динамику по одному и тому же объекту.

Конечно, пришлось решать вопросы с rate limiting и блокировками: некоторые площадки отдают 403 при частых запросах. Поэтому в адаптеры встроил задержки и рандомизацию User-Agent. Это не панацея, но для прототипа хватило.

Уведомления о новых объектах

Следующий шаг — уведомления. Если появляется подходящий объект, система должна сообщать об этом без участия пользователя. Я не стал строить сложный сервис пушей, а использовал Telegram Bot API: после каждого цикла сбора скрипт проверял новые карточки относительно заданных фильтров и отправлял сообщения в канал или личные чаты. Это работает надёжно и не требует инфраструктуры.

Практически это особенно полезно, когда:

  • рынок горячий и хорошие варианты исчезают за часы;
  • есть жёсткий бюджет;
  • нужен редкий формат объекта;
  • важна конкретная локация.

Вручную такой мониторинг почти всегда ломается через несколько дней. Автоматизация здесь даёт реальный выигрыш.

Конвертация и нормализация форматов

Отдельный маленький, но очень полезный инструмент — конвертер. На практике данные часто нужны не «как есть», а в удобном виде:

  • CSV для таблиц;
  • JSON для дальнейшей обработки;
  • Excel для быстрой ручной работы;
  • структурированный формат для импорта в другие сервисы.

Я реализовал экспорт в пару кликов: любой набор отфильтрованных карточек можно выгрузить в нужном формате. Это оказалось удобно для ручного анализа и для интеграции с CRM или аналитическими системами. Именно с конвертации часто начинается путь от хобби-парсера к полезному продукту.

Калькулятор ипотеки на основе реальных цен

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

Это полезно, когда нужно:

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

Такой расчёт лучше показывает реальную картину, чем усреднённые значения из рекламных материалов. Когда видишь, что из 20 подходящих по цене квартир реально доступны только 3 в заданном районе, это отрезвляет.

Что оказалось сложнее, чем выглядело сначала

Первый прототип быстро показал: автоматизация недвижимости — это не только про код. Есть несколько системных проблем, которые всплывают почти сразу.

Дубли объявлений

Один и тот же объект может всплывать на разных площадках, в разное время и с разными формулировками. Иногда его публикует агентство, иногда собственник, иногда объявление обновляется без явной смены текста. Наивный подход — сравнивать по одному полю — не работает, потому что адрес может быть записан по-разному: «ул. Ленина, 10» и «Ленина 10 кв. 5».

Что помогает:

  • сравнение по адресу, площади и цене с допуском на незначительные расхождения;
  • поиск похожих фотографий — я использовал перцептивный хеш (pHash) для быстрого отсеивания кандидатов;
  • отслеживание совпадений по контактам;
  • выделение объявлений с одинаковым набором признаков.

Дедупликация — это не разовая задача, а постоянный процесс, потому что площадки могут переиндексировать одно и то же объявление с новым ID.

Неполные или грязные данные

На практике в объявлениях часто не хватает:

  • точного адреса;
  • этажности дома;
  • года постройки;
  • информации о ремонте;
  • адекватного описания;
  • корректной площади.

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

Быстро меняющаяся верстка

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

Что помогает на старте:

  • изолировать адаптеры под каждый источник;
  • хранить логи ошибок парсинга с контекстом запроса;
  • проверять выборку на пустые значения после каждого запуска;
  • иметь механизм быстрого обновления парсера (например, через конфиг с селекторами, а не перекомпиляцию);
  • не завязывать всю систему на один источник — всегда иметь fallback.

Отдельная боль — сайты с JavaScript-рендерингом. Для них приходится подключать headless-браузеры, что увеличивает время сбора и нагрузку. В прототипе я старался обходиться обычными HTTP-запросами, а JS-рендеринг использовал только для самых критичных источников.

Ограничения и юридическая аккуратность

При работе с объявлениями важно помнить: собранные данные нельзя использовать бездумно. Нужны:

  • уважение к правилам источников — проверять robots.txt и условия использования;
  • аккуратная работа с контактами — не публиковать их без необходимости, не спамить;
  • понятная политика хранения данных — как долго хранятся карточки, кто имеет к ним доступ;
  • контроль того, что именно индексируется и как используется;
  • соблюдение региональных законов о персональных данных (для РФ — 152-ФЗ, для Европы — GDPR).

Это не только вопрос этики, но и устойчивости продукта. Один судебный иск может похоронить сервис, поэтому лучше сразу заложить ограничения в архитектуру.

Как выглядела минимальная архитектура

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

Базовый поток данных

  1. Планировщик (cron) запускает сбор по расписанию.
  2. Парсер забирает объявления с источников через HTTP-запросы или headless-браузер.
  3. Данные проходят нормализацию: чистка полей, конвертация единиц, валидация.
  4. Система ищет дубликаты, сравнивая с уже существующими записями.
  5. Объявления сохраняются в базе данных с историей изменений.
  6. Пользователь получает фильтрованную выдачу и уведомления о новых совпадениях.

Весь поток можно уложить в простой пайплайн: планировщик → парсеры → нормализатор → дедупликатор → база → API для фронтенда → нотификации. На старте не нужны очереди сообщений, хотя при росте объёмов я бы сразу добавил что-то типа RabbitMQ или Redis Streams, чтобы разгрузить сбор и обработку.

Минимальный стек для такого прототипа

Компонент Назначение
Сборщик данных Получение объявлений с сайтов (Python, Playwright/Requests)
Нормализатор Приведение данных к единому виду (скрипты на Python или Node.js)
База данных Хранение карточек и истории изменений (PostgreSQL + JSONB)
Фильтры Поиск по параметрам (индексы в БД, запросы к API)
Уведомления Оповещение о новых совпадениях (Telegram Bot API)
Экспорт Выгрузка в CSV, JSON, Excel (библиотеки для генерации файлов)

Этого достаточно, чтобы проверить гипотезу и понять, нужен ли продукт рынку. Я собирал всё в Docker-контейнерах, чтобы легко переносить и масштабировать.

Какие функции были самыми полезными для пользователя

Если смотреть не глазами разработчика, а глазами человека, который ищет жильё, то ценность оказалась в следующем.

  • Одна лента вместо десятка вкладок. Все объявления в одном интерфейсе, без переключения между сайтами.
  • Свежие объявления без ручного обновления. Система сама подтягивает новые карточки, не нужно нажимать F5.
  • Быстрый отбор по бюджету и району. Фильтры применяются мгновенно, потому что данные уже нормализованы.
  • Сравнение объектов в одном формате. Можно открыть две карточки рядом и видеть разницу по площади, цене, этажу.
  • Понимание рынка через аналитику, а не интуицию. Видно, какова реальная цена квадратного метра в конкретном районе, сколько объектов доступно в бюджете.

Именно это делает агрегатор полезным не как техническую игрушку, а как инструмент принятия решений.

Типовые ошибки при создании первого прототипа

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

1. Собирать всё подряд

Сначала кажется, что чем больше данных, тем лучше. На деле это часто создаёт шум: объявления с одной площадки могут быть некачественными, дублироваться или содержать мусор. Лучше начать с ограниченного набора полей, но сделать их чистыми и стабильными. Дополнительные поля можно добавить позже, когда выстроится пайплайн.

2. Игнорировать дубли

Без дедупликации один объект выглядит как несколько разных вариантов. Это портит аналитику — средняя цена по району получается заниженной или завышенной из-за повторений — и раздражает пользователя, который видит одну и ту же квартиру трижды. Дедупликацию нужно закладывать с первого дня.

3. Делать фильтры слишком поздно

Если фильтрация появляется только в конце, когда база уже разрослась, приходится пересобирать архитектуру. Лучше заложить её сразу: хранить все параметры, по которым возможен отбор, в отдельных полях с индексами. Тогда фронтенд может строить любые запросы без переделки бэкенда.

4. Не хранить историю изменений

Цена, статус и описание могут меняться. Без истории невозможно понять, как рынок двигается и что происходило с конкретным объектом. Я рекомендую хранить снапшоты карточки при каждом обновлении или хотя бы логировать изменения ключевых полей. Это даёт возможность строить аналитику динамики цен и видеть, когда объект был снят с продажи.

5. Пытаться сразу построить «идеальную платформу»

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

Чек-лист: что стоит автоматизировать в первом MVP

  • сбор новых объявлений по расписанию;
  • нормализацию полей в единый формат;
  • поиск и пометку дублей;
  • фильтры по цене, району, площади, комнатам;
  • экспорт в удобный формат (CSV, JSON, Excel);
  • уведомления о новых совпадениях;
  • базовую аналитику по ценам (медиана, диапазон, цена за м²);
  • хранение истории изменений;
  • контроль качества данных (проверка на пустые значения и выбросы);
  • логирование ошибок парсинга с возможностью быстрого отладчика.

Что бы я сделал иначе с самого начала

Если смотреть на первый прототип с позиции опыта, то я бы сразу заложил три вещи:

  • Отдельный слой под каждый источник. Это означает не просто отдельные скрипты, а полноценные адаптеры с интерфейсом, которые принимают URL и возвращают нормализованные объекты. Тогда добавление нового источника сводится к написанию одного класса, а не к переписыванию всего пайплайна.
  • Хранение не только текущего состояния, но и истории. Вместо того чтобы обновлять запись в базе, лучше добавлять новую версию с timestamp, а текущей считать последнюю. Это немного усложняет запросы, но даёт огромное преимущество для аналитики и отладки.
  • Оценку качества данных для каждой карточки. Помимо самих полей, хранить числовой score (например, процент заполненности) и флаги для подозрительных значений. Это позволяет автоматически отфильтровывать мусор, не вводя жёстких правил.

Это сильно упрощает дальнейший рост продукта. Когда агрегатор превращается из «сборщика объявлений» в полноценный сервис, именно эти детали начинают экономить месяцы переделок.

Вывод

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

Главный результат такого кейса — не только работающий парсер, а понятие, какие процессы действительно стоит автоматизировать в недвижимости, а какие лучше оставить на следующую итерацию. И да, иногда лучше потратить час на написание скрипта, чем неделю на ручной мониторинг.

FAQ

Чем агрегатор недвижимости отличается от обычного поиска на одном сайте?

Агрегатор собирает объявления из нескольких источников, нормализует их и позволяет сравнивать варианты в одном интерфейсе. Обычный поиск ограничен данными одной площадки и не гарантирует, что вы видите все доступные объекты.

Что важнее в первом прототипе: дизайн или данные?

Сначала важнее данные. Если карточки неточные, дублируются или плохо фильтруются, красивый интерфейс не спасёт. Лучше сделать простой, но честный UI поверх чистых данных, чем наоборот.

Можно ли обойтись без аналитики на старте?

Можно, но это быстро ограничивает ценность продукта. Даже базовая аналитика по ценам помогает принимать решения лучше, чем просто листание карточек. Расчёт медианной цены за квадратный метр по району — это минимальный набор для старта.

Зачем хранить историю изменений объявления?

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

Какие функции стоит добавить после MVP?

После MVP обычно добавляют более точную дедупликацию, геоаналитику (карты, тепловые карты цен), расширенные уведомления с фильтрами, интеграции с CRM риелторских агентств и API для застройщиков, а также расширенную аналитику рынка: прогнозы, индексы, оценку ликвидности.