spb/immo-ka Public
Immo-Ka — agrégateur des propriétés à vendre au Québec (73 connecteurs, ~40 000 annonces, React+FastAPI)
Python 64%
TypeScript 21.1%
CSS 14.3%
HTML 0.6%
1# -----------------------------------------------------------------------------2# Immo-Ka — Agrégateur de maisons à vendre (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# ingest.py : pipeline d'ingestion — exécute les connecteurs et synchronise5# la base (ajouts / mises à jour / retraits) = contenu toujours à jour6# -----------------------------------------------------------------------------7from __future__ import annotations89import sys10import time11import traceback1213from . import db14from .connectors import CONNECTORS151617def run(sources: list[str] | None = None) -> list[dict]:18 """Exécute l'ingestion pour toutes les sources (ou celles demandées)."""19 con = db.connect()20 results = []21 targets = sources or list(CONNECTORS.keys())22 for sid in targets:23 cls = CONNECTORS.get(sid)24 if cls is None:25 print(f"[immo-ka] connecteur inconnu : {sid}", file=sys.stderr)26 continue27 t0 = time.time()28 print(f"[immo-ka] sync {sid} ...")29 try:30 listings = cls().fetch()31 finalized, dropped = [], 032 for lst in listings:33 try:34 finalized.append(lst.finalize())35 except Exception: # une annonce malformée ne bloque pas la source36 dropped += 137 stats = db.sync_source(con, sid, finalized)38 stats["seconds"] = round(time.time() - t0, 1)39 if dropped:40 stats["dropped"] = dropped41 if stats.get("alert"):42 print(f"[immo-ka] ⚠ ALERTE {sid} : {stats['alert']}")43 print(f"[immo-ka] {stats}")44 results.append(stats)45 except Exception as exc: # robustesse : une source ne bloque pas les autres46 db.log_failure(con, sid, f"{exc}")47 traceback.print_exc()48 results.append({"source": sid, "error": str(exc)})49 con.close()50 return results515253def watch(interval_seconds: int = 3600) -> None:54 """Boucle de synchronisation périodique (équivalent webhook, via PM2/cron)."""55 while True:56 run()57 print(f"[immo-ka] prochaine synchronisation dans {interval_seconds // 60} min")58 time.sleep(interval_seconds)59