SPB Git

spb/job-ka

Public

[ka6] snapshot pré-mission ocadogroup

Simon-Pierre Boucher committed (Aug 30, 2026) parent c7d9ece Browse files

1 changed file +18 −4

Unified Split
modified jobka/connectors/guichet_emplois.py +18 −4
@@ -6,7 +6,7 @@
6 # Rôle : Connecteur portail — Guichet-Emplois / Job Bank Canada (offres 6 # Rôle : Connecteur portail — Guichet-Emplois / Job Bank Canada (offres
7 # Québec, fenêtre glissante des N derniers jours). AGRÉGATEUR : 7 # Québec, fenêtre glissante des N derniers jours). AGRÉGATEUR :
8 # moins autoritaire qu'une page carrière (voir dedup.AGGREGATORS). 8 # moins autoritaire qu'une page carrière (voir dedup.AGGREGATORS).
9−# Créé : 2026-08-18 Modifié : 2026-08-18 9+# Créé : 2026-08-18 Modifié : 2026-08-30
10 # ============================================================================= 10 # =============================================================================
11 """Portail Guichet-Emplois (guichetemplois.gc.ca — gouvernement du Canada). 11 """Portail Guichet-Emplois (guichetemplois.gc.ca — gouvernement du Canada).
12 12
@@ -36,6 +36,9 @@ DAYS = os.environ.get("JOBKA_GUICHET_DAYS", "7")
36 MAX_PAGES = int(os.environ.get("JOBKA_GUICHET_PAGES", "20")) 36 MAX_PAGES = int(os.environ.get("JOBKA_GUICHET_PAGES", "20"))
37 MAX_DETAILS = int(os.environ.get("JOBKA_GUICHET_DETAIL_LIMIT", "50")) 37 MAX_DETAILS = int(os.environ.get("JOBKA_GUICHET_DETAIL_LIMIT", "50"))
38 38
39+# Page « Erreur HTTP 500 » servie avec un statut 200 (vu 2026-08-30, aléatoire
40+# requête par requête) : sans détection, 0 item → fin de pagination prématurée.
41+_SOFT500_RE = re.compile(r"<title>\s*(?:Erreur HTTP|HTTP Error)\s*5\d\d", re.I)
39 _ITEM_RE = re.compile( 42 _ITEM_RE = re.compile(
40 r'href="/rechercheemplois/offredemploi/(\d+)[^"]*"[^>]*class="resultJobItem"' 43 r'href="/rechercheemplois/offredemploi/(\d+)[^"]*"[^>]*class="resultJobItem"'
41 r"(.*?)</ul>", re.S) 44 r"(.*?)</ul>", re.S)
@@ -60,6 +63,8 @@ class GuichetEmploisConnector(BaseConnector):
60 63
61 def _fetch_detail(self, jid: str) -> dict: 64 def _fetch_detail(self, jid: str) -> dict:
62 html = self.get(f"{BASE}/rechercheemplois/offredemploi/{jid}").text 65 html = self.get(f"{BASE}/rechercheemplois/offredemploi/{jid}").text
66+ if _SOFT500_RE.search(html):
67+ return {} # erreur 200 : rien à cacher, repris au prochain cycle
63 d: dict = {} 68 d: dict = {}
64 m = re.search(r"<main[^>]*>(.*?)</main>", html, re.S | re.I) 69 m = re.search(r"<main[^>]*>(.*?)</main>", html, re.S | re.I)
65 body = m.group(1) if m else "" 70 body = m.group(1) if m else ""
@@ -94,21 +99,30 @@ class GuichetEmploisConnector(BaseConnector):
94 seen: set[str] = set() 99 seen: set[str] = set()
95 for page in range(1, MAX_PAGES + 1): 100 for page in range(1, MAX_PAGES + 1):
96 html = "" 101 html = ""
97− for attempt in (1, 2): 102+ for attempt in (1, 2, 3):
98 try: 103 try:
99 html = self.get(f"{BASE}/jobsearch/rechercheemplois", 104 html = self.get(f"{BASE}/jobsearch/rechercheemplois",
100 params={"fprov": "QC", "sort": "D", 105 params={"fprov": "QC", "sort": "D",
101 "fage": DAYS, 106 "fage": DAYS,
102 "page": str(page)}).text 107 "page": str(page)}).text
103− break
104 except (requests.ConnectionError, requests.Timeout): 108 except (requests.ConnectionError, requests.Timeout):
105 # le WAF du Guichet coupe parfois la connexion : une 109 # le WAF du Guichet coupe parfois la connexion : une
106 # reprise après pause, sinon on garde l'acquis partiel 110 # reprise après pause, sinon on garde l'acquis partiel
107− if attempt == 2: 111+ if attempt == 3:
108 if out: 112 if out:
109 return out 113 return out
110 raise 114 raise
111 time.sleep(25) 115 time.sleep(25)
116+ continue
117+ if _SOFT500_RE.search(html):
118+ # « Erreur HTTP 500 » servie en 200 : retenter la page
119+ html = ""
120+ if attempt < 3:
121+ time.sleep(15)
122+ continue
123+ break
124+ if not html:
125+ continue # erreur persistante sur CETTE page : suivante
112 items = _ITEM_RE.findall(html) 126 items = _ITEM_RE.findall(html)
113 if not items: 127 if not items:
114 break 128 break
115 129
Menu

Theme