Add CLAUDE.md project documentation for session context
Provides automatic context loading for new Claude Code sessions, documenting architecture, filters, sources, and conventions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
124
CLAUDE.md
Normal file
124
CLAUDE.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
# Maru hledá byt
|
||||||
|
|
||||||
|
Projekt pro hledání bytů v Praze. Scrapuje inzeráty ze 7 realitních portálů, filtruje, deduplikuje a generuje interaktivní mapu.
|
||||||
|
|
||||||
|
**Jazyk komunikace:** Čeština (uživatelka Marie). Kód a komentáře v kódu jsou mix CZ/EN.
|
||||||
|
|
||||||
|
## Architektura
|
||||||
|
|
||||||
|
```
|
||||||
|
run_all.sh (orchestrátor)
|
||||||
|
├─ scrape_and_map.py → byty_sreality.json (Sreality API)
|
||||||
|
├─ scrape_bezrealitky.py → byty_bezrealitky.json (HTML Apollo cache)
|
||||||
|
├─ scrape_idnes.py → byty_idnes.json (HTML regex)
|
||||||
|
├─ scrape_psn.py } → byty_psn.json (React API + curl)
|
||||||
|
├─ scrape_cityhome.py } → byty_cityhome.json (HTML tabulky)
|
||||||
|
├─ scrape_bazos.py → byty_bazos.json (HTML regex)
|
||||||
|
└─ scrape_realingo.py → byty_realingo.json (Next.js __NEXT_DATA__)
|
||||||
|
↓
|
||||||
|
merge_and_map.py
|
||||||
|
├─ byty_merged.json (deduplikovaná data)
|
||||||
|
└─ mapa_bytu.html (Leaflet.js mapa)
|
||||||
|
↓
|
||||||
|
generate_status.py → status.json + scraper_history.json
|
||||||
|
↓
|
||||||
|
server.py (port 8080) → servíruje mapu + status page + ratings API
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filtry (společné všem scraperům)
|
||||||
|
|
||||||
|
| Parametr | Hodnota | Poznámka |
|
||||||
|
|----------|---------|----------|
|
||||||
|
| Max cena | 13.5M Kč (Sreality/Realingo/Bezrealitky/iDNES), 14M Kč (PSN/CityHome/Bazoš) | Rozdíl je záměrný |
|
||||||
|
| Min plocha | 69 m² | |
|
||||||
|
| Min patro | 2. NP | 2. NP se na mapě označí varováním |
|
||||||
|
| Dispozice | 3+kk, 3+1, 4+kk, 4+1, 5+kk, 5+1, 6+ | |
|
||||||
|
| Region | Praha | |
|
||||||
|
| Vyloučit | panelové domy, sídliště | regex v popisu/polích |
|
||||||
|
|
||||||
|
## Klíčové soubory
|
||||||
|
|
||||||
|
- **scrape_and_map.py** — Sreality scraper + `generate_map()` funkce (sdílená, generuje HTML mapu)
|
||||||
|
- **merge_and_map.py** — sloučí 7 JSON zdrojů, deduplikuje (klíč: ulice + cena + plocha), volá `generate_map()`
|
||||||
|
- **scraper_stats.py** — utility: `validate_listing()` (validace povinných polí + GPS bounds) a `write_stats()`
|
||||||
|
- **generate_status.py** — generuje status.json a scraper_history.json z výstupů scraperů
|
||||||
|
- **server.py** — HTTP server (port 8080), endpointy: `/mapa_bytu.html`, `/scrapers-status`, `/api/ratings`, `/api/status`
|
||||||
|
- **run_all.sh** — orchestrátor, spouští scrapery postupně (PSN+CityHome paralelně), pak merge + status
|
||||||
|
|
||||||
|
## Mapa (mapa_bytu.html)
|
||||||
|
|
||||||
|
- Leaflet.js + CARTO tiles
|
||||||
|
- Barvy markerů podle ceny/m² (modrá < 110k → červená > 165k, šedá = neuvedeno)
|
||||||
|
- PSN/CityHome = srdíčkové markery (❤️)
|
||||||
|
- Nové inzeráty (≤ 1 den) = žlutý badge "NEW"
|
||||||
|
- Zamítnuté = zprůhledněné + 🚫 SVG overlay
|
||||||
|
- Oblíbené = hvězdička (⭐)
|
||||||
|
- Filtry: patro, max cena (input, default 13.5M, max 14M), datum přidání, skrýt zamítnuté, klik na cenový pás
|
||||||
|
- Ratings uložené v localStorage + sync na server `/api/ratings`
|
||||||
|
|
||||||
|
## Barvy zdrojů na mapě
|
||||||
|
|
||||||
|
```python
|
||||||
|
source_colors = {
|
||||||
|
"sreality": "#1976D2", # modrá
|
||||||
|
"realingo": "#00897B", # teal
|
||||||
|
"bezrealitky": "#E91E63", # růžová
|
||||||
|
"idnes": "#FF6F00", # oranžová
|
||||||
|
"psn": "#D32F2F", # červená
|
||||||
|
"cityhome": "#D32F2F", # červená
|
||||||
|
"bazos": "#7B1FA2", # fialová
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deduplikace (merge_and_map.py)
|
||||||
|
|
||||||
|
- Klíč: `normalize_street(locality) + price + area`
|
||||||
|
- Normalizace ulice: první část před čárkou, lowercase, odstranění diakritiky, jen alfanumerické znaky
|
||||||
|
- PSN a CityHome mají prioritu (načtou se první)
|
||||||
|
|
||||||
|
## Vývoj
|
||||||
|
|
||||||
|
- **Git remote:** `https://gitea.home.hrajfrisbee.cz/littlemeat/maru-hleda-byt.git`
|
||||||
|
- **Gitea API token:** uložen v `.claude/settings.local.json`
|
||||||
|
- **Python 3.9+** kompatibilita (`from __future__ import annotations`)
|
||||||
|
- **Žádné pip závislosti** — jen stdlib (urllib, json, re, logging, pathlib, subprocess)
|
||||||
|
- **Docker:** `build/Dockerfile` (python:3.13-alpine), cron každé 4 hodiny
|
||||||
|
- Generované soubory (`byty_*.json`, `mapa_bytu.html`, `*.log`) jsou v `.gitignore`
|
||||||
|
|
||||||
|
## Typické úlohy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rychlý test scraperu
|
||||||
|
python3 scrape_bazos.py --max-pages 1 --max-properties 5 --log-level DEBUG
|
||||||
|
|
||||||
|
# Lokální validace (všechny scrapery s limity)
|
||||||
|
make validation-local
|
||||||
|
|
||||||
|
# Vygenerovat mapu z existujících dat
|
||||||
|
python3 merge_and_map.py
|
||||||
|
|
||||||
|
# Spustit server
|
||||||
|
python3 server.py # nebo: make serve
|
||||||
|
|
||||||
|
# Plný scrape
|
||||||
|
./run_all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pořadí scraperů v run_all.sh
|
||||||
|
|
||||||
|
1. Sreality
|
||||||
|
2. Bezrealitky
|
||||||
|
3. iDNES
|
||||||
|
4. PSN + CityHome (paralelně)
|
||||||
|
5. Bazoš
|
||||||
|
6. Realingo (poslední — uživatelka ho nemá ráda)
|
||||||
|
7. Merge + mapa
|
||||||
|
8. Status generování
|
||||||
|
|
||||||
|
## Konvence
|
||||||
|
|
||||||
|
- Commit messages v angličtině, PR popis v angličtině
|
||||||
|
- Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||||
|
- PRy přes Gitea API (viz create_pr.sh pattern v historii)
|
||||||
|
- Nové scrapery kopírují vzor z `scrape_bezrealitky.py`
|
||||||
|
- Každý scraper má argparse s `--max-pages`, `--max-properties`, `--log-level`
|
||||||
Reference in New Issue
Block a user