SPB Git forge

spb/lou-ka

Public

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

232commits 1branches 0releases
172.9 MBsize
maindefault branch
3 days agolast push
HTML 98.9% Python 0.6%

Revert "[ka2] fix connecteur vision_immo: échec honnête au lieu d'un « 0 trouvé ok » qui a déjà dépublié les 6 annonces. Le sync du 2026-09-11 10:43 a rapporté found=0 ok=1 missed=6 (médiane 6, stale) : fetch() avalait toute exception sur la page liste (`except Exception: return []`) — un échec réseau transitoire devenait un succès à 0, invisible du disjoncteur. L'historique montre le coût réel : pendant la panne DNS systémique du 2026-09-10 (14:17 et 15:22), deux « 0 ok » silencieux ont abouti à removed=6 — les 6 annonces dépubliées puis re-publiées au sync suivant. Reproduit en live : la source est SAINE (page 200, 177 Ko, 6 liens /logements/), seul le silence sur erreur était fautif — même situation que thrace e5379b0 et novelo 6bf26bd, distinct du cas lienard (rollback d1571fc, source en panne). Fix : (1) fetch() laisse remonter les exceptions réseau (ingest journalise ok=0) et lève RuntimeError si 0 lien parsé ET formulaire de filtres Search & Filter absent (rendu partiel/refonte) — un vrai zéro (0 lien mais squelette présent) reste possible car la page ne liste que les unités offertes ; (2) _parse_detail() ne retourne plus {} sur exception : detail() aurait mis ce {} en cache PERMANENT (clé figée « v1 », jamais invalidée) et l'unité aurait disparu pour toujours — vérifié : cache actuel sain, 7 payloads complets. Testé : fetch() venv → 6 annonces (4½ Terrebonne 1 720 $, 4½ Lachine 1 995 $, 3½ St-Henri 1 395 $, 4½ J180 2 195 $, 5½ 2 395 $, 6½ 2 695 $), run.py sync vision_immo → found=6 ok, pm2 restart lou-ka-sync, site :8095 → 200."

This reverts commit 602ff085f8e5b57320fc15852598d73d6a057a76.
Simon-Pierre Boucher committed 14 days ago (Sep 11, 2026) parent 602ff08

1 changed file +8 −15

modified louka/connectors/vision_immo.py +8 −15
@@ -41,10 +41,10 @@ class VisionImmoConnector(BaseConnector):
41 41 request_delay = 0.7
42 42
43 43 def _parse_detail(self, url: str) -> dict:
44 − # pas de try/except : un échec réseau doit remonter (ok=0), pas être
45 − # caché — detail() mettrait le {} en cache permanent (clé figée « v1 »)
46 − # et l'unité disparaîtrait pour toujours
47 − html = self.get(url).text
44 + try:
45 + html = self.get(url).text
46 + except Exception:
47 + return {}
48 48 soup = BeautifulSoup(html, "html.parser")
49 49 payload: dict = {}
50 50
@@ -127,19 +127,12 @@ class VisionImmoConnector(BaseConnector):
127 127 return payload
128 128
129 129 def fetch(self) -> list[Listing]:
130 − # échec HONNÊTE : pas de try/except — une erreur réseau doit remonter
131 − # (ok=0 dans sync_log) et non devenir un « 0 trouvé ok » qui dépublie
132 − # les annonces (vu les 2026-09-10 15:22 removed=6 et 2026-09-11 10:43)
133 130 listings: list[Listing] = []
134 − html = self.get(LIST_URL).text
131 + try:
132 + html = self.get(LIST_URL).text
133 + except Exception:
134 + return listings
135 135 links = list(dict.fromkeys(LINK_RE.findall(html)))
136 − # 0 lien peut être un VRAI zéro (la page ne liste que les unités
137 − # offertes) : on ne lève que si le squelette de la page saine manque
138 − # aussi (formulaire de filtres Search & Filter → rendu partiel/refonte)
139 − if not links and "sf-field-post-meta-prix" not in html:
140 − raise RuntimeError(
141 − "visionimmo.com : aucun lien /logements/ et formulaire de "
142 − "filtres absent (rendu partiel ou page restructurée)")
143 136 for url, slug in links:
144 137 payload = self.detail(slug, "v1",
145 138 lambda u=url: self._parse_detail(u))
146 139