91 lines
6.3 KiB
Markdown
91 lines
6.3 KiB
Markdown
# Журнал сессии (2026-05-25)
|
||
|
||
## Что построили
|
||
|
||
Внутренний мониторинг цен конкурентов на propertyfinder.ae и bayut.com для HOME LIGA REAL ESTATE.
|
||
|
||
**Стек:** FastAPI + Jinja2 (Bootstrap 5) + SQLAlchemy/SQLite + APScheduler + python-telegram-bot + httpx/BS4.
|
||
|
||
**Три процесса** (каждый — свой .bat-лаунчер):
|
||
- `run_web.bat` — веб-UI на http://127.0.0.1:8000
|
||
- `run_bot.bat` — Telegram-бот (polling)
|
||
- `run_scheduler.bat` — фоновый сканер каждые `SCRAPE_INTERVAL_HOURS` часов
|
||
|
||
## Эволюция архитектуры
|
||
|
||
### Первая попытка (отвергнута)
|
||
**Идея:** сотрудник вводит DLD Permit Number своего объекта → система автоматически ищет «то же permit» на PF и Bayut → находит объявления конкурентов.
|
||
|
||
**Почему не сработало:**
|
||
1. В Дубае **каждый брокер получает свой permit на свою публикацию**. Два брокера, рекламирующих одну квартиру = два разных permit. Permit не идентифицирует физический объект — он идентифицирует конкретное объявление конкретного брокера.
|
||
2. PF на странице объявления показывает permit **картинкой** через сервис верификации, не plain text (anti-scraping).
|
||
3. PF search `?q=<permit>` — free-text по названию/описанию, не структурированный фильтр.
|
||
|
||
### Финальная архитектура
|
||
**Manual URL list + опциональные подсказки:**
|
||
1. Сотрудник создаёт проект (название, тип сделки, владелец, опц. building/bedrooms/sqft).
|
||
2. На странице проекта **вручную вставляет URL** объявления конкурента → система делает single-page fetch, парсит `__NEXT_DATA__`, добавляет в трекинг.
|
||
3. Если указано здание — кнопка «🔍 Подобрать похожие» ищет на PF/Bayut по `building + bedrooms` и предлагает кандидатов с кнопкой «+ Отслеживать».
|
||
4. Каждые 4 часа фоновый сканер делает refetch каждого отслеживаемого URL → детектит:
|
||
- 📈📉 изменение цены
|
||
- ❌ удаление (URL отдаёт 404)
|
||
- ♻️ возвращение из удалённого статуса
|
||
5. Уведомления — в Telegram личкой владельцу проекта.
|
||
|
||
## Модель данных
|
||
|
||
- `Employee` — name, tg_chat_id (опц.), tg_username
|
||
- `Project` — title, deal_type, owner_id, our_price, building, bedrooms, size_sqft, our_url, dld_permit (все после `owner` — опционально)
|
||
- `CompetitorListing` — source (PF|Bayut), external_id, url, current_price, status (active|removed), agent_name, agency_name, first_seen, last_seen
|
||
- `PriceHistory` — listing_id, price, recorded_at
|
||
|
||
## Как подключиться сотруднику
|
||
|
||
1. В TG найти бота → отправить `/start`.
|
||
2. Отправить `/whoami` → бот пришлёт chat_id.
|
||
3. В вебе http://127.0.0.1:8000/employees → найти/создать запись → вставить chat_id → Сохранить.
|
||
|
||
## Известные ограничения
|
||
|
||
- **PF/Bayut могут блокировать** при частых запросах (видно как `Blocked by site (403/429)` в логах). Решение — увеличить интервал; если уже не помогает — добавить Playwright fallback.
|
||
- **Подсказки эвристические**: ищем по совпадению building name в title + bedrooms-фильтр. Могут попасть «другие квартиры в том же здании» — поэтому добавление в трекинг через ручное подтверждение.
|
||
- **Permit как plain text** на PF не отдаётся. Если когда-нибудь понадобится — нужен OCR на verification-image.
|
||
|
||
## Что в .env
|
||
|
||
```
|
||
TG_BOT_TOKEN=<токен от @BotFather>
|
||
SCRAPE_INTERVAL_HOURS=4
|
||
ADMIN_CHAT_ID= # опц.
|
||
```
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
DLD Permit Number/
|
||
├── run_web.bat, run_bot.bat, run_scheduler.bat
|
||
├── run_web.py
|
||
├── requirements.txt
|
||
├── .env (не в git — содержит токен)
|
||
├── data/monitor.db (создаётся автоматически)
|
||
├── app/
|
||
│ ├── config.py ← settings + резолвит относительные SQLite-пути в абсолютные
|
||
│ ├── db.py, models.py
|
||
│ ├── web.py ← FastAPI: CRUD проектов, /listings add/delete, /suggest
|
||
│ ├── bot.py ← /start, /whoami, /list, /check
|
||
│ ├── scheduler.py
|
||
│ ├── scrapers/{base,propertyfinder,bayut}.py
|
||
│ ├── services/{monitor,notifier}.py
|
||
│ └── templates/ ← projects_list, project_form, project_detail, suggest, employees, base
|
||
```
|
||
|
||
## Что протестировать в первую очередь
|
||
|
||
1. Удалить старый `data/monitor.db` (схема изменилась).
|
||
2. Запустить три .bat файла.
|
||
3. `/start` боту → `/whoami` → chat_id → вписать в Сотрудники.
|
||
4. Создать тестовый проект (Aykon City Tower B, 2BR).
|
||
5. Вставить URL реального объявления конкурента → проверить, что добавилось с ценой/брокером.
|
||
6. Жмякнуть «Подобрать похожие» → посмотреть кандидатов.
|
||
7. Жмякнуть «Проверить сейчас» → если цена не менялась, изменений не будет (это нормально); для теста алертов можно поменять цену в БД руками или подождать реального изменения.
|