# DLD Monitor Внутренний инструмент для агентства недвижимости в Дубае: мониторит цены объявлений конкурентов на **PropertyFinder.ae** и **Bayut.com** по DLD Permit Number, шлёт уведомления в Telegram при: - 📈📉 изменении цены конкурента, - ❌ удалении объявления (404 / withdrawn), - 🆕 появлении нового объявления с тем же permit (новый брокер выставил ту же квартиру). ## Архитектура ``` ┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Web UI │ │ Scheduler │ │ Telegram Bot │ │ (FastAPI) │ │ (APScheduler) │ │ (polling) │ │ add project │ │ every N hours │ │ /start /check │ └──────┬───────┘ └────────┬─────────┘ └────────┬────────┘ │ │ │ └──────────────┬──────┴───────────────────────┘ ▼ ┌────────────────┐ │ monitor │ │ service │ ← скрапит PF и Bayut, пишет в SQLite └────────────────┘ │ ▼ уведомления в TG конкретному employee ``` ## Локальный запуск (Windows) ### 1. Создать виртуальное окружение и поставить зависимости ```powershell python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt ``` ### 2. Получить токен Telegram-бота Уже есть? Отлично. Если нет: 1. Откройте Telegram, найдите [@BotFather](https://t.me/BotFather). 2. Отправьте `/newbot`, придумайте имя. 3. Скопируйте токен вида `123456:ABC-DEF…`. ### 3. Создать `.env` ```powershell Copy-Item .env.example .env notepad .env ``` В `.env` вставьте: ``` TG_BOT_TOKEN=ваш_токен_от_botfather SCRAPE_INTERVAL_HOURS=4 ADMIN_CHAT_ID= # опционально — куда слать системные ошибки ``` ### 4. Запустить три процесса (в **трёх** разных окнах PowerShell) **Окно 1 — веб-интерфейс:** ```powershell .\.venv\Scripts\Activate.ps1 python run_web.py ``` Откройте http://127.0.0.1:8000 **Окно 2 — Telegram-бот:** ```powershell .\.venv\Scripts\Activate.ps1 python -m app.bot ``` **Окно 3 — фоновый сканер:** ```powershell .\.venv\Scripts\Activate.ps1 python -m app.scheduler ``` ## Первое использование 1. Откройте бота в Telegram и отправьте `/start` — он зарегистрирует ваш `chat_id`. 2. В веб-UI перейдите в **Сотрудники** — убедитесь, что вы там есть с ✓ TG. 3. Нажмите **+ Новый проект**, заполните: - Название (например: «Marina Pinnacle 1502, 2BR») - DLD Permit Number (Trakheesi) - Тип сделки (продажа/аренда) - Владелец = вы 4. На странице проекта нажмите **Проверить сейчас** — система найдёт все объявления конкурентов с этим permit на PF и Bayut. 5. Дальше фоновый сканер сам будет проверять каждые `SCRAPE_INTERVAL_HOURS` часов и слать уведомления в Telegram. ## Команды бота - `/start` — подключить себя как сотрудника (запоминает chat_id) - `/list` — список ваших проектов - `/check` — запустить проверку всех ваших проектов сейчас - `/whoami` — показать свой chat_id ## Структура ``` app/ ├── config.py настройки из .env ├── db.py SQLAlchemy engine + session ├── models.py Employee, Project, CompetitorListing, PriceHistory ├── web.py FastAPI роуты и UI ├── bot.py Telegram-бот ├── scheduler.py APScheduler фоновый сканер ├── scrapers/ │ ├── base.py httpx + парсинг __NEXT_DATA__ │ ├── propertyfinder.py │ └── bayut.py ├── services/ │ ├── monitor.py детект изменений, основная бизнес-логика │ └── notifier.py отправка в TG └── templates/ Jinja2 (Bootstrap 5) data/ └── monitor.db SQLite (создаётся автоматически) ``` ## Перенос на сервер Когда придёт время — нужно: 1. Поставить Python 3.11+ на сервер (Linux). 2. Скопировать репозиторий, `pip install -r requirements.txt`. 3. Создать `.env`. 4. Поставить три процесса под `systemd`: - `dld-monitor-web.service` → `python run_web.py` - `dld-monitor-bot.service` → `python -m app.bot` - `dld-monitor-scheduler.service` → `python -m app.scheduler` 5. Поставить nginx + TLS перед веб-портом (8000). ## Возможные проблемы скрапинга PF/Bayut могут начать блокировать запросы при частых обращениях. Признаки: - В логах сканера видны `Blocked by site (403/429)`. - Поиск возвращает 0 объявлений, хотя они должны быть. Что делать: 1. Уменьшите `SCRAPE_INTERVAL_HOURS` (реже = меньше риска). 2. Если не помогает — добавьте Playwright (headless-браузер). Заготовка: `pip install playwright && playwright install chromium`, затем заменить `fetch_html` на запуск через Playwright. 3. Опционально — прокси.