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
2 days agolast push
HTML 98.9% Python 0.6%

[ka2] fix connecteur location_saguenay: retry (3 essais, espacés par le throttling 10 s) de la page liste — une page 200 servie sans le menu « Logements disponibles » (raté transitoire, vu 2026-08-29 03:47) produisait un faux « 0 trouvé ok »; après 3 essais infructueux le connecteur lève une erreur franche au lieu d'un zéro silencieux. Testé: 21 annonces (= médiane 21)

Simon-Pierre Boucher committed 27 days ago (Aug 29, 2026) parent 0112164

1 changed file +24 −15

modified louka/connectors/location_saguenay.py +24 −15
@@ -37,22 +37,19 @@ class LocationSaguenayConnector(BaseConnector):
37 37 max_details = 12 # garde-fou fiches détail (vraies requêtes par sync)
38 38
39 39 def fetch(self) -> list[Listing]:
40 − html = self.get(LIST_URL).text
41 − soup = BeautifulSoup(html, "html.parser")
42 −
43 − menu = soup.select_one("ul.blog-menu")
44 − if menu is None:
45 − return []
46 −
47 − # entrée « Logements disponibles » du menu principal
48 − root = None
49 − for li in menu.find_all("li", recursive=False):
50 − a = li.find("a", recursive=False)
51 − if a and "logements disponibles" in a.get_text(strip=True).lower():
52 − root = li.find("ul", class_="sub-menu")
40 + # Un raté transitoire (page 200 sans le menu « Logements disponibles »,
41 + # vu 2026-08-29) produisait un faux « 0 trouvé ok » : retry court, puis
42 + # erreur franche plutôt qu'un zéro silencieux. Le throttling de get()
43 + # (10 s) espace naturellement les essais.
44 + for _ in range(3):
45 + html = self.get(LIST_URL).text
46 + soup = BeautifulSoup(html, "html.parser")
47 + root = self._find_menu_root(soup)
48 + if root is not None:
53 49 break
54 − if root is None:
55 − return []
50 + else:
51 + raise RuntimeError(
52 + "menu « Logements disponibles » introuvable après 3 essais")
56 53
57 54 self._fetched = 0
58 55 listings: dict[str, Listing] = {}
@@ -72,6 +69,18 @@ class LocationSaguenayConnector(BaseConnector):
72 69 continue
73 70 return list(listings.values())
74 71
72 + @staticmethod
73 + def _find_menu_root(soup: BeautifulSoup):
74 + """Sous-menu de l'entrée « Logements disponibles » du menu principal."""
75 + menu = soup.select_one("ul.blog-menu")
76 + if menu is None:
77 + return None
78 + for li in menu.find_all("li", recursive=False):
79 + a = li.find("a", recursive=False)
80 + if a and "logements disponibles" in a.get_text(strip=True).lower():
81 + return li.find("ul", class_="sub-menu")
82 + return None
83 +
75 84 # -- entrée du menu (une fiche WP par immeuble/type) -------------------------------
76 85 def _parse_entry(self, a, bedrooms: str,
77 86 listings: dict[str, Listing]) -> None:
78 87