Lou·Ka — tous les logements à louer du Québec, un seul endroit.
HTML 98.9%
Python 0.6%
1# -----------------------------------------------------------------------------2# Lou-Ka — Agrégateur de logements à louer (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# connectors/place_barrage.py : connecteur Place du Barrage (placedubarrage.com)5# Immeuble locatif au 2, rue Vertu à Windsor (Estrie), géré par Sphère6# immobilier. Site Wix rendu serveur : la page /appartements liste 24 cartes7# (répéteur Wix « wixui-repeater__item ») — « Appartement 101-A », courte8# description, prix (« 1475$ ») ou « LOUÉ », lien vers la fiche9# /appartements/appartement-<no>-<lettre>. ⚠️ Le <title> du gabarit Wix10# mentionne un autre projet (Le Connaught) : ignorer. On dérive l'URL de la11# fiche du numéro affiché sur la carte (les hrefs peuvent être désalignés).12# Granularité : unité ; prix affichés, typologies non publiées.13# -----------------------------------------------------------------------------14from __future__ import annotations1516import re1718from bs4 import BeautifulSoup1920from .base import BaseConnector21from ..schema import Listing2223BASE = "https://www.placedubarrage.com"24LIST_URL = f"{BASE}/appartements"2526ADDRESS = "2, rue Vertu, Windsor"27CITY = "Windsor"2829UNIT_RE = re.compile(r"^Appartement\s+(\d{3})-([A-F])$", re.I)30PRICE_RE = re.compile(r"^(\d{3,4})\s*\$$")31IMG_RE = re.compile(r'https://static\.wixstatic\.com/media/'32 r'[^"\s\\)]+\.(?:jpe?g|png|webp)[^"\s\\)]*', re.I)3334FLOOR_BY_DIGIT = {"1": "Étage 1", "2": "Étage 2", "3": "Étage 3"}353637class PlaceBarrageConnector(BaseConnector):38 source_id = "place_barrage"39 request_delay = 0.64041 def fetch(self) -> list[Listing]:42 listings: list[Listing] = []43 try:44 html = self.get(LIST_URL).text45 except Exception:46 return listings47 soup = BeautifulSoup(html, "html.parser")4849 for item in soup.select("div.wixui-repeater__item"):50 try:51 text_lines = [t.strip() for t in52 item.get_text("\n", strip=True).split("\n")]53 unit_no, letter = "", ""54 for t in text_lines:55 m = UNIT_RE.match(t)56 if m:57 unit_no, letter = m.group(1), m.group(2).upper()58 break59 if not unit_no:60 continue61 if any(re.search(r"^lou[ée]$", t, re.I) for t in text_lines):62 continue # déjà loué63 price = None64 for t in text_lines:65 mp = PRICE_RE.match(t)66 if mp:67 price = float(mp.group(1))68 break69 if price is None:70 continue # ni prix ni LOUÉ : statut inconnu7172 description = next(73 (t for t in text_lines74 if t.lower().startswith("appartement situé")), "")7576 images = [u.split("/v1/")[0] for u in77 dict.fromkeys(IMG_RE.findall(str(item)))][:15]7879 # ⚠️ hrefs Wix désalignés (la carte 302-E pointe vers la fiche80 # 302-a…) et seules les fiches -a/-b/-f existent : on ne garde81 # la fiche que si sa lettre correspond à celle de la carte,82 # sinon l'URL de l'annonce est la page liste.83 url = LIST_URL84 a = item.select_one('a[href*="/appartements/appartement-"]')85 if a and a.get("href", "").rstrip("/").endswith(86 f"-{unit_no}-{letter.lower()}"):87 url = a["href"].rstrip("/")88 ext_id = f"{unit_no}-{letter}".lower()89 if any(l.external_id == ext_id for l in listings):90 continue91 listings.append(Listing(92 source=self.source_id,93 external_id=ext_id,94 url=url,95 title=f"Appartement {unit_no}-{letter} — "96 f"Place du Barrage",97 address=ADDRESS,98 city=CITY,99 price=price,100 availability="Disponible",101 description=description,102 details={"floor": FLOOR_BY_DIGIT.get(unit_no[0], "")},103 images=images,104 ))105 except Exception:106 continue107 return listings108