Нужны данные о рынке. Не "средняя цена на Бали" из статьи двухлетней давности, а живые цифры: сколько стоит вилла с 3 спальнями в Чангу прямо сейчас, какая заполняемость у конкурентов, когда начинается высокий сезон по факту, а не по учебнику. Без этих данных управление виллами — гадание на кофейной гуще.

За три дня (4-6 февраля) написал Market Intelligence — отдельный микросервис для парсинга Airbnb, Booking.com и Agoda. Примерно 105 коммитов. Парсеры, прокси-ротация, обработка данных, фронтенд с дашбордами.

Отдельная инфраструктура

Market Intelligence живёт в изолированном Docker Compose рядом с основным приложением Villa Metrics. Отдельная база, отдельные контейнеры, отдельный деплой. Причина простая: скрейпинг — это нестабильная штука. Парсер упал, прокси заблокировали, Airbnb поменял API — основное приложение не должно от этого страдать.

Django-приложение с моделями: District (районы Бали), MarketProperty (объекты с платформ), DailyRate (цены по дням), BaliEvent (события на острове), SchoolHoliday (каникулы по странам). На каждый объект — 21 поле данных: от цены за ночь до рейтинга, количества отзывов и координат.

Три парсера — три подхода

Airbnb. Начал с HTML-скрейпинга. Сработало ровно один раз — потом разметка поменялась. Переключился на Airbnb Calendar API — дёргаешь календарь доступности и получаешь цены по дням. Через неделю API устарел. Третья попытка — grid search: запрос по координатам с radius, парсинг JSON-ответа поисковой выдачи. Это работает стабильно, потому что поисковый API Airbnb не может просто так сломать — им самим нужен.

Booking.com и Agoda. JavaScript-rendered страницы. Обычным requests не вытащишь — контент генерируется на клиенте. Поднял Playwright, headless Chromium. Загрузка страницы, ожидание рендеринга, парсинг DOM. Медленнее, но надёжнее, чем пытаться реверс-инжинирить их внутренние API.

Прокси-ротация: два провайдера за три дня

Начал с GonzoProxy. Дешёвый, но процент заблокированных запросов на Airbnb — около 40%. Перешёл на Geonode — резидентные прокси, success rate вырос до 92%. Стоит дороже, но один успешный запрос дешевле трёх неудачных.

Ротация реализована на уровне middleware: каждый запрос получает случайный прокси из пула. Если прокси возвращает 403 или таймаут — помечается как мёртвый на 10 минут и выбирается следующий.

Оптимизации скорости

Playwright с полной загрузкой страницы — это секунд 5-8 на запрос. Умножаем на тысячи объектов — ждать неделю. Поэтому оптимизации:

  • Блокировка трафика. Отключил загрузку картинок, шрифтов, трекинг-скриптов. Страница Booking.com тянет 3-4 МБ медиа — без них грузится за 1.5 секунды вместо 6.
  • Комбинирование запросов. Один поисковый запрос к Airbnb возвращает 18-20 объектов. Вместо парсинга каждого объекта отдельно — собираю данные из поисковой выдачи.
  • Сохранение кеша. Browser context переиспользуется между запросами — cookies и localStorage остаются, не нужна повторная авторизация.
  • Управление памятью. Playwright съедает память. Перезапуск browser context каждые 50 запросов. Garbage collection между батчами.

ScrapeJob модель отслеживает каждый запуск: время старта, количество собранных объектов, ошибки, использованные прокси. Если парсер упал на середине — следующий запуск продолжает с того же места.

Фронтенд: три экрана

Market Dashboard. Общая картина рынка: средние цены по районам, количество объектов, тренды за последние 30/60/90 дней. Графики с маркерами событий — видно, как цены растут перед Новым годом или Nyepi.

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

Property Detail. Карточка объекта: фото, цены, календарь занятости, история изменений цены, рейтинг, отзывы. Прямые ссылки на оригинал на Airbnb/Booking/Agoda.

Результат

~105 коммитов за 3 дня. Market Intelligence работает как отдельный сервис: три парсера собирают данные с Airbnb, Booking.com и Agoda. 21 поле на каждый объект. Прокси-ротация через Geonode. ScrapeJob для трекинга.

Первый полный скан Чангу: 847 объектов, 12 часов работы парсеров. Второй скан (с оптимизациями) — те же 847 объектов за 3.5 часа. Данные есть. Теперь нужно превратить их в аналитику и рекомендации по ценам — но это следующий пост.