Providers de taux hypothécaires
Un connecteur indépendant par institution. Auto-découverte : tout module du
dossier définissant une sous-classe de RateProvider avec un provider_id
non vide est enregistré dans PROVIDERS automatiquement (aucun registre à
éditer). La panne d'un provider n'affecte jamais les autres.
Règle absolue : aucun taux inventé. Un produit non confirmé sur la page officielle est simplement omis — jamais deviné, jamais de valeur par défaut.
Ajouter une institution (8 étapes)
-
Créer
<slug>.pydans ce dossier, avec une sous-classe deRateProvider:pythonfrom .base import RateProvider class MaBanque(RateProvider): provider_id = "ma_banque" # slug stable (clé BD) institution = "Ma Banque" # nom d'affichage fr-CA source_url = "https://mabanque.ca/taux-hypothecaires" def fetch(self) -> list[dict]: html = self.get(self.source_url).text # ou .json() return self.parse(html) def parse(self, html: str) -> list[dict]: ... # → [self.make_product(...), ...]Séparer
fetch()(réseau) deparse()(pur) : les tests appellentparse()sur des fixtures, sans réseau. -
Backend réseau :
self.get(url)(requests + politesserequest_delay) d'abord ;self.get_scrapfly(url, render_js=True)en dernier recours seulement si le site bloque (403/JS requis). -
Normaliser chaque produit via
self.make_product(...):rate_type:fixed/variable— ouotherpour tout taux préférentiel/prime/référence (avecpurpose="unknown"), afin qu'il ne tombe jamais dans un classement « meilleur taux d'achat » ;kind:posted(affiché) ouspecial(offre spéciale) — ne jamais confondre ;insured_status:insured/insurable/uninsured, ouunknownsi la page ne le précise pas — ne pas deviner ;product_nameen français, explicite (ex. « Fixe fermé 5 ans ») ;apr(TAP) seulement s'il est publié.
-
Aucune écriture BD dans le provider : le scheduler valide (
validate_batch) puis enregistre (store.record_observations). Ne pas filtrer soi-même les aberrations — la validation s'en charge et journalise. -
Fixture : sauvegarder la réponse réelle (HTML/JSON) dans
tests/fixtures/mortgage/<slug>.<ext>(anonymisée si besoin, taille raisonnable — garder le bloc utile). -
Test : ajouter le slug dans
EXPECTEDdetests/test_mortgage_providers.py(fixture + nombre exact de produits) ; le test générique vérifie déjà validation propre,source_url,institutionet la règle « préférentiel → other/unknown ». Ajouter un test ciblé sur 1–2 valeurs connues de la fixture. -
Exécuter :
bashPYTHONPATH=. .venv/bin/python -P -m unittest tests.test_mortgage_providers .venv/bin/python run.py mortgage-sync ma_banque # collecte réelle .venv/bin/python run.py mortgage-status # santé -
Vérifier en BD/API :
GET /api/mortgage/rates?provider=ma_banque— provenance (source_url), fraîcheur et nature correctes. C'est tout : ni web.py, ni le scheduler, ni le frontend n'ont besoin d'être modifiés.
Pièges connus
4.19 % → 419: toujours vérifier l'échelle ; la validation rejette24 %, mais un « 41,9 » passerait — parser au bon endroit.
- Pages avec plusieurs onglets (assuré/non assuré) : étiqueter
insured_statuscorrectement plutôt que de tout mélanger. - Taux « ouverts » vs « fermés » : les distinguer dans
product_name(ex. BNC publie « Fixe ouvert 1 an » à 9,65 % — ce n'est pas une erreur). - Ne jamais soumettre de formulaire ni simuler une demande de prêt : pages publiques de taux uniquement.