SPB Git

spb/lou-ka Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

HTML 99.7%
3.0 KB · 78 lines python
Raw Blame History
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