spb/lou-ka Public
Lou·Ka — tous les logements à louer du Québec, un seul endroit.
HTML 99.7%
1# -----------------------------------------------------------------------------2# Lou-Ka — Agrégateur de logements à louer (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"[lou-ka] connecteur inconnu : {sid}", file=sys.stderr)26 continue27 t0 = time.time()28 print(f"[lou-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"[lou-ka] ⚠ ALERTE {sid} : {stats['alert']}")43 print(f"[lou-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 rafraîchissement périodique (pseudo-webhook par sondage)."""55 while True:56 run()57 try: # géocoder les nouvelles adresses (cache : quasi gratuit en régime stable)58 from . import geocode59 geocode.run(limit=120)60 except Exception as exc:61 print(f"[lou-ka] geocode: erreur non bloquante: {exc}", file=sys.stderr)62 try: # commodités de proximité des nouveaux immeubles (cache aussi)63 from . import poi64 poi.run(limit=80)65 except Exception as exc:66 print(f"[lou-ka] poi: erreur non bloquante: {exc}", file=sys.stderr)67 try: # aire de diffusion (stats de quartier) des nouvelles annonces68 from . import quartier69 quartier.enrich()70 except Exception as exc:71 print(f"[lou-ka] quartier: erreur non bloquante: {exc}", file=sys.stderr)72 print(f"[lou-ka] prochaine synchronisation dans {interval_seconds}s")73 time.sleep(interval_seconds)747576if __name__ == "__main__":77 run(sys.argv[1:] or None)78