SPB Git forge

spb/job-ka

Public
229commits 1branches 0releases
38.1 MBsize
maindefault branch
1 h agolast push
HTML 82.1% Python 14.6% TypeScript 1.9% CSS 1% JavaScript 0.5%

[ka6] snapshot pré-mission ocadogroup

Simon-Pierre Boucher committed 25 days ago (Aug 30, 2026) parent c7d9ece

1 changed file +18 −4

modified jobka/connectors/guichet_emplois.py +18 −4
@@ -6,7 +6,7 @@
6 6 # Rôle : Connecteur portail — Guichet-Emplois / Job Bank Canada (offres
7 7 # Québec, fenêtre glissante des N derniers jours). AGRÉGATEUR :
8 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 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 36 MAX_PAGES = int(os.environ.get("JOBKA_GUICHET_PAGES", "20"))
37 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 42 _ITEM_RE = re.compile(
40 43 r'href="/rechercheemplois/offredemploi/(\d+)[^"]*"[^>]*class="resultJobItem"'
41 44 r"(.*?)</ul>", re.S)
@@ -60,6 +63,8 @@ class GuichetEmploisConnector(BaseConnector):
60 63
61 64 def _fetch_detail(self, jid: str) -> dict:
62 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 68 d: dict = {}
64 69 m = re.search(r"<main[^>]*>(.*?)</main>", html, re.S | re.I)
65 70 body = m.group(1) if m else ""
@@ -94,21 +99,30 @@ class GuichetEmploisConnector(BaseConnector):
94 99 seen: set[str] = set()
95 100 for page in range(1, MAX_PAGES + 1):
96 101 html = ""
97 − for attempt in (1, 2):
102 + for attempt in (1, 2, 3):
98 103 try:
99 104 html = self.get(f"{BASE}/jobsearch/rechercheemplois",
100 105 params={"fprov": "QC", "sort": "D",
101 106 "fage": DAYS,
102 107 "page": str(page)}).text
103 − break
104 108 except (requests.ConnectionError, requests.Timeout):
105 109 # le WAF du Guichet coupe parfois la connexion : une
106 110 # reprise après pause, sinon on garde l'acquis partiel
107 − if attempt == 2:
111 + if attempt == 3:
108 112 if out:
109 113 return out
110 114 raise
111 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 126 items = _ITEM_RE.findall(html)
113 127 if not items:
114 128 break
115 129