SPB Git

spb/job-ka

Public

[ka6] fix connecteur stl_laval: garde-fou njoyn — une page liste vide/anti-bot (Scrapfly en échec renvoie "") ne passe plus pour un babillard à 0 offre; retente une fois puis lève une erreur (njoyn.py)

Simon-Pierre Boucher committed (Aug 26, 2026) parent 1953afc Browse files

1 changed file +21 −4

Unified Split
modified jobka/connectors/njoyn.py +21 −4
@@ -5,7 +5,7 @@
5 # Fichier : jobka/connectors/njoyn.py 5 # Fichier : jobka/connectors/njoyn.py
6 # Rôle : Classe de plateforme Njoyn (CGI) — très répandu au secteur public 6 # Rôle : Classe de plateforme Njoyn (CGI) — très répandu au secteur public
7 # québécois (santé, villes, sociétés d'État). HTML serveur + jeton. 7 # québécois (santé, villes, sociétés d'État). HTML serveur + jeton.
8−# Créé : 2026-08-18 Modifié : 2026-08-25 8+# Créé : 2026-08-18 Modifié : 2026-08-26
9 # ============================================================================= 9 # =============================================================================
10 """Plateforme Njoyn (CGI). 10 """Plateforme Njoyn (CGI).
11 11
@@ -27,6 +27,7 @@ import hashlib
27 import html as _html 27 import html as _html
28 import os 28 import os
29 import re 29 import re
30+import time
30 31
31 from ..schema import JobPosting, clean_html 32 from ..schema import JobPosting, clean_html
32 from .base import BaseConnector 33 from .base import BaseConnector
@@ -254,10 +255,26 @@ class NjoynConnector(BaseConnector):
254 it.get("fields", {}).get("villes et arrondissements") or "") 255 it.get("fields", {}).get("villes et arrondissements") or "")
255 return bool(place) and is_quebec_location(place.replace("-", " ")) 256 return bool(place) and is_quebec_location(place.replace("-", " "))
256 257
258+ def _fetch_listing(self) -> tuple[str, list[dict]]:
259+ """Page liste + items parsés, avec garde-fou : une réponse vide ou
260+ anti-bot (Scrapfly en échec renvoie "" — voir base.get_scrapfly) ne
261+ doit JAMAIS passer pour un babillard vide. Toute page Njoyn légitime,
262+ même sans offre, contient le formulaire xweb.asp — sinon on retente
263+ une fois puis on lève une erreur (sync en échec, pas « 0 trouvé »)."""
264+ for attempt in range(2):
265+ page = self._html(self._url("joblisting"))
266+ items = (self._parse_articles(page) or self._parse_table(page)
267+ or self._parse_rows(page))
268+ if items or re.search(r"xweb\.asp", page, re.I):
269+ return page, items
270+ if attempt == 0:
271+ time.sleep(10)
272+ raise RuntimeError(
273+ f"njoyn {self.source_id}: page liste illisible "
274+ f"(vide ou anti-bot, {len(page)} octets) — sync avorté")
275+
257 def fetch(self) -> list[JobPosting]: 276 def fetch(self) -> list[JobPosting]:
258− page = self._html(self._url("joblisting")) 277+ page, items = self._fetch_listing()
259− items = (self._parse_articles(page) or self._parse_table(page)
260− or self._parse_rows(page))
261 items = self._paginate(page, items) 278 items = self._paginate(page, items)
262 items = [it for it in items if self._keep(it)] 279 items = [it for it in items if self._keep(it)]
263 out: list[JobPosting] = [] 280 out: list[JobPosting] = []
264 281
Menu

Theme