Expansion ×: 59 nouveaux employeurs connectés via sondage massif d ATS + détection de pages carrières
- scripts/probe_ats.py : sonde 800+ slugs candidats sur les 9 ATS (timeout 6 s, throttle 0,3 s/domaine, 8 threads) ; confirmé = ≥1 offre ET ≥1 offre QC (is_quebec_location du projet). Découverte Workday sans page HTML (bloquée 406) : cxs 422=tenant absent / 404=hôte bon, puis devinette du site. - scripts/detect_ats.py : visite 6 337 domaines d employeurs QC (accueil + /carrieres|/careers|/emplois|/jobs|/fr/carrieres + liens carrières), reconnaît l ATS par motifs URL/DOM ; ATS non supportés (taleo 11, successfactors 6, adp 5, icims 4, njoyn 4, ukg 3) consignés dans data/detected-other-ats.jsonl pour traitement séparé. - data/feeds-expansion.json : 59 flux vérifiés -> 59 connecteurs générés (workday 22, smartrecruiters 10, bamboohr 12, greenhouse 6, lever 4, workable 2, ashby 1, recruitee 1, breezy 0) dont Vidéotron, CDPQ, BDC, Beneva, Intact, PSP, Investissement Québec, Rio Tinto, Alcoa, Airbus, Walmart Canada, Canadian Tire, RCGT, Lightspeed, Behaviour, Cirque du Soleil, Gameloft, Canam, QSL, Promutuel, EXFO… - 2 107 offres actives ajoutées, 100 % villes QC ; faux positif retiré (genetec smartrecruiters, doublon faible de genetec_inc workable) - normalize.py : villes hors-QC supplémentaires (Las Vegas, Orlando…) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
65 changed files +3,728 −2
added
data/detected-other-ats.jsonl
+33 −0
@@ -0,0 +1,33 @@ | ||
| 1 | +{"name": "Canada Vie", "domain": "canadalife.com", "ats": "successfactors", "url": "https://career5.successfactors.eu/career?career_company=thegreatweP2&lang=en_US&company=thegreatweP2&site=&loginFlowRequired=true","label":"View"} | |
| 2 | +{"name": "Power Corporation du Canada", "domain": "powercorporation.com", "ats": "icims", "url": "https://careersfr-mackenzieinvestments.icims.com/jobs/search?amp;hashed=0&mobile=false&width=562&height=500&bga=true&needsRedirect=false"} | |
| 3 | +{"name": "Hydro-Québec", "domain": "hydroquebec.com", "ats": "successfactors", "url": "https://rmkcdn.successfactors.com/3119a4f4/be354fb9-0f6f-4e20-a2b9-e.jpg"} | |
| 4 | +{"name": "Valero — raffinerie Jean-Gaulin", "domain": "valero.com", "ats": "taleo", "url": "https://valero.taleo.net/careersection/2/jobsearch.ftl?lang=en"} | |
| 5 | +{"name": "Agnico Eagle", "domain": "agnicoeagle.com", "ats": "taleo", "url": "https://agnicoeagle.taleo.net/careersection/2/jobsearch.ftl?lang=fi"} | |
| 6 | +{"name": "Produits forestiers Résolu", "domain": "pfresolu.com", "ats": "successfactors", "url": "https://rmkcdn.successfactors.com/2012394c/1b67750f-ca41-4435-be90-d.png"} | |
| 7 | +{"name": "Cascades", "domain": "cascades.com", "ats": "successfactors", "url": "https://performancemanager4.successfactors.com/verp/vmod_v1/ui/extlib/jquery_3.5.1/jquery.js"} | |
| 8 | +{"name": "Lassonde", "domain": "lassonde.com", "ats": "adp", "url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=f96ce972-7721-4c7b-99ea-9a970ddc824a&ccId=9200604444876_2&lang=en_US"} | |
| 9 | +{"name": "Domtar", "domain": "domtar.com", "ats": "successfactors", "url": "https://rmkcdn.successfactors.com/2012394c/1b67750f-ca41-4435-be90-d.png"} | |
| 10 | +{"name": "Kruger", "domain": "kruger.com", "ats": "taleo", "url": "https://tre.tbe.taleo.net/tre01/ats/careers/v2/jobSearch?act=redirectCwsV2&cws=76&org=KRUGER2"} | |
| 11 | +{"name": "Bell Textron Canada", "domain": "bellflight.com", "ats": "taleo", "url": "https://textron.taleo.net/careersection/bell/jobsearch.ftl?lang=en"} | |
| 12 | +{"name": "exo", "domain": "exo.quebec", "ats": "taleo", "url": "https://phh.tbe.taleo.net/phh04/ats/careers/v2/jobSearch?org=AMT&cws=39"} | |
| 13 | +{"name": "STL — Société de transport de Laval", "domain": "stlaval.ca", "ats": "njoyn", "url": "https://lavaltransit.njoyn.com/CL2/xweb/xweb.asp?tbtoken=ZlxcRRkXCBJ3EQZwNlxUCCQ7d2FEcCIoA0hYVl8LE2cuKjIdXkobdWcBcQkbUhVWSXYqWw%3D%3D&chk=ZVpaShw%3D&clid=60406&page=joblisting"} | |
| 14 | +{"name": "RTC — Réseau de transport de la Capitale", "domain": "rtcquebec.ca", "ats": "njoyn", "url": "https://rtc.njoyn.com/CGI/xweb/Xweb.asp?tbtoken=ZlBQShwXCGl6Z3BwTFNSCCZAA2FEcCcuBkggJy0PE2YqWkcdLUpqdGcGcgkbVhZSSXkqWw%3D%3D&chk=ZVpaShw%3D&CLID=23009&page=joblisting&lang=2"} | |
| 15 | +{"name": "CGI", "domain": "cgi.com", "ats": "njoyn", "url": "https://cgi.njoyn.com/CORP/xweb/xweb.asp?NTKN=c&clid=21001&page=joblisting&lang=2"} | |
| 16 | +{"name": "Groupe Dynamite", "domain": "groupedynamite.com", "ats": "icims", "url": "https://www.icims.com/legal/privacy-notice-website/"} | |
| 17 | +{"name": "Sépaq", "domain": "sepaq.com", "ats": "taleo", "url": "https://tre.tbe.taleo.net/tre01/ats/careers/v2/jobSearch?org=SEPAQ&cws=37"} | |
| 18 | +{"name": "Ville de Terrebonne", "domain": "ville.terrebonne.qc.ca", "ats": "njoyn", "url": "https://clients.njoyn.com/cl4/xweb/Xweb.asp?tbtoken=Z19fQBpfDVBzEAQHQSBVHU8%2FeBdZaVVbciBMWlB9f3ksUEsaKzIZBxEDB0YYGhJTTnZgF3Y%3D&chk=ZVpaShM%3D&CLID=71764&page=joblisting&lang=2"} | |
| 19 | +{"name": "HEC Montréal", "domain": "hec.ca", "ats": "taleo", "url": "https://tre.tbe.taleo.net/tre01/ats/careers/v2/jobSearch?act=redirectCwsV2&cws=40&org=NYQEDG"} | |
| 20 | +{"name": "Université TÉLUQ", "domain": "teluq.ca", "ats": "taleo", "url": "https://phh.tbe.taleo.net/phh01/ats/careers/jobSearch.jsp?org=TELUQ&cws=1"} | |
| 21 | +{"name": "CIUSSS de l'Est-de-l'Île-de-Montréal", "domain": "ciusss-estmtl.gouv.qc.ca", "ats": "taleo", "url": "https://ciusssemtl.taleo.net/careersection/hmr/jobsearch.ftl?lang=fr&portal=14170700380"} | |
| 22 | +{"name": "Deloitte Canada", "domain": "deloitte.com", "ats": "taleo", "url": "https://dttit.taleo.net/careersection/d_corporate+28greece29/jobsearch.ftl?lang=en"} | |
| 23 | +{"name": "Deloitte Canada", "domain": "deloitte.com", "ats": "successfactors", "url": "https://career4.successfactors.com/career?company=C0020897957P&"} | |
| 24 | +{"name": "MSI Gestion immobilière", "domain": "msimmobiliers.com", "ats": "adp", "url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=47d4e792-26e5-471c-92ac-73c60131bab8&ccId=19000101_000001&lang=fr_CA"} | |
| 25 | +{"name": "CAPREIT", "domain": "capreit.ca", "ats": "icims", "url": "https://careers-capreit.icims.com/jobs/search"} | |
| 26 | +{"name": "Osgoode Properties", "domain": "osgoodeproperties.com", "ats": "adp", "url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=c6a2e782-c971-4a6d-9a63-1365f5ce7d21&ccId=19000101_000001&lang=en_CA"} | |
| 27 | +{"name": "Fruit D'or Inc.", "domain": "fruitdor.ca", "ats": "ukg_ultipro", "url": "https://rec-cdn-prod.cdn.ultipro.com/rec-web/d3560791671d02f6e2ce98a5b18c441302d3f36a/site.css"} | |
| 28 | +{"name": "Cultures Gen V inc.", "domain": "gen-v.com", "ats": "adp", "url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=8b346731-d189-4cf2-a14c-9e48d38befde&ccId=36427051_2&lang=fr_CA&selectedMenuKey=CurrentOpenings"} | |
| 29 | +{"name": "Nortera Foods Inc.", "domain": "norterafoods.com", "ats": "ukg_ultipro", "url": "https://rec-cdn-prod.cdn.ultipro.com/rec-web/d3560791671d02f6e2ce98a5b18c441302d3f36a/site.css"} | |
| 30 | +{"name": "Produits Kruger Inc", "domain": "krugerproducts.ca", "ats": "taleo", "url": "https://tre.tbe.taleo.net/tre01/ats/careers/v2/jobSearch?org=KRUGER2&cws=78"} | |
| 31 | +{"name": "Méchant Boeuf Bar & Brasserie", "domain": "mechantboeuf.com", "ats": "ukg_ultipro", "url": "https://rec-cdn-prod.cdn.ultipro.com/rec-web/d3560791671d02f6e2ce98a5b18c441302d3f36a/site.css"} | |
| 32 | +{"name": "Bento Sushi", "domain": "bentosushi.com", "ats": "adp", "url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=d0dfb14c-f365-4599-b39b-0fdccb3d1160&ccId=19000101_000001&lang=fr_CA"} | |
| 33 | +{"name": "Jack Astor's", "domain": "jackastors.com", "ats": "icims", "url": "https://careersen-sircorp.icims.com/"} | |
added
data/feeds-expansion.json
+883 −0
@@ -0,0 +1,883 @@ | ||
| 1 | +[ | |
| 2 | + { | |
| 3 | + "ats": "ashby", | |
| 4 | + "employer": "Lightspeed Commerce", | |
| 5 | + "sectors": [ | |
| 6 | + "TI" | |
| 7 | + ], | |
| 8 | + "cities": [ | |
| 9 | + "Montréal" | |
| 10 | + ], | |
| 11 | + "url": "", | |
| 12 | + "org": "lightspeedhq", | |
| 13 | + "source_id": "lightspeedhq", | |
| 14 | + "qc": 62, | |
| 15 | + "api_name": "" | |
| 16 | + }, | |
| 17 | + { | |
| 18 | + "ats": "bamboohr", | |
| 19 | + "employer": "Big Bang", | |
| 20 | + "sectors": [ | |
| 21 | + "TI" | |
| 22 | + ], | |
| 23 | + "cities": [ | |
| 24 | + "Montréal" | |
| 25 | + ], | |
| 26 | + "url": "", | |
| 27 | + "org": "bigbang", | |
| 28 | + "source_id": "bigbang", | |
| 29 | + "qc": 8, | |
| 30 | + "api_name": "" | |
| 31 | + }, | |
| 32 | + { | |
| 33 | + "ats": "bamboohr", | |
| 34 | + "employer": "Broccolini", | |
| 35 | + "sectors": [ | |
| 36 | + "Construction", | |
| 37 | + "Immobilier" | |
| 38 | + ], | |
| 39 | + "cities": [ | |
| 40 | + "Montréal" | |
| 41 | + ], | |
| 42 | + "url": "", | |
| 43 | + "org": "broccolini", | |
| 44 | + "source_id": "broccolini", | |
| 45 | + "qc": 23, | |
| 46 | + "api_name": "" | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "ats": "bamboohr", | |
| 50 | + "employer": "Aliments Ouimet-Cordon Bleu inc.", | |
| 51 | + "sectors": [ | |
| 52 | + "Production" | |
| 53 | + ], | |
| 54 | + "cities": [], | |
| 55 | + "url": "https://clarkcordonbleu.ca", | |
| 56 | + "org": "cordonbleu", | |
| 57 | + "source_id": "cordonbleu", | |
| 58 | + "qc": 2, | |
| 59 | + "api_name": "" | |
| 60 | + }, | |
| 61 | + { | |
| 62 | + "ats": "bamboohr", | |
| 63 | + "employer": "Devimco Appartements", | |
| 64 | + "sectors": [ | |
| 65 | + "Immobilier" | |
| 66 | + ], | |
| 67 | + "cities": [], | |
| 68 | + "url": "https://devimco.com", | |
| 69 | + "org": "devimco", | |
| 70 | + "source_id": "devimco", | |
| 71 | + "qc": 7, | |
| 72 | + "api_name": "" | |
| 73 | + }, | |
| 74 | + { | |
| 75 | + "ats": "bamboohr", | |
| 76 | + "employer": "EVLO (Hydro-Québec)", | |
| 77 | + "sectors": [ | |
| 78 | + "Énergie" | |
| 79 | + ], | |
| 80 | + "cities": [ | |
| 81 | + "Varennes" | |
| 82 | + ], | |
| 83 | + "url": "", | |
| 84 | + "org": "evlo", | |
| 85 | + "source_id": "evlo", | |
| 86 | + "qc": 2, | |
| 87 | + "api_name": "" | |
| 88 | + }, | |
| 89 | + { | |
| 90 | + "ats": "bamboohr", | |
| 91 | + "employer": "Fenêtres Concept", | |
| 92 | + "sectors": [ | |
| 93 | + "Production" | |
| 94 | + ], | |
| 95 | + "cities": [], | |
| 96 | + "url": "https://fenetresconcept.com", | |
| 97 | + "org": "fenetresconcept", | |
| 98 | + "source_id": "fenetresconcept", | |
| 99 | + "qc": 1, | |
| 100 | + "api_name": "" | |
| 101 | + }, | |
| 102 | + { | |
| 103 | + "ats": "bamboohr", | |
| 104 | + "employer": "Flare (cybersécurité)", | |
| 105 | + "sectors": [ | |
| 106 | + "TI" | |
| 107 | + ], | |
| 108 | + "cities": [ | |
| 109 | + "Montréal" | |
| 110 | + ], | |
| 111 | + "url": "", | |
| 112 | + "org": "flare", | |
| 113 | + "source_id": "flare", | |
| 114 | + "qc": 2, | |
| 115 | + "api_name": "" | |
| 116 | + }, | |
| 117 | + { | |
| 118 | + "ats": "bamboohr", | |
| 119 | + "employer": "Korem", | |
| 120 | + "sectors": [ | |
| 121 | + "TI" | |
| 122 | + ], | |
| 123 | + "cities": [ | |
| 124 | + "Québec" | |
| 125 | + ], | |
| 126 | + "url": "", | |
| 127 | + "org": "korem", | |
| 128 | + "source_id": "korem", | |
| 129 | + "qc": 4, | |
| 130 | + "api_name": "" | |
| 131 | + }, | |
| 132 | + { | |
| 133 | + "ats": "bamboohr", | |
| 134 | + "employer": "Logisco", | |
| 135 | + "sectors": [ | |
| 136 | + "Immobilier" | |
| 137 | + ], | |
| 138 | + "cities": [], | |
| 139 | + "url": "https://logisco.com", | |
| 140 | + "org": "logisco", | |
| 141 | + "source_id": "logisco", | |
| 142 | + "qc": 13, | |
| 143 | + "api_name": "" | |
| 144 | + }, | |
| 145 | + { | |
| 146 | + "ats": "greenhouse", | |
| 147 | + "employer": "AlayaCare", | |
| 148 | + "sectors": [ | |
| 149 | + "TI", | |
| 150 | + "Santé" | |
| 151 | + ], | |
| 152 | + "cities": [ | |
| 153 | + "Montréal" | |
| 154 | + ], | |
| 155 | + "url": "https://www.alayacare.com", | |
| 156 | + "org": "alayacare", | |
| 157 | + "source_id": "alayacare", | |
| 158 | + "qc": 10, | |
| 159 | + "api_name": "AlayaCare" | |
| 160 | + }, | |
| 161 | + { | |
| 162 | + "ats": "greenhouse", | |
| 163 | + "employer": "GURUS Solutions", | |
| 164 | + "sectors": [ | |
| 165 | + "TI" | |
| 166 | + ], | |
| 167 | + "cities": [ | |
| 168 | + "Montréal" | |
| 169 | + ], | |
| 170 | + "url": "", | |
| 171 | + "org": "gurussolutions", | |
| 172 | + "source_id": "gurussolutions", | |
| 173 | + "qc": 8, | |
| 174 | + "api_name": "GURUS Solutions" | |
| 175 | + }, | |
| 176 | + { | |
| 177 | + "ats": "greenhouse", | |
| 178 | + "employer": "Levio", | |
| 179 | + "sectors": [ | |
| 180 | + "TI" | |
| 181 | + ], | |
| 182 | + "cities": [ | |
| 183 | + "Québec", | |
| 184 | + "Montréal" | |
| 185 | + ], | |
| 186 | + "url": "", | |
| 187 | + "org": "levio", | |
| 188 | + "source_id": "levio", | |
| 189 | + "qc": 42, | |
| 190 | + "api_name": "Levio" | |
| 191 | + }, | |
| 192 | + { | |
| 193 | + "ats": "greenhouse", | |
| 194 | + "employer": "Sid Lee", | |
| 195 | + "sectors": [ | |
| 196 | + "Marketing", | |
| 197 | + "Création" | |
| 198 | + ], | |
| 199 | + "cities": [ | |
| 200 | + "Montréal" | |
| 201 | + ], | |
| 202 | + "url": "", | |
| 203 | + "org": "sidlee", | |
| 204 | + "source_id": "sidlee", | |
| 205 | + "qc": 15, | |
| 206 | + "api_name": "Sid Lee" | |
| 207 | + }, | |
| 208 | + { | |
| 209 | + "ats": "greenhouse", | |
| 210 | + "employer": "Valtech", | |
| 211 | + "sectors": [ | |
| 212 | + "TI" | |
| 213 | + ], | |
| 214 | + "cities": [ | |
| 215 | + "Montréal" | |
| 216 | + ], | |
| 217 | + "url": "", | |
| 218 | + "org": "valtech", | |
| 219 | + "source_id": "valtech", | |
| 220 | + "qc": 17, | |
| 221 | + "api_name": "Valtech" | |
| 222 | + }, | |
| 223 | + { | |
| 224 | + "ats": "greenhouse", | |
| 225 | + "employer": "Vooban", | |
| 226 | + "sectors": [ | |
| 227 | + "TI" | |
| 228 | + ], | |
| 229 | + "cities": [ | |
| 230 | + "Québec" | |
| 231 | + ], | |
| 232 | + "url": "", | |
| 233 | + "org": "vooban", | |
| 234 | + "source_id": "vooban", | |
| 235 | + "qc": 18, | |
| 236 | + "api_name": "" | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "ats": "lever", | |
| 240 | + "employer": "Behaviour Interactif", | |
| 241 | + "sectors": [ | |
| 242 | + "Jeux vidéo" | |
| 243 | + ], | |
| 244 | + "cities": [ | |
| 245 | + "Montréal" | |
| 246 | + ], | |
| 247 | + "url": "", | |
| 248 | + "org": "bhvr", | |
| 249 | + "source_id": "bhvr", | |
| 250 | + "qc": 39, | |
| 251 | + "api_name": "" | |
| 252 | + }, | |
| 253 | + { | |
| 254 | + "ats": "lever", | |
| 255 | + "employer": "Cirque du Soleil", | |
| 256 | + "sectors": [ | |
| 257 | + "Divertissement", | |
| 258 | + "Création" | |
| 259 | + ], | |
| 260 | + "cities": [ | |
| 261 | + "Montréal" | |
| 262 | + ], | |
| 263 | + "url": "https://www.cirquedusoleil.com", | |
| 264 | + "org": "cirquedusoleil", | |
| 265 | + "source_id": "cirquedusoleil", | |
| 266 | + "qc": 19, | |
| 267 | + "api_name": "" | |
| 268 | + }, | |
| 269 | + { | |
| 270 | + "ats": "lever", | |
| 271 | + "employer": "Mirego", | |
| 272 | + "sectors": [ | |
| 273 | + "TI" | |
| 274 | + ], | |
| 275 | + "cities": [ | |
| 276 | + "Québec", | |
| 277 | + "Montréal" | |
| 278 | + ], | |
| 279 | + "url": "", | |
| 280 | + "org": "mirego", | |
| 281 | + "source_id": "mirego", | |
| 282 | + "qc": 11, | |
| 283 | + "api_name": "" | |
| 284 | + }, | |
| 285 | + { | |
| 286 | + "ats": "lever", | |
| 287 | + "employer": "Spiria", | |
| 288 | + "sectors": [ | |
| 289 | + "TI" | |
| 290 | + ], | |
| 291 | + "cities": [ | |
| 292 | + "Montréal", | |
| 293 | + "Gatineau" | |
| 294 | + ], | |
| 295 | + "url": "", | |
| 296 | + "org": "spiria", | |
| 297 | + "source_id": "spiria", | |
| 298 | + "qc": 16, | |
| 299 | + "api_name": "" | |
| 300 | + }, | |
| 301 | + { | |
| 302 | + "ats": "recruitee", | |
| 303 | + "employer": "Amilia", | |
| 304 | + "sectors": [ | |
| 305 | + "TI" | |
| 306 | + ], | |
| 307 | + "cities": [ | |
| 308 | + "Montréal" | |
| 309 | + ], | |
| 310 | + "url": "", | |
| 311 | + "org": "amilia", | |
| 312 | + "source_id": "amilia", | |
| 313 | + "qc": 1, | |
| 314 | + "api_name": "" | |
| 315 | + }, | |
| 316 | + { | |
| 317 | + "ats": "smartrecruiters", | |
| 318 | + "employer": "Gameloft", | |
| 319 | + "sectors": [ | |
| 320 | + "Jeux vidéo" | |
| 321 | + ], | |
| 322 | + "cities": [ | |
| 323 | + "Montréal" | |
| 324 | + ], | |
| 325 | + "url": "https://www.gameloft.com", | |
| 326 | + "org": "gameloft", | |
| 327 | + "source_id": "gameloft", | |
| 328 | + "qc": 15, | |
| 329 | + "api_name": "Gameloft" | |
| 330 | + }, | |
| 331 | + { | |
| 332 | + "ats": "smartrecruiters", | |
| 333 | + "employer": "GoLogic", | |
| 334 | + "sectors": [ | |
| 335 | + "TI" | |
| 336 | + ], | |
| 337 | + "cities": [ | |
| 338 | + "Montréal" | |
| 339 | + ], | |
| 340 | + "url": "", | |
| 341 | + "org": "gologic", | |
| 342 | + "source_id": "gologic", | |
| 343 | + "qc": 1, | |
| 344 | + "api_name": "Gologic" | |
| 345 | + }, | |
| 346 | + { | |
| 347 | + "ats": "smartrecruiters", | |
| 348 | + "employer": "Groupe Canam", | |
| 349 | + "sectors": [ | |
| 350 | + "Production", | |
| 351 | + "Construction" | |
| 352 | + ], | |
| 353 | + "cities": [ | |
| 354 | + "Saint-Georges" | |
| 355 | + ], | |
| 356 | + "url": "", | |
| 357 | + "org": "groupecanam", | |
| 358 | + "source_id": "groupecanam", | |
| 359 | + "qc": 66, | |
| 360 | + "api_name": "Canam" | |
| 361 | + }, | |
| 362 | + { | |
| 363 | + "ats": "smartrecruiters", | |
| 364 | + "employer": "Playmind", | |
| 365 | + "sectors": [ | |
| 366 | + "Jeux vidéo" | |
| 367 | + ], | |
| 368 | + "cities": [ | |
| 369 | + "Montréal" | |
| 370 | + ], | |
| 371 | + "url": "", | |
| 372 | + "org": "playmind", | |
| 373 | + "source_id": "playmind", | |
| 374 | + "qc": 2, | |
| 375 | + "api_name": "PLAYMIND" | |
| 376 | + }, | |
| 377 | + { | |
| 378 | + "ats": "smartrecruiters", | |
| 379 | + "employer": "QSL", | |
| 380 | + "sectors": [], | |
| 381 | + "cities": [ | |
| 382 | + "Québec" | |
| 383 | + ], | |
| 384 | + "url": "https://qsl.com", | |
| 385 | + "org": "qsl", | |
| 386 | + "source_id": "qsl", | |
| 387 | + "qc": 37, | |
| 388 | + "api_name": "QSL" | |
| 389 | + }, | |
| 390 | + { | |
| 391 | + "ats": "smartrecruiters", | |
| 392 | + "employer": "Stelpro", | |
| 393 | + "sectors": [ | |
| 394 | + "Production" | |
| 395 | + ], | |
| 396 | + "cities": [ | |
| 397 | + "Saint-Bruno-de-Montarville" | |
| 398 | + ], | |
| 399 | + "url": "", | |
| 400 | + "org": "stelpro", | |
| 401 | + "source_id": "stelpro", | |
| 402 | + "qc": 1, | |
| 403 | + "api_name": "Stelpro" | |
| 404 | + }, | |
| 405 | + { | |
| 406 | + "ats": "smartrecruiters", | |
| 407 | + "employer": "Talsom", | |
| 408 | + "sectors": [ | |
| 409 | + "TI" | |
| 410 | + ], | |
| 411 | + "cities": [ | |
| 412 | + "Montréal" | |
| 413 | + ], | |
| 414 | + "url": "", | |
| 415 | + "org": "talsom", | |
| 416 | + "source_id": "talsom", | |
| 417 | + "qc": 1, | |
| 418 | + "api_name": "Talsom" | |
| 419 | + }, | |
| 420 | + { | |
| 421 | + "ats": "smartrecruiters", | |
| 422 | + "employer": "Vidéotron", | |
| 423 | + "sectors": [], | |
| 424 | + "cities": [ | |
| 425 | + "Montréal" | |
| 426 | + ], | |
| 427 | + "url": "https://videotron.com", | |
| 428 | + "org": "videotron", | |
| 429 | + "source_id": "videotron", | |
| 430 | + "qc": 77, | |
| 431 | + "api_name": "Videotron" | |
| 432 | + }, | |
| 433 | + { | |
| 434 | + "ats": "smartrecruiters", | |
| 435 | + "employer": "Vosker", | |
| 436 | + "sectors": [ | |
| 437 | + "TI", | |
| 438 | + "Production" | |
| 439 | + ], | |
| 440 | + "cities": [ | |
| 441 | + "Victoriaville" | |
| 442 | + ], | |
| 443 | + "url": "", | |
| 444 | + "org": "vosker", | |
| 445 | + "source_id": "vosker", | |
| 446 | + "qc": 20, | |
| 447 | + "api_name": "Vosker" | |
| 448 | + }, | |
| 449 | + { | |
| 450 | + "ats": "workable", | |
| 451 | + "employer": "Genetec", | |
| 452 | + "sectors": [], | |
| 453 | + "cities": [ | |
| 454 | + "Montréal" | |
| 455 | + ], | |
| 456 | + "url": "https://genetec.com", | |
| 457 | + "org": "genetec-inc", | |
| 458 | + "source_id": "genetec_inc", | |
| 459 | + "qc": 81, | |
| 460 | + "api_name": "Genetec" | |
| 461 | + }, | |
| 462 | + { | |
| 463 | + "ats": "workable", | |
| 464 | + "employer": "Mila — Institut québécois d'IA", | |
| 465 | + "sectors": [], | |
| 466 | + "cities": [ | |
| 467 | + "Montréal" | |
| 468 | + ], | |
| 469 | + "url": "https://mila.quebec", | |
| 470 | + "org": "mila-2", | |
| 471 | + "source_id": "mila_2", | |
| 472 | + "qc": 8, | |
| 473 | + "api_name": "Mila - Institut québécois d'intelligence artificielle" | |
| 474 | + }, | |
| 475 | + { | |
| 476 | + "ats": "workday", | |
| 477 | + "employer": "Airbus Canada", | |
| 478 | + "sectors": [], | |
| 479 | + "cities": [ | |
| 480 | + "Mirabel" | |
| 481 | + ], | |
| 482 | + "url": "https://airbus.com", | |
| 483 | + "tenant": "ag", | |
| 484 | + "host": "wd3", | |
| 485 | + "site": "Airbus", | |
| 486 | + "source_id": "airbus", | |
| 487 | + "qc": 1, | |
| 488 | + "api_name": "" | |
| 489 | + }, | |
| 490 | + { | |
| 491 | + "ats": "workday", | |
| 492 | + "employer": "Alcoa Canada", | |
| 493 | + "sectors": [], | |
| 494 | + "cities": [ | |
| 495 | + "Baie-Comeau" | |
| 496 | + ], | |
| 497 | + "url": "https://alcoa.com", | |
| 498 | + "tenant": "alcoa", | |
| 499 | + "host": "wd5", | |
| 500 | + "site": "Careers", | |
| 501 | + "source_id": "alcoa", | |
| 502 | + "qc": 2, | |
| 503 | + "api_name": "" | |
| 504 | + }, | |
| 505 | + { | |
| 506 | + "ats": "workday", | |
| 507 | + "employer": "Altasciences", | |
| 508 | + "sectors": [ | |
| 509 | + "Pharmaceutique" | |
| 510 | + ], | |
| 511 | + "cities": [ | |
| 512 | + "Laval" | |
| 513 | + ], | |
| 514 | + "url": "", | |
| 515 | + "tenant": "altasciences", | |
| 516 | + "host": "wd1", | |
| 517 | + "site": "Careers", | |
| 518 | + "source_id": "altasciences", | |
| 519 | + "qc": 6, | |
| 520 | + "api_name": "" | |
| 521 | + }, | |
| 522 | + { | |
| 523 | + "ats": "workday", | |
| 524 | + "employer": "BDC", | |
| 525 | + "sectors": [ | |
| 526 | + "Finance" | |
| 527 | + ], | |
| 528 | + "cities": [ | |
| 529 | + "Montréal" | |
| 530 | + ], | |
| 531 | + "url": "", | |
| 532 | + "tenant": "bdc", | |
| 533 | + "host": "wd10", | |
| 534 | + "site": "bdc_careers", | |
| 535 | + "source_id": "bdc", | |
| 536 | + "qc": 10, | |
| 537 | + "api_name": "" | |
| 538 | + }, | |
| 539 | + { | |
| 540 | + "ats": "workday", | |
| 541 | + "employer": "Beneva", | |
| 542 | + "sectors": [], | |
| 543 | + "cities": [ | |
| 544 | + "Québec" | |
| 545 | + ], | |
| 546 | + "url": "https://beneva.ca", | |
| 547 | + "tenant": "beneva", | |
| 548 | + "host": "wd10", | |
| 549 | + "site": "BenevaSite_carriere", | |
| 550 | + "source_id": "beneva", | |
| 551 | + "qc": 4, | |
| 552 | + "api_name": "" | |
| 553 | + }, | |
| 554 | + { | |
| 555 | + "ats": "workday", | |
| 556 | + "employer": "CAA-Québec", | |
| 557 | + "sectors": [], | |
| 558 | + "cities": [ | |
| 559 | + "Québec" | |
| 560 | + ], | |
| 561 | + "url": "https://caaquebec.com", | |
| 562 | + "tenant": "caaquebec", | |
| 563 | + "host": "wd3", | |
| 564 | + "site": "CarrieresCAA-Quebec", | |
| 565 | + "source_id": "caaquebec", | |
| 566 | + "qc": 12, | |
| 567 | + "api_name": "" | |
| 568 | + }, | |
| 569 | + { | |
| 570 | + "ats": "workday", | |
| 571 | + "employer": "Canadian Tire", | |
| 572 | + "sectors": [], | |
| 573 | + "cities": [ | |
| 574 | + "Montréal" | |
| 575 | + ], | |
| 576 | + "url": "https://canadiantire.ca", | |
| 577 | + "tenant": "canadiantirecorporation", | |
| 578 | + "host": "wd3", | |
| 579 | + "site": "Enterprise_External_Careers_Site", | |
| 580 | + "source_id": "canadiantirecorporation", | |
| 581 | + "qc": 9, | |
| 582 | + "api_name": "" | |
| 583 | + }, | |
| 584 | + { | |
| 585 | + "ats": "workday", | |
| 586 | + "employer": "CDPQ — Caisse de dépôt et placement du Québec", | |
| 587 | + "sectors": [], | |
| 588 | + "cities": [ | |
| 589 | + "Montréal" | |
| 590 | + ], | |
| 591 | + "url": "https://cdpq.com", | |
| 592 | + "tenant": "cdpq", | |
| 593 | + "host": "wd10", | |
| 594 | + "site": "CDPQ", | |
| 595 | + "source_id": "cdpq", | |
| 596 | + "qc": 20, | |
| 597 | + "api_name": "" | |
| 598 | + }, | |
| 599 | + { | |
| 600 | + "ats": "workday", | |
| 601 | + "employer": "Church & Dwight Canada", | |
| 602 | + "sectors": [ | |
| 603 | + "Production" | |
| 604 | + ], | |
| 605 | + "cities": [], | |
| 606 | + "url": "https://churchdwight.ca", | |
| 607 | + "tenant": "churchdwight", | |
| 608 | + "host": "wd1", | |
| 609 | + "site": "chdcanadacareers", | |
| 610 | + "source_id": "churchdwight", | |
| 611 | + "qc": 6, | |
| 612 | + "api_name": "" | |
| 613 | + }, | |
| 614 | + { | |
| 615 | + "ats": "workday", | |
| 616 | + "employer": "EXFO", | |
| 617 | + "sectors": [ | |
| 618 | + "TI", | |
| 619 | + "Télécommunications" | |
| 620 | + ], | |
| 621 | + "cities": [ | |
| 622 | + "Québec" | |
| 623 | + ], | |
| 624 | + "url": "", | |
| 625 | + "tenant": "exfo", | |
| 626 | + "host": "wd10", | |
| 627 | + "site": "exfo_careers", | |
| 628 | + "source_id": "exfo", | |
| 629 | + "qc": 12, | |
| 630 | + "api_name": "" | |
| 631 | + }, | |
| 632 | + { | |
| 633 | + "ats": "workday", | |
| 634 | + "employer": "Fonds de solidarité FTQ", | |
| 635 | + "sectors": [], | |
| 636 | + "cities": [ | |
| 637 | + "Montréal" | |
| 638 | + ], | |
| 639 | + "url": "https://fondsftq.com", | |
| 640 | + "tenant": "fondsftq", | |
| 641 | + "host": "wd10", | |
| 642 | + "site": "sitecarriere_externe", | |
| 643 | + "source_id": "fondsftq", | |
| 644 | + "qc": 10, | |
| 645 | + "api_name": "" | |
| 646 | + }, | |
| 647 | + { | |
| 648 | + "ats": "workday", | |
| 649 | + "employer": "Intact Corporation financière", | |
| 650 | + "sectors": [ | |
| 651 | + "Assurance" | |
| 652 | + ], | |
| 653 | + "cities": [ | |
| 654 | + "Montréal" | |
| 655 | + ], | |
| 656 | + "url": "", | |
| 657 | + "tenant": "intactfc", | |
| 658 | + "host": "wd3", | |
| 659 | + "site": "Intactfc", | |
| 660 | + "source_id": "intactfc", | |
| 661 | + "qc": 2, | |
| 662 | + "api_name": "" | |
| 663 | + }, | |
| 664 | + { | |
| 665 | + "ats": "workday", | |
| 666 | + "employer": "Investissements PSP", | |
| 667 | + "sectors": [], | |
| 668 | + "cities": [ | |
| 669 | + "Montréal" | |
| 670 | + ], | |
| 671 | + "url": "https://investpsp.com", | |
| 672 | + "tenant": "investpsp", | |
| 673 | + "host": "wd3", | |
| 674 | + "site": "psp_careers", | |
| 675 | + "source_id": "investpsp", | |
| 676 | + "qc": 19, | |
| 677 | + "api_name": "" | |
| 678 | + }, | |
| 679 | + { | |
| 680 | + "ats": "workday", | |
| 681 | + "employer": "Investissement Québec", | |
| 682 | + "sectors": [], | |
| 683 | + "cities": [ | |
| 684 | + "Québec" | |
| 685 | + ], | |
| 686 | + "url": "https://investquebec.com", | |
| 687 | + "tenant": "investquebec", | |
| 688 | + "host": "wd10", | |
| 689 | + "site": "Ext", | |
| 690 | + "source_id": "investquebec", | |
| 691 | + "qc": 16, | |
| 692 | + "api_name": "" | |
| 693 | + }, | |
| 694 | + { | |
| 695 | + "ats": "workday", | |
| 696 | + "employer": "Plusgrade", | |
| 697 | + "sectors": [], | |
| 698 | + "cities": [ | |
| 699 | + "Montréal" | |
| 700 | + ], | |
| 701 | + "url": "https://plusgrade.com", | |
| 702 | + "tenant": "plusgrade", | |
| 703 | + "host": "wd10", | |
| 704 | + "site": "Plusgrade_External_Site", | |
| 705 | + "source_id": "plusgrade", | |
| 706 | + "qc": 4, | |
| 707 | + "api_name": "" | |
| 708 | + }, | |
| 709 | + { | |
| 710 | + "ats": "workday", | |
| 711 | + "employer": "Promutuel Assurance", | |
| 712 | + "sectors": [], | |
| 713 | + "cities": [ | |
| 714 | + "Québec" | |
| 715 | + ], | |
| 716 | + "url": "https://promutuelassurance.ca", | |
| 717 | + "tenant": "promutuel", | |
| 718 | + "host": "wd3", | |
| 719 | + "site": "promutuel_carrieres", | |
| 720 | + "source_id": "promutuel", | |
| 721 | + "qc": 7, | |
| 722 | + "api_name": "" | |
| 723 | + }, | |
| 724 | + { | |
| 725 | + "ats": "workday", | |
| 726 | + "employer": "Raymond Chabot Grant Thornton", | |
| 727 | + "sectors": [], | |
| 728 | + "cities": [ | |
| 729 | + "Montréal" | |
| 730 | + ], | |
| 731 | + "url": "https://rcgt.com", | |
| 732 | + "tenant": "rcgt", | |
| 733 | + "host": "wd3", | |
| 734 | + "site": "External", | |
| 735 | + "source_id": "rcgt", | |
| 736 | + "qc": 17, | |
| 737 | + "api_name": "" | |
| 738 | + }, | |
| 739 | + { | |
| 740 | + "ats": "workday", | |
| 741 | + "employer": "Rio Tinto", | |
| 742 | + "sectors": [ | |
| 743 | + "Mines" | |
| 744 | + ], | |
| 745 | + "cities": [ | |
| 746 | + "Saguenay", | |
| 747 | + "Montréal" | |
| 748 | + ], | |
| 749 | + "url": "", | |
| 750 | + "tenant": "riotinto", | |
| 751 | + "host": "wd3", | |
| 752 | + "site": "riotinto_careers", | |
| 753 | + "source_id": "riotinto", | |
| 754 | + "qc": 3, | |
| 755 | + "api_name": "" | |
| 756 | + }, | |
| 757 | + { | |
| 758 | + "ats": "workday", | |
| 759 | + "employer": "Suncor Énergie", | |
| 760 | + "sectors": [], | |
| 761 | + "cities": [ | |
| 762 | + "Montréal" | |
| 763 | + ], | |
| 764 | + "url": "https://suncor.com", | |
| 765 | + "tenant": "suncor", | |
| 766 | + "host": "wd1", | |
| 767 | + "site": "Suncor_External", | |
| 768 | + "source_id": "suncor", | |
| 769 | + "qc": 2, | |
| 770 | + "api_name": "" | |
| 771 | + }, | |
| 772 | + { | |
| 773 | + "ats": "workday", | |
| 774 | + "employer": "Walmart Canada", | |
| 775 | + "sectors": [], | |
| 776 | + "cities": [ | |
| 777 | + "Montréal" | |
| 778 | + ], | |
| 779 | + "url": "https://walmart.ca", | |
| 780 | + "tenant": "walmart", | |
| 781 | + "host": "wd504", | |
| 782 | + "site": "WalmartExternal", | |
| 783 | + "source_id": "walmart", | |
| 784 | + "qc": 2, | |
| 785 | + "api_name": "" | |
| 786 | + }, | |
| 787 | + { | |
| 788 | + "ats": "bamboohr", | |
| 789 | + "employer": "MXO", | |
| 790 | + "sectors": [ | |
| 791 | + "manufacturier/commerce" | |
| 792 | + ], | |
| 793 | + "cities": [], | |
| 794 | + "url": "https://mxoconseil.com", | |
| 795 | + "org": "mxo", | |
| 796 | + "qc": 6, | |
| 797 | + "api_name": "" | |
| 798 | + }, | |
| 799 | + { | |
| 800 | + "ats": "bamboohr", | |
| 801 | + "employer": "Poulet Rouge", | |
| 802 | + "sectors": [ | |
| 803 | + "restauration" | |
| 804 | + ], | |
| 805 | + "cities": [ | |
| 806 | + "Montréal" | |
| 807 | + ], | |
| 808 | + "url": "https://poulet-rouge.ca", | |
| 809 | + "org": "pouletrouge", | |
| 810 | + "qc": 1, | |
| 811 | + "api_name": "" | |
| 812 | + }, | |
| 813 | + { | |
| 814 | + "ats": "bamboohr", | |
| 815 | + "employer": "Ziptrek Tremblant", | |
| 816 | + "sectors": [ | |
| 817 | + "manufacturier/commerce" | |
| 818 | + ], | |
| 819 | + "cities": [], | |
| 820 | + "url": "https://tremblant.ziptrek.com", | |
| 821 | + "org": "ziptrekeco", | |
| 822 | + "qc": 2, | |
| 823 | + "api_name": "" | |
| 824 | + }, | |
| 825 | + { | |
| 826 | + "ats": "workday", | |
| 827 | + "employer": "JG Rive-Sud (GFS)", | |
| 828 | + "sectors": [ | |
| 829 | + "manufacturier/commerce" | |
| 830 | + ], | |
| 831 | + "cities": [], | |
| 832 | + "url": "https://jgfruitsetlegumes.com", | |
| 833 | + "tenant": "gfs", | |
| 834 | + "host": "wd5", | |
| 835 | + "site": "jgrive-sud", | |
| 836 | + "source_id": "jgrivesud", | |
| 837 | + "qc": 10, | |
| 838 | + "api_name": "" | |
| 839 | + }, | |
| 840 | + { | |
| 841 | + "ats": "workday", | |
| 842 | + "employer": "Service alimentaire Gordon", | |
| 843 | + "sectors": [ | |
| 844 | + "manufacturier/commerce" | |
| 845 | + ], | |
| 846 | + "cities": [], | |
| 847 | + "url": "https://gfs.ca", | |
| 848 | + "tenant": "gfs", | |
| 849 | + "host": "wd5", | |
| 850 | + "site": "usjobs-french", | |
| 851 | + "source_id": "gfs", | |
| 852 | + "qc": 19, | |
| 853 | + "api_name": "" | |
| 854 | + }, | |
| 855 | + { | |
| 856 | + "ats": "workday", | |
| 857 | + "employer": "Scotts Canada (Fafard)", | |
| 858 | + "sectors": [ | |
| 859 | + "manufacturier/commerce" | |
| 860 | + ], | |
| 861 | + "cities": [], | |
| 862 | + "url": "https://scottsmiraclegro.com", | |
| 863 | + "tenant": "scottsmiraclegro", | |
| 864 | + "host": "wd5", | |
| 865 | + "site": "SMGExternal", | |
| 866 | + "qc": 3, | |
| 867 | + "api_name": "" | |
| 868 | + }, | |
| 869 | + { | |
| 870 | + "ats": "workday", | |
| 871 | + "employer": "Brasseries Sleeman (Unibroue)", | |
| 872 | + "sectors": [ | |
| 873 | + "manufacturier/commerce" | |
| 874 | + ], | |
| 875 | + "cities": [], | |
| 876 | + "url": "https://unibroue.com", | |
| 877 | + "tenant": "sleeman", | |
| 878 | + "host": "wd3", | |
| 879 | + "site": "SBL", | |
| 880 | + "qc": 3, | |
| 881 | + "api_name": "" | |
| 882 | + } | |
| 883 | +] | |
modified
data/sources.json
+1041 −1
@@ -3,7 +3,7 @@ | ||
| 3 | 3 | "project": "Job·Ka — Groupe KA", |
| 4 | 4 | "author": "Simon-Pierre Boucher <contact@spboucher.ai>", |
| 5 | 5 | "role": "Registre descriptif des sources (alimente la page Sources)", |
| 6 | − "updated": "2026-08-17" | |
| 6 | + "updated": "2026-08-18" | |
| 7 | 7 | }, |
| 8 | 8 | "sources": [ |
| 9 | 9 | { |
@@ -1714,6 +1714,1046 @@ | ||
| 1714 | 1714 | "connector": "bamboohr", |
| 1715 | 1715 | "status": "actif", |
| 1716 | 1716 | "region": "Montréal" |
| 1717 | + }, | |
| 1718 | + { | |
| 1719 | + "id": "lightspeedhq", | |
| 1720 | + "name": "Lightspeed Commerce", | |
| 1721 | + "url": "", | |
| 1722 | + "careers_url": "https://jobs.ashbyhq.com/lightspeedhq", | |
| 1723 | + "sectors": [ | |
| 1724 | + "TI" | |
| 1725 | + ], | |
| 1726 | + "connector": "ashby", | |
| 1727 | + "status": "actif", | |
| 1728 | + "region": "Montréal" | |
| 1729 | + }, | |
| 1730 | + { | |
| 1731 | + "id": "bigbang", | |
| 1732 | + "name": "Big Bang", | |
| 1733 | + "url": "", | |
| 1734 | + "careers_url": "https://bigbang.bamboohr.com/careers", | |
| 1735 | + "sectors": [ | |
| 1736 | + "TI" | |
| 1737 | + ], | |
| 1738 | + "connector": "bamboohr", | |
| 1739 | + "status": "actif", | |
| 1740 | + "region": "Montréal" | |
| 1741 | + }, | |
| 1742 | + { | |
| 1743 | + "id": "broccolini", | |
| 1744 | + "name": "Broccolini", | |
| 1745 | + "url": "", | |
| 1746 | + "careers_url": "https://broccolini.bamboohr.com/careers", | |
| 1747 | + "sectors": [ | |
| 1748 | + "Construction", | |
| 1749 | + "Immobilier" | |
| 1750 | + ], | |
| 1751 | + "connector": "bamboohr", | |
| 1752 | + "status": "actif", | |
| 1753 | + "region": "Montréal" | |
| 1754 | + }, | |
| 1755 | + { | |
| 1756 | + "id": "cordonbleu", | |
| 1757 | + "name": "Aliments Ouimet-Cordon Bleu inc.", | |
| 1758 | + "url": "https://clarkcordonbleu.ca", | |
| 1759 | + "careers_url": "https://cordonbleu.bamboohr.com/careers", | |
| 1760 | + "sectors": [ | |
| 1761 | + "Production" | |
| 1762 | + ], | |
| 1763 | + "connector": "bamboohr", | |
| 1764 | + "status": "actif", | |
| 1765 | + "region": "" | |
| 1766 | + }, | |
| 1767 | + { | |
| 1768 | + "id": "devimco", | |
| 1769 | + "name": "Devimco Appartements", | |
| 1770 | + "url": "https://devimco.com", | |
| 1771 | + "careers_url": "https://devimco.bamboohr.com/careers", | |
| 1772 | + "sectors": [ | |
| 1773 | + "Immobilier" | |
| 1774 | + ], | |
| 1775 | + "connector": "bamboohr", | |
| 1776 | + "status": "actif", | |
| 1777 | + "region": "" | |
| 1778 | + }, | |
| 1779 | + { | |
| 1780 | + "id": "evlo", | |
| 1781 | + "name": "EVLO (Hydro-Québec)", | |
| 1782 | + "url": "", | |
| 1783 | + "careers_url": "https://evlo.bamboohr.com/careers", | |
| 1784 | + "sectors": [ | |
| 1785 | + "Énergie" | |
| 1786 | + ], | |
| 1787 | + "connector": "bamboohr", | |
| 1788 | + "status": "actif", | |
| 1789 | + "region": "Varennes" | |
| 1790 | + }, | |
| 1791 | + { | |
| 1792 | + "id": "fenetresconcept", | |
| 1793 | + "name": "Fenêtres Concept", | |
| 1794 | + "url": "https://fenetresconcept.com", | |
| 1795 | + "careers_url": "https://fenetresconcept.bamboohr.com/careers", | |
| 1796 | + "sectors": [ | |
| 1797 | + "Production" | |
| 1798 | + ], | |
| 1799 | + "connector": "bamboohr", | |
| 1800 | + "status": "actif", | |
| 1801 | + "region": "" | |
| 1802 | + }, | |
| 1803 | + { | |
| 1804 | + "id": "flare", | |
| 1805 | + "name": "Flare (cybersécurité)", | |
| 1806 | + "url": "", | |
| 1807 | + "careers_url": "https://flare.bamboohr.com/careers", | |
| 1808 | + "sectors": [ | |
| 1809 | + "TI" | |
| 1810 | + ], | |
| 1811 | + "connector": "bamboohr", | |
| 1812 | + "status": "actif", | |
| 1813 | + "region": "Montréal" | |
| 1814 | + }, | |
| 1815 | + { | |
| 1816 | + "id": "korem", | |
| 1817 | + "name": "Korem", | |
| 1818 | + "url": "", | |
| 1819 | + "careers_url": "https://korem.bamboohr.com/careers", | |
| 1820 | + "sectors": [ | |
| 1821 | + "TI" | |
| 1822 | + ], | |
| 1823 | + "connector": "bamboohr", | |
| 1824 | + "status": "actif", | |
| 1825 | + "region": "Québec" | |
| 1826 | + }, | |
| 1827 | + { | |
| 1828 | + "id": "logisco", | |
| 1829 | + "name": "Logisco", | |
| 1830 | + "url": "https://logisco.com", | |
| 1831 | + "careers_url": "https://logisco.bamboohr.com/careers", | |
| 1832 | + "sectors": [ | |
| 1833 | + "Immobilier" | |
| 1834 | + ], | |
| 1835 | + "connector": "bamboohr", | |
| 1836 | + "status": "actif", | |
| 1837 | + "region": "" | |
| 1838 | + }, | |
| 1839 | + { | |
| 1840 | + "id": "alayacare", | |
| 1841 | + "name": "AlayaCare", | |
| 1842 | + "url": "https://www.alayacare.com", | |
| 1843 | + "careers_url": "https://job-boards.greenhouse.io/alayacare", | |
| 1844 | + "sectors": [ | |
| 1845 | + "TI", | |
| 1846 | + "Santé" | |
| 1847 | + ], | |
| 1848 | + "connector": "greenhouse", | |
| 1849 | + "status": "actif", | |
| 1850 | + "region": "Montréal" | |
| 1851 | + }, | |
| 1852 | + { | |
| 1853 | + "id": "gurussolutions", | |
| 1854 | + "name": "GURUS Solutions", | |
| 1855 | + "url": "", | |
| 1856 | + "careers_url": "https://job-boards.greenhouse.io/gurussolutions", | |
| 1857 | + "sectors": [ | |
| 1858 | + "TI" | |
| 1859 | + ], | |
| 1860 | + "connector": "greenhouse", | |
| 1861 | + "status": "actif", | |
| 1862 | + "region": "Montréal" | |
| 1863 | + }, | |
| 1864 | + { | |
| 1865 | + "id": "levio", | |
| 1866 | + "name": "Levio", | |
| 1867 | + "url": "", | |
| 1868 | + "careers_url": "https://job-boards.greenhouse.io/levio", | |
| 1869 | + "sectors": [ | |
| 1870 | + "TI" | |
| 1871 | + ], | |
| 1872 | + "connector": "greenhouse", | |
| 1873 | + "status": "actif", | |
| 1874 | + "region": "Québec, Montréal" | |
| 1875 | + }, | |
| 1876 | + { | |
| 1877 | + "id": "sidlee", | |
| 1878 | + "name": "Sid Lee", | |
| 1879 | + "url": "", | |
| 1880 | + "careers_url": "https://job-boards.greenhouse.io/sidlee", | |
| 1881 | + "sectors": [ | |
| 1882 | + "Marketing", | |
| 1883 | + "Création" | |
| 1884 | + ], | |
| 1885 | + "connector": "greenhouse", | |
| 1886 | + "status": "actif", | |
| 1887 | + "region": "Montréal" | |
| 1888 | + }, | |
| 1889 | + { | |
| 1890 | + "id": "valtech", | |
| 1891 | + "name": "Valtech", | |
| 1892 | + "url": "", | |
| 1893 | + "careers_url": "https://job-boards.greenhouse.io/valtech", | |
| 1894 | + "sectors": [ | |
| 1895 | + "TI" | |
| 1896 | + ], | |
| 1897 | + "connector": "greenhouse", | |
| 1898 | + "status": "actif", | |
| 1899 | + "region": "Montréal" | |
| 1900 | + }, | |
| 1901 | + { | |
| 1902 | + "id": "vooban", | |
| 1903 | + "name": "Vooban", | |
| 1904 | + "url": "", | |
| 1905 | + "careers_url": "https://job-boards.greenhouse.io/vooban", | |
| 1906 | + "sectors": [ | |
| 1907 | + "TI" | |
| 1908 | + ], | |
| 1909 | + "connector": "greenhouse", | |
| 1910 | + "status": "actif", | |
| 1911 | + "region": "Québec" | |
| 1912 | + }, | |
| 1913 | + { | |
| 1914 | + "id": "bhvr", | |
| 1915 | + "name": "Behaviour Interactif", | |
| 1916 | + "url": "", | |
| 1917 | + "careers_url": "https://jobs.lever.co/bhvr", | |
| 1918 | + "sectors": [ | |
| 1919 | + "Jeux vidéo" | |
| 1920 | + ], | |
| 1921 | + "connector": "lever", | |
| 1922 | + "status": "actif", | |
| 1923 | + "region": "Montréal" | |
| 1924 | + }, | |
| 1925 | + { | |
| 1926 | + "id": "cirquedusoleil", | |
| 1927 | + "name": "Cirque du Soleil", | |
| 1928 | + "url": "https://www.cirquedusoleil.com", | |
| 1929 | + "careers_url": "https://jobs.lever.co/cirquedusoleil", | |
| 1930 | + "sectors": [ | |
| 1931 | + "Divertissement", | |
| 1932 | + "Création" | |
| 1933 | + ], | |
| 1934 | + "connector": "lever", | |
| 1935 | + "status": "actif", | |
| 1936 | + "region": "Montréal" | |
| 1937 | + }, | |
| 1938 | + { | |
| 1939 | + "id": "mirego", | |
| 1940 | + "name": "Mirego", | |
| 1941 | + "url": "", | |
| 1942 | + "careers_url": "https://jobs.lever.co/mirego", | |
| 1943 | + "sectors": [ | |
| 1944 | + "TI" | |
| 1945 | + ], | |
| 1946 | + "connector": "lever", | |
| 1947 | + "status": "actif", | |
| 1948 | + "region": "Québec, Montréal" | |
| 1949 | + }, | |
| 1950 | + { | |
| 1951 | + "id": "spiria", | |
| 1952 | + "name": "Spiria", | |
| 1953 | + "url": "", | |
| 1954 | + "careers_url": "https://jobs.lever.co/spiria", | |
| 1955 | + "sectors": [ | |
| 1956 | + "TI" | |
| 1957 | + ], | |
| 1958 | + "connector": "lever", | |
| 1959 | + "status": "actif", | |
| 1960 | + "region": "Montréal, Gatineau" | |
| 1961 | + }, | |
| 1962 | + { | |
| 1963 | + "id": "amilia", | |
| 1964 | + "name": "Amilia", | |
| 1965 | + "url": "", | |
| 1966 | + "careers_url": "https://amilia.recruitee.com", | |
| 1967 | + "sectors": [ | |
| 1968 | + "TI" | |
| 1969 | + ], | |
| 1970 | + "connector": "recruitee", | |
| 1971 | + "status": "actif", | |
| 1972 | + "region": "Montréal" | |
| 1973 | + }, | |
| 1974 | + { | |
| 1975 | + "id": "gameloft", | |
| 1976 | + "name": "Gameloft", | |
| 1977 | + "url": "https://www.gameloft.com", | |
| 1978 | + "careers_url": "https://jobs.smartrecruiters.com/company/gameloft", | |
| 1979 | + "sectors": [ | |
| 1980 | + "Jeux vidéo" | |
| 1981 | + ], | |
| 1982 | + "connector": "smartrecruiters", | |
| 1983 | + "status": "actif", | |
| 1984 | + "region": "Montréal" | |
| 1985 | + }, | |
| 1986 | + { | |
| 1987 | + "id": "gologic", | |
| 1988 | + "name": "GoLogic", | |
| 1989 | + "url": "", | |
| 1990 | + "careers_url": "https://jobs.smartrecruiters.com/company/gologic", | |
| 1991 | + "sectors": [ | |
| 1992 | + "TI" | |
| 1993 | + ], | |
| 1994 | + "connector": "smartrecruiters", | |
| 1995 | + "status": "actif", | |
| 1996 | + "region": "Montréal" | |
| 1997 | + }, | |
| 1998 | + { | |
| 1999 | + "id": "groupecanam", | |
| 2000 | + "name": "Groupe Canam", | |
| 2001 | + "url": "", | |
| 2002 | + "careers_url": "https://jobs.smartrecruiters.com/company/groupecanam", | |
| 2003 | + "sectors": [ | |
| 2004 | + "Production", | |
| 2005 | + "Construction" | |
| 2006 | + ], | |
| 2007 | + "connector": "smartrecruiters", | |
| 2008 | + "status": "actif", | |
| 2009 | + "region": "Saint-Georges" | |
| 2010 | + }, | |
| 2011 | + { | |
| 2012 | + "id": "playmind", | |
| 2013 | + "name": "Playmind", | |
| 2014 | + "url": "", | |
| 2015 | + "careers_url": "https://jobs.smartrecruiters.com/company/playmind", | |
| 2016 | + "sectors": [ | |
| 2017 | + "Jeux vidéo" | |
| 2018 | + ], | |
| 2019 | + "connector": "smartrecruiters", | |
| 2020 | + "status": "actif", | |
| 2021 | + "region": "Montréal" | |
| 2022 | + }, | |
| 2023 | + { | |
| 2024 | + "id": "qsl", | |
| 2025 | + "name": "QSL", | |
| 2026 | + "url": "https://qsl.com", | |
| 2027 | + "careers_url": "https://jobs.smartrecruiters.com/company/qsl", | |
| 2028 | + "sectors": [], | |
| 2029 | + "connector": "smartrecruiters", | |
| 2030 | + "status": "actif", | |
| 2031 | + "region": "Québec" | |
| 2032 | + }, | |
| 2033 | + { | |
| 2034 | + "id": "stelpro", | |
| 2035 | + "name": "Stelpro", | |
| 2036 | + "url": "", | |
| 2037 | + "careers_url": "https://jobs.smartrecruiters.com/company/stelpro", | |
| 2038 | + "sectors": [ | |
| 2039 | + "Production" | |
| 2040 | + ], | |
| 2041 | + "connector": "smartrecruiters", | |
| 2042 | + "status": "actif", | |
| 2043 | + "region": "Saint-Bruno-de-Montarville" | |
| 2044 | + }, | |
| 2045 | + { | |
| 2046 | + "id": "talsom", | |
| 2047 | + "name": "Talsom", | |
| 2048 | + "url": "", | |
| 2049 | + "careers_url": "https://jobs.smartrecruiters.com/company/talsom", | |
| 2050 | + "sectors": [ | |
| 2051 | + "TI" | |
| 2052 | + ], | |
| 2053 | + "connector": "smartrecruiters", | |
| 2054 | + "status": "actif", | |
| 2055 | + "region": "Montréal" | |
| 2056 | + }, | |
| 2057 | + { | |
| 2058 | + "id": "videotron", | |
| 2059 | + "name": "Vidéotron", | |
| 2060 | + "url": "https://videotron.com", | |
| 2061 | + "careers_url": "https://jobs.smartrecruiters.com/company/videotron", | |
| 2062 | + "sectors": [], | |
| 2063 | + "connector": "smartrecruiters", | |
| 2064 | + "status": "actif", | |
| 2065 | + "region": "Montréal" | |
| 2066 | + }, | |
| 2067 | + { | |
| 2068 | + "id": "vosker", | |
| 2069 | + "name": "Vosker", | |
| 2070 | + "url": "", | |
| 2071 | + "careers_url": "https://jobs.smartrecruiters.com/company/vosker", | |
| 2072 | + "sectors": [ | |
| 2073 | + "TI", | |
| 2074 | + "Production" | |
| 2075 | + ], | |
| 2076 | + "connector": "smartrecruiters", | |
| 2077 | + "status": "actif", | |
| 2078 | + "region": "Victoriaville" | |
| 2079 | + }, | |
| 2080 | + { | |
| 2081 | + "id": "genetec_inc", | |
| 2082 | + "name": "Genetec", | |
| 2083 | + "url": "https://genetec.com", | |
| 2084 | + "careers_url": "https://apply.workable.com/genetec-inc", | |
| 2085 | + "sectors": [], | |
| 2086 | + "connector": "workable", | |
| 2087 | + "status": "actif", | |
| 2088 | + "region": "Montréal" | |
| 2089 | + }, | |
| 2090 | + { | |
| 2091 | + "id": "mila_2", | |
| 2092 | + "name": "Mila — Institut québécois d'IA", | |
| 2093 | + "url": "https://mila.quebec", | |
| 2094 | + "careers_url": "https://apply.workable.com/mila-2", | |
| 2095 | + "sectors": [], | |
| 2096 | + "connector": "workable", | |
| 2097 | + "status": "actif", | |
| 2098 | + "region": "Montréal" | |
| 2099 | + }, | |
| 2100 | + { | |
| 2101 | + "id": "airbus", | |
| 2102 | + "name": "Airbus Canada", | |
| 2103 | + "url": "https://airbus.com", | |
| 2104 | + "careers_url": "https://ag.wd3.myworkdayjobs.com/Airbus", | |
| 2105 | + "sectors": [], | |
| 2106 | + "connector": "workday", | |
| 2107 | + "status": "actif", | |
| 2108 | + "region": "Mirabel" | |
| 2109 | + }, | |
| 2110 | + { | |
| 2111 | + "id": "alcoa", | |
| 2112 | + "name": "Alcoa Canada", | |
| 2113 | + "url": "https://alcoa.com", | |
| 2114 | + "careers_url": "https://alcoa.wd5.myworkdayjobs.com/Careers", | |
| 2115 | + "sectors": [], | |
| 2116 | + "connector": "workday", | |
| 2117 | + "status": "actif", | |
| 2118 | + "region": "Baie-Comeau" | |
| 2119 | + }, | |
| 2120 | + { | |
| 2121 | + "id": "altasciences", | |
| 2122 | + "name": "Altasciences", | |
| 2123 | + "url": "", | |
| 2124 | + "careers_url": "https://altasciences.wd1.myworkdayjobs.com/Careers", | |
| 2125 | + "sectors": [ | |
| 2126 | + "Pharmaceutique" | |
| 2127 | + ], | |
| 2128 | + "connector": "workday", | |
| 2129 | + "status": "actif", | |
| 2130 | + "region": "Laval" | |
| 2131 | + }, | |
| 2132 | + { | |
| 2133 | + "id": "bdc", | |
| 2134 | + "name": "BDC", | |
| 2135 | + "url": "", | |
| 2136 | + "careers_url": "https://bdc.wd10.myworkdayjobs.com/bdc_careers", | |
| 2137 | + "sectors": [ | |
| 2138 | + "Finance" | |
| 2139 | + ], | |
| 2140 | + "connector": "workday", | |
| 2141 | + "status": "actif", | |
| 2142 | + "region": "Montréal" | |
| 2143 | + }, | |
| 2144 | + { | |
| 2145 | + "id": "beneva", | |
| 2146 | + "name": "Beneva", | |
| 2147 | + "url": "https://beneva.ca", | |
| 2148 | + "careers_url": "https://beneva.wd10.myworkdayjobs.com/BenevaSite_carriere", | |
| 2149 | + "sectors": [], | |
| 2150 | + "connector": "workday", | |
| 2151 | + "status": "actif", | |
| 2152 | + "region": "Québec" | |
| 2153 | + }, | |
| 2154 | + { | |
| 2155 | + "id": "caaquebec", | |
| 2156 | + "name": "CAA-Québec", | |
| 2157 | + "url": "https://caaquebec.com", | |
| 2158 | + "careers_url": "https://caaquebec.wd3.myworkdayjobs.com/CarrieresCAA-Quebec", | |
| 2159 | + "sectors": [], | |
| 2160 | + "connector": "workday", | |
| 2161 | + "status": "actif", | |
| 2162 | + "region": "Québec" | |
| 2163 | + }, | |
| 2164 | + { | |
| 2165 | + "id": "canadiantirecorporation", | |
| 2166 | + "name": "Canadian Tire", | |
| 2167 | + "url": "https://canadiantire.ca", | |
| 2168 | + "careers_url": "https://canadiantirecorporation.wd3.myworkdayjobs.com/Enterprise_External_Careers_Site", | |
| 2169 | + "sectors": [], | |
| 2170 | + "connector": "workday", | |
| 2171 | + "status": "actif", | |
| 2172 | + "region": "Montréal" | |
| 2173 | + }, | |
| 2174 | + { | |
| 2175 | + "id": "cdpq", | |
| 2176 | + "name": "CDPQ — Caisse de dépôt et placement du Québec", | |
| 2177 | + "url": "https://cdpq.com", | |
| 2178 | + "careers_url": "https://cdpq.wd10.myworkdayjobs.com/CDPQ", | |
| 2179 | + "sectors": [], | |
| 2180 | + "connector": "workday", | |
| 2181 | + "status": "actif", | |
| 2182 | + "region": "Montréal" | |
| 2183 | + }, | |
| 2184 | + { | |
| 2185 | + "id": "churchdwight", | |
| 2186 | + "name": "Church & Dwight Canada", | |
| 2187 | + "url": "https://churchdwight.ca", | |
| 2188 | + "careers_url": "https://churchdwight.wd1.myworkdayjobs.com/chdcanadacareers", | |
| 2189 | + "sectors": [ | |
| 2190 | + "Production" | |
| 2191 | + ], | |
| 2192 | + "connector": "workday", | |
| 2193 | + "status": "actif", | |
| 2194 | + "region": "" | |
| 2195 | + }, | |
| 2196 | + { | |
| 2197 | + "id": "exfo", | |
| 2198 | + "name": "EXFO", | |
| 2199 | + "url": "", | |
| 2200 | + "careers_url": "https://exfo.wd10.myworkdayjobs.com/exfo_careers", | |
| 2201 | + "sectors": [ | |
| 2202 | + "TI", | |
| 2203 | + "Télécommunications" | |
| 2204 | + ], | |
| 2205 | + "connector": "workday", | |
| 2206 | + "status": "actif", | |
| 2207 | + "region": "Québec" | |
| 2208 | + }, | |
| 2209 | + { | |
| 2210 | + "id": "fondsftq", | |
| 2211 | + "name": "Fonds de solidarité FTQ", | |
| 2212 | + "url": "https://fondsftq.com", | |
| 2213 | + "careers_url": "https://fondsftq.wd10.myworkdayjobs.com/sitecarriere_externe", | |
| 2214 | + "sectors": [], | |
| 2215 | + "connector": "workday", | |
| 2216 | + "status": "actif", | |
| 2217 | + "region": "Montréal" | |
| 2218 | + }, | |
| 2219 | + { | |
| 2220 | + "id": "intactfc", | |
| 2221 | + "name": "Intact Corporation financière", | |
| 2222 | + "url": "", | |
| 2223 | + "careers_url": "https://intactfc.wd3.myworkdayjobs.com/Intactfc", | |
| 2224 | + "sectors": [ | |
| 2225 | + "Assurance" | |
| 2226 | + ], | |
| 2227 | + "connector": "workday", | |
| 2228 | + "status": "actif", | |
| 2229 | + "region": "Montréal" | |
| 2230 | + }, | |
| 2231 | + { | |
| 2232 | + "id": "investpsp", | |
| 2233 | + "name": "Investissements PSP", | |
| 2234 | + "url": "https://investpsp.com", | |
| 2235 | + "careers_url": "https://investpsp.wd3.myworkdayjobs.com/psp_careers", | |
| 2236 | + "sectors": [], | |
| 2237 | + "connector": "workday", | |
| 2238 | + "status": "actif", | |
| 2239 | + "region": "Montréal" | |
| 2240 | + }, | |
| 2241 | + { | |
| 2242 | + "id": "investquebec", | |
| 2243 | + "name": "Investissement Québec", | |
| 2244 | + "url": "https://investquebec.com", | |
| 2245 | + "careers_url": "https://investquebec.wd10.myworkdayjobs.com/Ext", | |
| 2246 | + "sectors": [], | |
| 2247 | + "connector": "workday", | |
| 2248 | + "status": "actif", | |
| 2249 | + "region": "Québec" | |
| 2250 | + }, | |
| 2251 | + { | |
| 2252 | + "id": "plusgrade", | |
| 2253 | + "name": "Plusgrade", | |
| 2254 | + "url": "https://plusgrade.com", | |
| 2255 | + "careers_url": "https://plusgrade.wd10.myworkdayjobs.com/Plusgrade_External_Site", | |
| 2256 | + "sectors": [], | |
| 2257 | + "connector": "workday", | |
| 2258 | + "status": "actif", | |
| 2259 | + "region": "Montréal" | |
| 2260 | + }, | |
| 2261 | + { | |
| 2262 | + "id": "promutuel", | |
| 2263 | + "name": "Promutuel Assurance", | |
| 2264 | + "url": "https://promutuelassurance.ca", | |
| 2265 | + "careers_url": "https://promutuel.wd3.myworkdayjobs.com/promutuel_carrieres", | |
| 2266 | + "sectors": [], | |
| 2267 | + "connector": "workday", | |
| 2268 | + "status": "actif", | |
| 2269 | + "region": "Québec" | |
| 2270 | + }, | |
| 2271 | + { | |
| 2272 | + "id": "rcgt", | |
| 2273 | + "name": "Raymond Chabot Grant Thornton", | |
| 2274 | + "url": "https://rcgt.com", | |
| 2275 | + "careers_url": "https://rcgt.wd3.myworkdayjobs.com/External", | |
| 2276 | + "sectors": [], | |
| 2277 | + "connector": "workday", | |
| 2278 | + "status": "actif", | |
| 2279 | + "region": "Montréal" | |
| 2280 | + }, | |
| 2281 | + { | |
| 2282 | + "id": "riotinto", | |
| 2283 | + "name": "Rio Tinto", | |
| 2284 | + "url": "", | |
| 2285 | + "careers_url": "https://riotinto.wd3.myworkdayjobs.com/riotinto_careers", | |
| 2286 | + "sectors": [ | |
| 2287 | + "Mines" | |
| 2288 | + ], | |
| 2289 | + "connector": "workday", | |
| 2290 | + "status": "actif", | |
| 2291 | + "region": "Saguenay, Montréal" | |
| 2292 | + }, | |
| 2293 | + { | |
| 2294 | + "id": "suncor", | |
| 2295 | + "name": "Suncor Énergie", | |
| 2296 | + "url": "https://suncor.com", | |
| 2297 | + "careers_url": "https://suncor.wd1.myworkdayjobs.com/Suncor_External", | |
| 2298 | + "sectors": [], | |
| 2299 | + "connector": "workday", | |
| 2300 | + "status": "actif", | |
| 2301 | + "region": "Montréal" | |
| 2302 | + }, | |
| 2303 | + { | |
| 2304 | + "id": "walmart", | |
| 2305 | + "name": "Walmart Canada", | |
| 2306 | + "url": "https://walmart.ca", | |
| 2307 | + "careers_url": "https://walmart.wd504.myworkdayjobs.com/WalmartExternal", | |
| 2308 | + "sectors": [], | |
| 2309 | + "connector": "workday", | |
| 2310 | + "status": "actif", | |
| 2311 | + "region": "Montréal" | |
| 2312 | + }, | |
| 2313 | + { | |
| 2314 | + "id": "agnico_eagle", | |
| 2315 | + "name": "Agnico Eagle Mines", | |
| 2316 | + "url": "https://www.agnicoeagle.com", | |
| 2317 | + "careers_url": "https://agnicoeagle.taleo.net/careersection/2/jobsearch.ftl?lang=fr", | |
| 2318 | + "sectors": [ | |
| 2319 | + "Mines", | |
| 2320 | + "Ingénierie", | |
| 2321 | + "Métiers spécialisés" | |
| 2322 | + ], | |
| 2323 | + "connector": "taleo", | |
| 2324 | + "status": "actif", | |
| 2325 | + "region": "Abitibi-Témiscamingue, Malartic, Rouyn-Noranda" | |
| 2326 | + }, | |
| 2327 | + { | |
| 2328 | + "id": "ciusss_est_montreal", | |
| 2329 | + "name": "CIUSSS de l'Est-de-l'Île-de-Montréal", | |
| 2330 | + "url": "https://ciusss-estmtl.gouv.qc.ca", | |
| 2331 | + "careers_url": "https://ciusssemtl.taleo.net/careersection/cemtl/jobsearch.ftl?lang=fr", | |
| 2332 | + "sectors": [ | |
| 2333 | + "Santé", | |
| 2334 | + "Services sociaux", | |
| 2335 | + "Secteur public" | |
| 2336 | + ], | |
| 2337 | + "connector": "taleo", | |
| 2338 | + "status": "actif", | |
| 2339 | + "region": "Montréal" | |
| 2340 | + }, | |
| 2341 | + { | |
| 2342 | + "id": "bayshore", | |
| 2343 | + "name": "Bayshore HealthCare", | |
| 2344 | + "url": "https://www.bayshore.ca", | |
| 2345 | + "careers_url": "https://bayshore.taleo.net/careersection/bs_ex/jobsearch.ftl?lang=fr", | |
| 2346 | + "sectors": [ | |
| 2347 | + "Santé", | |
| 2348 | + "Soins à domicile" | |
| 2349 | + ], | |
| 2350 | + "connector": "taleo", | |
| 2351 | + "status": "actif", | |
| 2352 | + "region": "Montréal, Québec" | |
| 2353 | + }, | |
| 2354 | + { | |
| 2355 | + "id": "bell_textron", | |
| 2356 | + "name": "Bell Textron Canada", | |
| 2357 | + "url": "https://www.bellflight.com", | |
| 2358 | + "careers_url": "https://textron.taleo.net/careersection/bell/jobsearch.ftl?lang=fr", | |
| 2359 | + "sectors": [ | |
| 2360 | + "Aéronautique", | |
| 2361 | + "Fabrication" | |
| 2362 | + ], | |
| 2363 | + "connector": "taleo", | |
| 2364 | + "status": "actif", | |
| 2365 | + "region": "Mirabel" | |
| 2366 | + }, | |
| 2367 | + { | |
| 2368 | + "id": "sante_montreal", | |
| 2369 | + "name": "Santé Québec — Montréal", | |
| 2370 | + "url": "https://santemontreal.ca", | |
| 2371 | + "careers_url": "https://emplois.santemontreal.qc.ca/CL3/xweb/xweb.asp?clid=54327&page=joblisting&lang=2", | |
| 2372 | + "sectors": [ | |
| 2373 | + "Santé", | |
| 2374 | + "Services sociaux", | |
| 2375 | + "Secteur public" | |
| 2376 | + ], | |
| 2377 | + "connector": "njoyn", | |
| 2378 | + "status": "actif", | |
| 2379 | + "region": "Montréal" | |
| 2380 | + }, | |
| 2381 | + { | |
| 2382 | + "id": "ville_gatineau", | |
| 2383 | + "name": "Ville de Gatineau", | |
| 2384 | + "url": "https://www.gatineau.ca", | |
| 2385 | + "careers_url": "https://gatineau.njoyn.com/CL2/xweb/xweb.asp?clid=27082&page=joblisting&lang=2", | |
| 2386 | + "sectors": [ | |
| 2387 | + "Municipal", | |
| 2388 | + "Secteur public" | |
| 2389 | + ], | |
| 2390 | + "connector": "njoyn", | |
| 2391 | + "status": "actif", | |
| 2392 | + "region": "Gatineau" | |
| 2393 | + }, | |
| 2394 | + { | |
| 2395 | + "id": "ville_terrebonne", | |
| 2396 | + "name": "Ville de Terrebonne", | |
| 2397 | + "url": "https://www.ville.terrebonne.qc.ca", | |
| 2398 | + "careers_url": "https://clients.njoyn.com/cl4/xweb/xweb.asp?clid=71764&page=joblisting&lang=2", | |
| 2399 | + "sectors": [ | |
| 2400 | + "Municipal", | |
| 2401 | + "Secteur public" | |
| 2402 | + ], | |
| 2403 | + "connector": "njoyn", | |
| 2404 | + "status": "actif", | |
| 2405 | + "region": "Terrebonne" | |
| 2406 | + }, | |
| 2407 | + { | |
| 2408 | + "id": "stl_laval", | |
| 2409 | + "name": "Société de transport de Laval", | |
| 2410 | + "url": "https://www.stlaval.ca", | |
| 2411 | + "careers_url": "https://lavaltransit.njoyn.com/CL2/xweb/xweb.asp?clid=60406&page=joblisting&lang=2", | |
| 2412 | + "sectors": [ | |
| 2413 | + "Transport collectif", | |
| 2414 | + "Secteur public" | |
| 2415 | + ], | |
| 2416 | + "connector": "njoyn", | |
| 2417 | + "status": "actif", | |
| 2418 | + "region": "Laval" | |
| 2419 | + }, | |
| 2420 | + { | |
| 2421 | + "id": "rtc_quebec", | |
| 2422 | + "name": "Réseau de transport de la Capitale", | |
| 2423 | + "url": "https://www.rtcquebec.ca", | |
| 2424 | + "careers_url": "https://rtc.njoyn.com/CGI/xweb/xweb.asp?clid=23009&page=joblisting&lang=2", | |
| 2425 | + "sectors": [ | |
| 2426 | + "Transport collectif", | |
| 2427 | + "Secteur public" | |
| 2428 | + ], | |
| 2429 | + "connector": "njoyn", | |
| 2430 | + "status": "actif", | |
| 2431 | + "region": "Québec" | |
| 2432 | + }, | |
| 2433 | + { | |
| 2434 | + "id": "messer_canada", | |
| 2435 | + "name": "Messer Canada", | |
| 2436 | + "url": "https://www.messer-ca.com", | |
| 2437 | + "careers_url": "https://recruiting.ultipro.com/MES1005MESR/JobBoard/dbd63926-d756-486f-a254-b2a6ede1d26e", | |
| 2438 | + "sectors": [ | |
| 2439 | + "Gaz industriels", | |
| 2440 | + "Industrie" | |
| 2441 | + ], | |
| 2442 | + "connector": "ultipro", | |
| 2443 | + "status": "actif", | |
| 2444 | + "region": "Montréal, Québec, Saint-Georges" | |
| 2445 | + }, | |
| 2446 | + { | |
| 2447 | + "id": "capreit", | |
| 2448 | + "name": "CAPREIT", | |
| 2449 | + "url": "https://www.capreit.ca", | |
| 2450 | + "careers_url": "https://careers-capreit.icims.com/jobs/search?ss=1", | |
| 2451 | + "sectors": [ | |
| 2452 | + "Immobilier", | |
| 2453 | + "Gestion immobilière" | |
| 2454 | + ], | |
| 2455 | + "connector": "icims", | |
| 2456 | + "status": "actif", | |
| 2457 | + "region": "Montréal" | |
| 2458 | + }, | |
| 2459 | + { | |
| 2460 | + "id": "mccarthy_tetrault", | |
| 2461 | + "name": "McCarthy Tétrault", | |
| 2462 | + "url": "https://www.mccarthy.ca", | |
| 2463 | + "careers_url": "https://careers-mccarthyca.icims.com/jobs/search?ss=1", | |
| 2464 | + "sectors": [ | |
| 2465 | + "Juridique", | |
| 2466 | + "Services professionnels" | |
| 2467 | + ], | |
| 2468 | + "connector": "icims", | |
| 2469 | + "status": "actif", | |
| 2470 | + "region": "Montréal, Québec" | |
| 2471 | + }, | |
| 2472 | + { | |
| 2473 | + "id": "omni_hotels_horaire", | |
| 2474 | + "name": "Omni Hôtel Mont-Royal", | |
| 2475 | + "url": "https://www.omnihotels.com/fr/hotels/montreal-mont-royal", | |
| 2476 | + "careers_url": "https://externalhourly-omnihotels.icims.com/jobs/search?ss=1", | |
| 2477 | + "sectors": [ | |
| 2478 | + "Hôtellerie", | |
| 2479 | + "Restauration" | |
| 2480 | + ], | |
| 2481 | + "connector": "icims", | |
| 2482 | + "status": "actif", | |
| 2483 | + "region": "Montréal" | |
| 2484 | + }, | |
| 2485 | + { | |
| 2486 | + "id": "omni_hotels_gestion", | |
| 2487 | + "name": "Omni Hôtel Mont-Royal", | |
| 2488 | + "url": "https://www.omnihotels.com/fr/hotels/montreal-mont-royal", | |
| 2489 | + "careers_url": "https://externalmanager-omnihotels.icims.com/jobs/search?ss=1", | |
| 2490 | + "sectors": [ | |
| 2491 | + "Hôtellerie", | |
| 2492 | + "Gestion" | |
| 2493 | + ], | |
| 2494 | + "connector": "icims", | |
| 2495 | + "status": "actif", | |
| 2496 | + "region": "Montréal" | |
| 2497 | + }, | |
| 2498 | + { | |
| 2499 | + "id": "edf_renouvelables", | |
| 2500 | + "name": "EDF Renouvelables Canada", | |
| 2501 | + "url": "https://www.edf-renouvelables.ca", | |
| 2502 | + "careers_url": "https://cafrench-edf-re.icims.com/jobs/search?ss=1", | |
| 2503 | + "sectors": [ | |
| 2504 | + "Énergie", | |
| 2505 | + "Ingénierie" | |
| 2506 | + ], | |
| 2507 | + "connector": "icims", | |
| 2508 | + "status": "actif", | |
| 2509 | + "region": "Montréal" | |
| 2510 | + }, | |
| 2511 | + { | |
| 2512 | + "id": "bombardier", | |
| 2513 | + "name": "Bombardier", | |
| 2514 | + "url": "https://bombardier.com", | |
| 2515 | + "careers_url": "https://jobs.bombardier.com", | |
| 2516 | + "sectors": [ | |
| 2517 | + "Aéronautique", | |
| 2518 | + "Ingénierie", | |
| 2519 | + "Fabrication" | |
| 2520 | + ], | |
| 2521 | + "connector": "successfactors", | |
| 2522 | + "status": "actif", | |
| 2523 | + "region": "Dorval, Mirabel, Montréal" | |
| 2524 | + }, | |
| 2525 | + { | |
| 2526 | + "id": "domtar", | |
| 2527 | + "name": "Domtar", | |
| 2528 | + "url": "https://www.domtar.com", | |
| 2529 | + "careers_url": "https://jobs.domtar.com", | |
| 2530 | + "sectors": [ | |
| 2531 | + "Pâtes et papiers", | |
| 2532 | + "Foresterie", | |
| 2533 | + "Fabrication" | |
| 2534 | + ], | |
| 2535 | + "connector": "successfactors", | |
| 2536 | + "status": "actif", | |
| 2537 | + "region": "Montréal, Windsor, Lachine" | |
| 2538 | + }, | |
| 2539 | + { | |
| 2540 | + "id": "cascades", | |
| 2541 | + "name": "Cascades", | |
| 2542 | + "url": "https://www.cascades.com", | |
| 2543 | + "careers_url": "https://jobs.cascades.com", | |
| 2544 | + "sectors": [ | |
| 2545 | + "Pâtes et papiers", | |
| 2546 | + "Emballage", | |
| 2547 | + "Fabrication" | |
| 2548 | + ], | |
| 2549 | + "connector": "successfactors", | |
| 2550 | + "status": "actif", | |
| 2551 | + "region": "Kingsey Falls, Drummondville, Candiac" | |
| 2552 | + }, | |
| 2553 | + { | |
| 2554 | + "id": "lassonde", | |
| 2555 | + "name": "Industries Lassonde", | |
| 2556 | + "url": "https://www.lassonde.com", | |
| 2557 | + "careers_url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=f96ce972-7721-4c7b-99ea-9a970ddc824a&ccId=19000101_000001&lang=fr_CA", | |
| 2558 | + "sectors": [ | |
| 2559 | + "Agroalimentaire", | |
| 2560 | + "Fabrication" | |
| 2561 | + ], | |
| 2562 | + "connector": "adp", | |
| 2563 | + "status": "actif", | |
| 2564 | + "region": "Rougemont, Montréal" | |
| 2565 | + }, | |
| 2566 | + { | |
| 2567 | + "id": "mitsubishi_hc_capital", | |
| 2568 | + "name": "Mitsubishi HC Capital Canada", | |
| 2569 | + "url": "https://www.mhccna.com", | |
| 2570 | + "careers_url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=b3ef4f03-f8ff-4ded-80c8-6dd5c5a224f7&ccId=9200144510729_2&lang=fr_CA", | |
| 2571 | + "sectors": [ | |
| 2572 | + "Finance", | |
| 2573 | + "Financement commercial" | |
| 2574 | + ], | |
| 2575 | + "connector": "adp", | |
| 2576 | + "status": "actif", | |
| 2577 | + "region": "Laval, Trois-Rivières" | |
| 2578 | + }, | |
| 2579 | + { | |
| 2580 | + "id": "msi_gestion", | |
| 2581 | + "name": "MSI Gestion immobilière", | |
| 2582 | + "url": "https://www.msimmobiliers.com", | |
| 2583 | + "careers_url": "https://workforcenow.adp.com/mascsr/default/mdf/recruitment/recruitment.html?cid=47d4e792-26e5-471c-92ac-73c60131bab8&ccId=19000101_000001&lang=fr_CA", | |
| 2584 | + "sectors": [ | |
| 2585 | + "Immobilier", | |
| 2586 | + "Gestion immobilière" | |
| 2587 | + ], | |
| 2588 | + "connector": "adp", | |
| 2589 | + "status": "actif", | |
| 2590 | + "region": "Montréal" | |
| 2591 | + }, | |
| 2592 | + { | |
| 2593 | + "id": "sante_quebec", | |
| 2594 | + "name": "Santé Québec", | |
| 2595 | + "url": "https://sante.quebec", | |
| 2596 | + "careers_url": "https://emplois.sante.quebec", | |
| 2597 | + "sectors": [ | |
| 2598 | + "Santé", | |
| 2599 | + "Secteur public", | |
| 2600 | + "Administration" | |
| 2601 | + ], | |
| 2602 | + "connector": "digitalrecruiters", | |
| 2603 | + "status": "actif", | |
| 2604 | + "region": "Montréal, Québec" | |
| 2605 | + }, | |
| 2606 | + { | |
| 2607 | + "id": "cssdm", | |
| 2608 | + "name": "Centre de services scolaire de Montréal", | |
| 2609 | + "url": "https://www.cssdm.gouv.qc.ca", | |
| 2610 | + "careers_url": "https://www.cssdm.gouv.qc.ca/travailler-cssdm/offres-emploi/", | |
| 2611 | + "sectors": [ | |
| 2612 | + "Éducation", | |
| 2613 | + "Secteur public" | |
| 2614 | + ], | |
| 2615 | + "connector": "workland", | |
| 2616 | + "status": "actif", | |
| 2617 | + "region": "Montréal" | |
| 2618 | + }, | |
| 2619 | + { | |
| 2620 | + "id": "guichet_emplois", | |
| 2621 | + "name": "Guichet-Emplois (Canada)", | |
| 2622 | + "url": "https://www.guichetemplois.gc.ca", | |
| 2623 | + "careers_url": "https://www.guichetemplois.gc.ca/jobsearch/rechercheemplois?fprov=QC", | |
| 2624 | + "sectors": [ | |
| 2625 | + "Portail", | |
| 2626 | + "Tous secteurs" | |
| 2627 | + ], | |
| 2628 | + "connector": "portail", | |
| 2629 | + "status": "actif", | |
| 2630 | + "region": "Québec (province)", | |
| 2631 | + "aggregator": true | |
| 2632 | + }, | |
| 2633 | + { | |
| 2634 | + "id": "jobillico", | |
| 2635 | + "name": "Jobillico", | |
| 2636 | + "url": "https://www.jobillico.com", | |
| 2637 | + "careers_url": "https://www.jobillico.com/recherche-emploi", | |
| 2638 | + "sectors": [ | |
| 2639 | + "Portail", | |
| 2640 | + "Tous secteurs" | |
| 2641 | + ], | |
| 2642 | + "connector": "portail", | |
| 2643 | + "status": "actif", | |
| 2644 | + "region": "Québec (province)", | |
| 2645 | + "aggregator": true | |
| 2646 | + }, | |
| 2647 | + { | |
| 2648 | + "id": "espresso_jobs", | |
| 2649 | + "name": "Espresso-Jobs", | |
| 2650 | + "url": "https://www.espresso-jobs.com", | |
| 2651 | + "careers_url": "https://www.espresso-jobs.com/emploi", | |
| 2652 | + "sectors": [ | |
| 2653 | + "Portail", | |
| 2654 | + "TI", | |
| 2655 | + "Créatif" | |
| 2656 | + ], | |
| 2657 | + "connector": "portail", | |
| 2658 | + "status": "actif", | |
| 2659 | + "region": "Québec (province)", | |
| 2660 | + "aggregator": true | |
| 2661 | + }, | |
| 2662 | + { | |
| 2663 | + "id": "depot-direct", | |
| 2664 | + "name": "Dépôt direct employeurs", | |
| 2665 | + "url": "https://www.job-ka.com/employeurs", | |
| 2666 | + "careers_url": "https://www.job-ka.com/employeurs", | |
| 2667 | + "sectors": [ | |
| 2668 | + "Tous secteurs" | |
| 2669 | + ], | |
| 2670 | + "connector": "depot-direct", | |
| 2671 | + "status": "modération", | |
| 2672 | + "region": "Québec (province)" | |
| 2673 | + }, | |
| 2674 | + { | |
| 2675 | + "id": "mxo", | |
| 2676 | + "name": "MXO", | |
| 2677 | + "url": "https://mxoconseil.com", | |
| 2678 | + "careers_url": "https://mxo.bamboohr.com/careers", | |
| 2679 | + "sectors": [ | |
| 2680 | + "manufacturier/commerce" | |
| 2681 | + ], | |
| 2682 | + "connector": "bamboohr", | |
| 2683 | + "status": "actif", | |
| 2684 | + "region": "" | |
| 2685 | + }, | |
| 2686 | + { | |
| 2687 | + "id": "pouletrouge", | |
| 2688 | + "name": "Poulet Rouge", | |
| 2689 | + "url": "https://poulet-rouge.ca", | |
| 2690 | + "careers_url": "https://pouletrouge.bamboohr.com/careers", | |
| 2691 | + "sectors": [ | |
| 2692 | + "restauration" | |
| 2693 | + ], | |
| 2694 | + "connector": "bamboohr", | |
| 2695 | + "status": "actif", | |
| 2696 | + "region": "Montréal" | |
| 2697 | + }, | |
| 2698 | + { | |
| 2699 | + "id": "ziptrekeco", | |
| 2700 | + "name": "Ziptrek Tremblant", | |
| 2701 | + "url": "https://tremblant.ziptrek.com", | |
| 2702 | + "careers_url": "https://ziptrekeco.bamboohr.com/careers", | |
| 2703 | + "sectors": [ | |
| 2704 | + "manufacturier/commerce" | |
| 2705 | + ], | |
| 2706 | + "connector": "bamboohr", | |
| 2707 | + "status": "actif", | |
| 2708 | + "region": "" | |
| 2709 | + }, | |
| 2710 | + { | |
| 2711 | + "id": "jgrivesud", | |
| 2712 | + "name": "JG Rive-Sud (GFS)", | |
| 2713 | + "url": "https://jgfruitsetlegumes.com", | |
| 2714 | + "careers_url": "https://gfs.wd5.myworkdayjobs.com/jgrive-sud", | |
| 2715 | + "sectors": [ | |
| 2716 | + "manufacturier/commerce" | |
| 2717 | + ], | |
| 2718 | + "connector": "workday", | |
| 2719 | + "status": "actif", | |
| 2720 | + "region": "" | |
| 2721 | + }, | |
| 2722 | + { | |
| 2723 | + "id": "gfs", | |
| 2724 | + "name": "Service alimentaire Gordon", | |
| 2725 | + "url": "https://gfs.ca", | |
| 2726 | + "careers_url": "https://gfs.wd5.myworkdayjobs.com/usjobs-french", | |
| 2727 | + "sectors": [ | |
| 2728 | + "manufacturier/commerce" | |
| 2729 | + ], | |
| 2730 | + "connector": "workday", | |
| 2731 | + "status": "actif", | |
| 2732 | + "region": "" | |
| 2733 | + }, | |
| 2734 | + { | |
| 2735 | + "id": "scottsmiraclegro", | |
| 2736 | + "name": "Scotts Canada (Fafard)", | |
| 2737 | + "url": "https://scottsmiraclegro.com", | |
| 2738 | + "careers_url": "https://scottsmiraclegro.wd5.myworkdayjobs.com/SMGExternal", | |
| 2739 | + "sectors": [ | |
| 2740 | + "manufacturier/commerce" | |
| 2741 | + ], | |
| 2742 | + "connector": "workday", | |
| 2743 | + "status": "actif", | |
| 2744 | + "region": "" | |
| 2745 | + }, | |
| 2746 | + { | |
| 2747 | + "id": "sleeman", | |
| 2748 | + "name": "Brasseries Sleeman (Unibroue)", | |
| 2749 | + "url": "https://unibroue.com", | |
| 2750 | + "careers_url": "https://sleeman.wd3.myworkdayjobs.com/SBL", | |
| 2751 | + "sectors": [ | |
| 2752 | + "manufacturier/commerce" | |
| 2753 | + ], | |
| 2754 | + "connector": "workday", | |
| 2755 | + "status": "actif", | |
| 2756 | + "region": "" | |
| 1717 | 2757 | } |
| 1718 | 2758 | ] |
| 1719 | 2759 | } |
added
jobka/connectors/airbus.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/airbus.py | |
| 6 | +# Rôle : Connecteur Airbus Canada — workday (tenant ag.wd3, site Airbus) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class AirbusConnector(WorkdayConnector): | |
| 14 | + source_id = 'airbus' | |
| 15 | + EMPLOYER = 'Airbus Canada' | |
| 16 | + TENANT = 'ag' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'Airbus' | |
added
jobka/connectors/alayacare.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/alayacare.py | |
| 6 | +# Rôle : Connecteur AlayaCare — greenhouse (org « alayacare ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class AlayacareConnector(GreenhouseConnector): | |
| 14 | + source_id = 'alayacare' | |
| 15 | + EMPLOYER = 'AlayaCare' | |
| 16 | + BOARD = 'alayacare' | |
added
jobka/connectors/alcoa.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/alcoa.py | |
| 6 | +# Rôle : Connecteur Alcoa Canada — workday (tenant alcoa.wd5, site Careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class AlcoaConnector(WorkdayConnector): | |
| 14 | + source_id = 'alcoa' | |
| 15 | + EMPLOYER = 'Alcoa Canada' | |
| 16 | + TENANT = 'alcoa' | |
| 17 | + HOST = 'wd5' | |
| 18 | + SITE = 'Careers' | |
added
jobka/connectors/altasciences.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/altasciences.py | |
| 6 | +# Rôle : Connecteur Altasciences — workday (tenant altasciences.wd1, site Careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class AltasciencesConnector(WorkdayConnector): | |
| 14 | + source_id = 'altasciences' | |
| 15 | + EMPLOYER = 'Altasciences' | |
| 16 | + TENANT = 'altasciences' | |
| 17 | + HOST = 'wd1' | |
| 18 | + SITE = 'Careers' | |
added
jobka/connectors/amilia.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/amilia.py | |
| 6 | +# Rôle : Connecteur Amilia — recruitee (org « amilia ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .recruitee import RecruiteeConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class AmiliaConnector(RecruiteeConnector): | |
| 14 | + source_id = 'amilia' | |
| 15 | + EMPLOYER = 'Amilia' | |
| 16 | + ORG = 'amilia' | |
added
jobka/connectors/bdc.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/bdc.py | |
| 6 | +# Rôle : Connecteur BDC — workday (tenant bdc.wd10, site bdc_careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class BdcConnector(WorkdayConnector): | |
| 14 | + source_id = 'bdc' | |
| 15 | + EMPLOYER = 'BDC' | |
| 16 | + TENANT = 'bdc' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'bdc_careers' | |
added
jobka/connectors/beneva.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/beneva.py | |
| 6 | +# Rôle : Connecteur Beneva — workday (tenant beneva.wd10, site BenevaSite_carriere) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class BenevaConnector(WorkdayConnector): | |
| 14 | + source_id = 'beneva' | |
| 15 | + EMPLOYER = 'Beneva' | |
| 16 | + TENANT = 'beneva' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'BenevaSite_carriere' | |
added
jobka/connectors/bhvr.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/bhvr.py | |
| 6 | +# Rôle : Connecteur Behaviour Interactif — lever (org « bhvr ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .lever import LeverConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class BhvrConnector(LeverConnector): | |
| 14 | + source_id = 'bhvr' | |
| 15 | + EMPLOYER = 'Behaviour Interactif' | |
| 16 | + ORG = 'bhvr' | |
added
jobka/connectors/bigbang.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/bigbang.py | |
| 6 | +# Rôle : Connecteur Big Bang — bamboohr (org « bigbang ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class BigbangConnector(BambooHRConnector): | |
| 14 | + source_id = 'bigbang' | |
| 15 | + EMPLOYER = 'Big Bang' | |
| 16 | + ORG = 'bigbang' | |
added
jobka/connectors/broccolini.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/broccolini.py | |
| 6 | +# Rôle : Connecteur Broccolini — bamboohr (org « broccolini ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class BroccoliniConnector(BambooHRConnector): | |
| 14 | + source_id = 'broccolini' | |
| 15 | + EMPLOYER = 'Broccolini' | |
| 16 | + ORG = 'broccolini' | |
added
jobka/connectors/caaquebec.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/caaquebec.py | |
| 6 | +# Rôle : Connecteur CAA-Québec — workday (tenant caaquebec.wd3, site CarrieresCAA-Quebec) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class CaaquebecConnector(WorkdayConnector): | |
| 14 | + source_id = 'caaquebec' | |
| 15 | + EMPLOYER = 'CAA-Québec' | |
| 16 | + TENANT = 'caaquebec' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'CarrieresCAA-Quebec' | |
added
jobka/connectors/canadiantirecorporation.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/canadiantirecorporation.py | |
| 6 | +# Rôle : Connecteur Canadian Tire — workday (tenant canadiantirecorporation.wd3, site Enterprise_External_Careers_Site) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class CanadiantirecorporationConnector(WorkdayConnector): | |
| 14 | + source_id = 'canadiantirecorporation' | |
| 15 | + EMPLOYER = 'Canadian Tire' | |
| 16 | + TENANT = 'canadiantirecorporation' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'Enterprise_External_Careers_Site' | |
added
jobka/connectors/cdpq.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/cdpq.py | |
| 6 | +# Rôle : Connecteur CDPQ — Caisse de dépôt et placement du Québec — workday (tenant cdpq.wd10, site CDPQ) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class CdpqConnector(WorkdayConnector): | |
| 14 | + source_id = 'cdpq' | |
| 15 | + EMPLOYER = 'CDPQ — Caisse de dépôt et placement du Québec' | |
| 16 | + TENANT = 'cdpq' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'CDPQ' | |
added
jobka/connectors/churchdwight.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/churchdwight.py | |
| 6 | +# Rôle : Connecteur Church & Dwight Canada — workday (tenant churchdwight.wd1, site chdcanadacareers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class ChurchdwightConnector(WorkdayConnector): | |
| 14 | + source_id = 'churchdwight' | |
| 15 | + EMPLOYER = 'Church & Dwight Canada' | |
| 16 | + TENANT = 'churchdwight' | |
| 17 | + HOST = 'wd1' | |
| 18 | + SITE = 'chdcanadacareers' | |
added
jobka/connectors/cirquedusoleil.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/cirquedusoleil.py | |
| 6 | +# Rôle : Connecteur Cirque du Soleil — lever (org « cirquedusoleil ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .lever import LeverConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class CirquedusoleilConnector(LeverConnector): | |
| 14 | + source_id = 'cirquedusoleil' | |
| 15 | + EMPLOYER = 'Cirque du Soleil' | |
| 16 | + ORG = 'cirquedusoleil' | |
added
jobka/connectors/cordonbleu.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/cordonbleu.py | |
| 6 | +# Rôle : Connecteur Aliments Ouimet-Cordon Bleu inc. — bamboohr (org « cordonbleu ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class CordonbleuConnector(BambooHRConnector): | |
| 14 | + source_id = 'cordonbleu' | |
| 15 | + EMPLOYER = 'Aliments Ouimet-Cordon Bleu inc.' | |
| 16 | + ORG = 'cordonbleu' | |
added
jobka/connectors/devimco.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/devimco.py | |
| 6 | +# Rôle : Connecteur Devimco Appartements — bamboohr (org « devimco ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class DevimcoConnector(BambooHRConnector): | |
| 14 | + source_id = 'devimco' | |
| 15 | + EMPLOYER = 'Devimco Appartements' | |
| 16 | + ORG = 'devimco' | |
added
jobka/connectors/evlo.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/evlo.py | |
| 6 | +# Rôle : Connecteur EVLO (Hydro-Québec) — bamboohr (org « evlo ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class EvloConnector(BambooHRConnector): | |
| 14 | + source_id = 'evlo' | |
| 15 | + EMPLOYER = 'EVLO (Hydro-Québec)' | |
| 16 | + ORG = 'evlo' | |
added
jobka/connectors/exfo.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/exfo.py | |
| 6 | +# Rôle : Connecteur EXFO — workday (tenant exfo.wd10, site exfo_careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class ExfoConnector(WorkdayConnector): | |
| 14 | + source_id = 'exfo' | |
| 15 | + EMPLOYER = 'EXFO' | |
| 16 | + TENANT = 'exfo' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'exfo_careers' | |
added
jobka/connectors/fenetresconcept.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/fenetresconcept.py | |
| 6 | +# Rôle : Connecteur Fenêtres Concept — bamboohr (org « fenetresconcept ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class FenetresconceptConnector(BambooHRConnector): | |
| 14 | + source_id = 'fenetresconcept' | |
| 15 | + EMPLOYER = 'Fenêtres Concept' | |
| 16 | + ORG = 'fenetresconcept' | |
added
jobka/connectors/flare.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/flare.py | |
| 6 | +# Rôle : Connecteur Flare (cybersécurité) — bamboohr (org « flare ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class FlareConnector(BambooHRConnector): | |
| 14 | + source_id = 'flare' | |
| 15 | + EMPLOYER = 'Flare (cybersécurité)' | |
| 16 | + ORG = 'flare' | |
added
jobka/connectors/fondsftq.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/fondsftq.py | |
| 6 | +# Rôle : Connecteur Fonds de solidarité FTQ — workday (tenant fondsftq.wd10, site sitecarriere_externe) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class FondsftqConnector(WorkdayConnector): | |
| 14 | + source_id = 'fondsftq' | |
| 15 | + EMPLOYER = 'Fonds de solidarité FTQ' | |
| 16 | + TENANT = 'fondsftq' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'sitecarriere_externe' | |
added
jobka/connectors/gameloft.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/gameloft.py | |
| 6 | +# Rôle : Connecteur Gameloft — smartrecruiters (org « gameloft ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GameloftConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'gameloft' | |
| 15 | + EMPLOYER = 'Gameloft' | |
| 16 | + COMPANY = 'gameloft' | |
added
jobka/connectors/genetec_inc.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/genetec_inc.py | |
| 6 | +# Rôle : Connecteur Genetec — workable (org « genetec-inc ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workable import WorkableConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GenetecIncConnector(WorkableConnector): | |
| 14 | + source_id = 'genetec_inc' | |
| 15 | + EMPLOYER = 'Genetec' | |
| 16 | + ORG = 'genetec-inc' | |
added
jobka/connectors/gfs.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/gfs.py | |
| 6 | +# Rôle : Connecteur Service alimentaire Gordon — workday (tenant gfs.wd5, site usjobs-french) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GfsConnector(WorkdayConnector): | |
| 14 | + source_id = 'gfs' | |
| 15 | + EMPLOYER = 'Service alimentaire Gordon' | |
| 16 | + TENANT = 'gfs' | |
| 17 | + HOST = 'wd5' | |
| 18 | + SITE = 'usjobs-french' | |
added
jobka/connectors/gologic.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/gologic.py | |
| 6 | +# Rôle : Connecteur GoLogic — smartrecruiters (org « gologic ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GologicConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'gologic' | |
| 15 | + EMPLOYER = 'GoLogic' | |
| 16 | + COMPANY = 'gologic' | |
added
jobka/connectors/groupecanam.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/groupecanam.py | |
| 6 | +# Rôle : Connecteur Groupe Canam — smartrecruiters (org « groupecanam ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GroupecanamConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'groupecanam' | |
| 15 | + EMPLOYER = 'Groupe Canam' | |
| 16 | + COMPANY = 'groupecanam' | |
added
jobka/connectors/gurussolutions.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/gurussolutions.py | |
| 6 | +# Rôle : Connecteur GURUS Solutions — greenhouse (org « gurussolutions ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class GurussolutionsConnector(GreenhouseConnector): | |
| 14 | + source_id = 'gurussolutions' | |
| 15 | + EMPLOYER = 'GURUS Solutions' | |
| 16 | + BOARD = 'gurussolutions' | |
added
jobka/connectors/intactfc.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/intactfc.py | |
| 6 | +# Rôle : Connecteur Intact Corporation financière — workday (tenant intactfc.wd3, site Intactfc) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class IntactfcConnector(WorkdayConnector): | |
| 14 | + source_id = 'intactfc' | |
| 15 | + EMPLOYER = 'Intact Corporation financière' | |
| 16 | + TENANT = 'intactfc' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'Intactfc' | |
added
jobka/connectors/investpsp.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/investpsp.py | |
| 6 | +# Rôle : Connecteur Investissements PSP — workday (tenant investpsp.wd3, site psp_careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class InvestpspConnector(WorkdayConnector): | |
| 14 | + source_id = 'investpsp' | |
| 15 | + EMPLOYER = 'Investissements PSP' | |
| 16 | + TENANT = 'investpsp' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'psp_careers' | |
added
jobka/connectors/investquebec.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/investquebec.py | |
| 6 | +# Rôle : Connecteur Investissement Québec — workday (tenant investquebec.wd10, site Ext) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class InvestquebecConnector(WorkdayConnector): | |
| 14 | + source_id = 'investquebec' | |
| 15 | + EMPLOYER = 'Investissement Québec' | |
| 16 | + TENANT = 'investquebec' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'Ext' | |
added
jobka/connectors/jgrivesud.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/jgrivesud.py | |
| 6 | +# Rôle : Connecteur JG Rive-Sud (GFS) — workday (tenant gfs.wd5, site jgrive-sud) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class JgrivesudConnector(WorkdayConnector): | |
| 14 | + source_id = 'jgrivesud' | |
| 15 | + EMPLOYER = 'JG Rive-Sud (GFS)' | |
| 16 | + TENANT = 'gfs' | |
| 17 | + HOST = 'wd5' | |
| 18 | + SITE = 'jgrive-sud' | |
added
jobka/connectors/korem.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/korem.py | |
| 6 | +# Rôle : Connecteur Korem — bamboohr (org « korem ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class KoremConnector(BambooHRConnector): | |
| 14 | + source_id = 'korem' | |
| 15 | + EMPLOYER = 'Korem' | |
| 16 | + ORG = 'korem' | |
added
jobka/connectors/levio.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/levio.py | |
| 6 | +# Rôle : Connecteur Levio — greenhouse (org « levio ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class LevioConnector(GreenhouseConnector): | |
| 14 | + source_id = 'levio' | |
| 15 | + EMPLOYER = 'Levio' | |
| 16 | + BOARD = 'levio' | |
added
jobka/connectors/lightspeedhq.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/lightspeedhq.py | |
| 6 | +# Rôle : Connecteur Lightspeed Commerce — ashby (org « lightspeedhq ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .ashby import AshbyConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class LightspeedhqConnector(AshbyConnector): | |
| 14 | + source_id = 'lightspeedhq' | |
| 15 | + EMPLOYER = 'Lightspeed Commerce' | |
| 16 | + ORG = 'lightspeedhq' | |
added
jobka/connectors/logisco.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/logisco.py | |
| 6 | +# Rôle : Connecteur Logisco — bamboohr (org « logisco ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class LogiscoConnector(BambooHRConnector): | |
| 14 | + source_id = 'logisco' | |
| 15 | + EMPLOYER = 'Logisco' | |
| 16 | + ORG = 'logisco' | |
added
jobka/connectors/mila_2.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/mila_2.py | |
| 6 | +# Rôle : Connecteur Mila — Institut québécois d'IA — workable (org « mila-2 ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workable import WorkableConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class Mila2Connector(WorkableConnector): | |
| 14 | + source_id = 'mila_2' | |
| 15 | + EMPLOYER = "Mila — Institut québécois d'IA" | |
| 16 | + ORG = 'mila-2' | |
added
jobka/connectors/mirego.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/mirego.py | |
| 6 | +# Rôle : Connecteur Mirego — lever (org « mirego ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .lever import LeverConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class MiregoConnector(LeverConnector): | |
| 14 | + source_id = 'mirego' | |
| 15 | + EMPLOYER = 'Mirego' | |
| 16 | + ORG = 'mirego' | |
added
jobka/connectors/mxo.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/mxo.py | |
| 6 | +# Rôle : Connecteur MXO — bamboohr (org « mxo ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class MxoConnector(BambooHRConnector): | |
| 14 | + source_id = 'mxo' | |
| 15 | + EMPLOYER = 'MXO' | |
| 16 | + ORG = 'mxo' | |
added
jobka/connectors/playmind.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/playmind.py | |
| 6 | +# Rôle : Connecteur Playmind — smartrecruiters (org « playmind ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class PlaymindConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'playmind' | |
| 15 | + EMPLOYER = 'Playmind' | |
| 16 | + COMPANY = 'playmind' | |
added
jobka/connectors/plusgrade.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/plusgrade.py | |
| 6 | +# Rôle : Connecteur Plusgrade — workday (tenant plusgrade.wd10, site Plusgrade_External_Site) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class PlusgradeConnector(WorkdayConnector): | |
| 14 | + source_id = 'plusgrade' | |
| 15 | + EMPLOYER = 'Plusgrade' | |
| 16 | + TENANT = 'plusgrade' | |
| 17 | + HOST = 'wd10' | |
| 18 | + SITE = 'Plusgrade_External_Site' | |
added
jobka/connectors/pouletrouge.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/pouletrouge.py | |
| 6 | +# Rôle : Connecteur Poulet Rouge — bamboohr (org « pouletrouge ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class PouletrougeConnector(BambooHRConnector): | |
| 14 | + source_id = 'pouletrouge' | |
| 15 | + EMPLOYER = 'Poulet Rouge' | |
| 16 | + ORG = 'pouletrouge' | |
added
jobka/connectors/promutuel.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/promutuel.py | |
| 6 | +# Rôle : Connecteur Promutuel Assurance — workday (tenant promutuel.wd3, site promutuel_carrieres) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class PromutuelConnector(WorkdayConnector): | |
| 14 | + source_id = 'promutuel' | |
| 15 | + EMPLOYER = 'Promutuel Assurance' | |
| 16 | + TENANT = 'promutuel' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'promutuel_carrieres' | |
added
jobka/connectors/qsl.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/qsl.py | |
| 6 | +# Rôle : Connecteur QSL — smartrecruiters (org « qsl ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class QslConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'qsl' | |
| 15 | + EMPLOYER = 'QSL' | |
| 16 | + COMPANY = 'qsl' | |
added
jobka/connectors/rcgt.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/rcgt.py | |
| 6 | +# Rôle : Connecteur Raymond Chabot Grant Thornton — workday (tenant rcgt.wd3, site External) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class RcgtConnector(WorkdayConnector): | |
| 14 | + source_id = 'rcgt' | |
| 15 | + EMPLOYER = 'Raymond Chabot Grant Thornton' | |
| 16 | + TENANT = 'rcgt' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'External' | |
added
jobka/connectors/riotinto.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/riotinto.py | |
| 6 | +# Rôle : Connecteur Rio Tinto — workday (tenant riotinto.wd3, site riotinto_careers) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class RiotintoConnector(WorkdayConnector): | |
| 14 | + source_id = 'riotinto' | |
| 15 | + EMPLOYER = 'Rio Tinto' | |
| 16 | + TENANT = 'riotinto' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'riotinto_careers' | |
added
jobka/connectors/scottsmiraclegro.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/scottsmiraclegro.py | |
| 6 | +# Rôle : Connecteur Scotts Canada (Fafard) — workday (tenant scottsmiraclegro.wd5, site SMGExternal) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class ScottsmiraclegroConnector(WorkdayConnector): | |
| 14 | + source_id = 'scottsmiraclegro' | |
| 15 | + EMPLOYER = 'Scotts Canada (Fafard)' | |
| 16 | + TENANT = 'scottsmiraclegro' | |
| 17 | + HOST = 'wd5' | |
| 18 | + SITE = 'SMGExternal' | |
added
jobka/connectors/sidlee.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/sidlee.py | |
| 6 | +# Rôle : Connecteur Sid Lee — greenhouse (org « sidlee ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class SidleeConnector(GreenhouseConnector): | |
| 14 | + source_id = 'sidlee' | |
| 15 | + EMPLOYER = 'Sid Lee' | |
| 16 | + BOARD = 'sidlee' | |
added
jobka/connectors/sleeman.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/sleeman.py | |
| 6 | +# Rôle : Connecteur Brasseries Sleeman (Unibroue) — workday (tenant sleeman.wd3, site SBL) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class SleemanConnector(WorkdayConnector): | |
| 14 | + source_id = 'sleeman' | |
| 15 | + EMPLOYER = 'Brasseries Sleeman (Unibroue)' | |
| 16 | + TENANT = 'sleeman' | |
| 17 | + HOST = 'wd3' | |
| 18 | + SITE = 'SBL' | |
added
jobka/connectors/spiria.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/spiria.py | |
| 6 | +# Rôle : Connecteur Spiria — lever (org « spiria ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .lever import LeverConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class SpiriaConnector(LeverConnector): | |
| 14 | + source_id = 'spiria' | |
| 15 | + EMPLOYER = 'Spiria' | |
| 16 | + ORG = 'spiria' | |
added
jobka/connectors/stelpro.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/stelpro.py | |
| 6 | +# Rôle : Connecteur Stelpro — smartrecruiters (org « stelpro ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class StelproConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'stelpro' | |
| 15 | + EMPLOYER = 'Stelpro' | |
| 16 | + COMPANY = 'stelpro' | |
added
jobka/connectors/suncor.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/suncor.py | |
| 6 | +# Rôle : Connecteur Suncor Énergie — workday (tenant suncor.wd1, site Suncor_External) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class SuncorConnector(WorkdayConnector): | |
| 14 | + source_id = 'suncor' | |
| 15 | + EMPLOYER = 'Suncor Énergie' | |
| 16 | + TENANT = 'suncor' | |
| 17 | + HOST = 'wd1' | |
| 18 | + SITE = 'Suncor_External' | |
added
jobka/connectors/talsom.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/talsom.py | |
| 6 | +# Rôle : Connecteur Talsom — smartrecruiters (org « talsom ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class TalsomConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'talsom' | |
| 15 | + EMPLOYER = 'Talsom' | |
| 16 | + COMPANY = 'talsom' | |
added
jobka/connectors/valtech.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/valtech.py | |
| 6 | +# Rôle : Connecteur Valtech — greenhouse (org « valtech ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class ValtechConnector(GreenhouseConnector): | |
| 14 | + source_id = 'valtech' | |
| 15 | + EMPLOYER = 'Valtech' | |
| 16 | + BOARD = 'valtech' | |
added
jobka/connectors/videotron.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/videotron.py | |
| 6 | +# Rôle : Connecteur Vidéotron — smartrecruiters (org « videotron ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class VideotronConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'videotron' | |
| 15 | + EMPLOYER = 'Vidéotron' | |
| 16 | + COMPANY = 'videotron' | |
added
jobka/connectors/vooban.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/vooban.py | |
| 6 | +# Rôle : Connecteur Vooban — greenhouse (org « vooban ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .greenhouse import GreenhouseConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class VoobanConnector(GreenhouseConnector): | |
| 14 | + source_id = 'vooban' | |
| 15 | + EMPLOYER = 'Vooban' | |
| 16 | + BOARD = 'vooban' | |
added
jobka/connectors/vosker.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/vosker.py | |
| 6 | +# Rôle : Connecteur Vosker — smartrecruiters (org « vosker ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .smartrecruiters import SmartRecruitersConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class VoskerConnector(SmartRecruitersConnector): | |
| 14 | + source_id = 'vosker' | |
| 15 | + EMPLOYER = 'Vosker' | |
| 16 | + COMPANY = 'vosker' | |
added
jobka/connectors/walmart.py
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/walmart.py | |
| 6 | +# Rôle : Connecteur Walmart Canada — workday (tenant walmart.wd504, site WalmartExternal) | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .workday import WorkdayConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class WalmartConnector(WorkdayConnector): | |
| 14 | + source_id = 'walmart' | |
| 15 | + EMPLOYER = 'Walmart Canada' | |
| 16 | + TENANT = 'walmart' | |
| 17 | + HOST = 'wd504' | |
| 18 | + SITE = 'WalmartExternal' | |
added
jobka/connectors/ziptrekeco.py
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +# ============================================================================= | |
| 2 | +# Job·Ka — Groupe KA | |
| 3 | +# Auteur : Simon-Pierre Boucher | |
| 4 | +# Contact : contact@spboucher.ai | |
| 5 | +# Fichier : jobka/connectors/ziptrekeco.py | |
| 6 | +# Rôle : Connecteur Ziptrek Tremblant — bamboohr (org « ziptrekeco ») | |
| 7 | +# [généré par scripts/gen_connectors.py, flux vérifié le 2026-08-18] | |
| 8 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 9 | +# ============================================================================= | |
| 10 | +from .bamboohr import BambooHRConnector | |
| 11 | + | |
| 12 | + | |
| 13 | +class ZiptrekecoConnector(BambooHRConnector): | |
| 14 | + source_id = 'ziptrekeco' | |
| 15 | + EMPLOYER = 'Ziptrek Tremblant' | |
| 16 | + ORG = 'ziptrekeco' | |
modified
jobka/normalize.py
+2 −1
@@ -382,7 +382,8 @@ _NON_QC_CITIES = frozenset({ | ||
| 382 | 382 | "paris", "londres", "amsterdam", "berlin", "munich", "dublin", "madrid", |
| 383 | 383 | "barcelona", "barcelone", "lisbon", "lisbonne", "sydney", "melbourne", |
| 384 | 384 | "singapore", "singapour", "tokyo", "bangalore", "bengaluru", "mumbai", |
| 385 | − "mexico city", "sao paulo", "bogota", "buenos aires", | |
| 385 | + "mexico city", "sao paulo", "bogota", "buenos aires", "las vegas", | |
| 386 | + "orlando", "nashville", "macau", | |
| 386 | 387 | }) |
| 387 | 388 | |
| 388 | 389 | |
added
scripts/detect_ats.py
+277 −0
@@ -0,0 +1,277 @@ | ||
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# ============================================================================= | |
| 3 | +# Job·Ka — Groupe KA | |
| 4 | +# Auteur : Simon-Pierre Boucher | |
| 5 | +# Contact : contact@spboucher.ai | |
| 6 | +# Fichier : scripts/detect_ats.py | |
| 7 | +# Rôle : Détecteur d'ATS par page carrières — visite le site de chaque | |
| 8 | +# employeur (accueil + chemins carrières usuels), reconnaît l'ATS | |
| 9 | +# par motifs d'URL/DOM et extrait le slug. Les 9 ATS supportés | |
| 10 | +# deviennent des candidats pour scripts/probe_ats.py ; les autres | |
| 11 | +# (njoyn/taleo/ukg/icims/successfactors/adp) sont consignés dans | |
| 12 | +# data/detected-other-ats.jsonl pour traitement séparé. | |
| 13 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 14 | +# ============================================================================= | |
| 15 | +"""Usage : | |
| 16 | + python3 scripts/detect_ats.py employeurs.jsonl [autres.jsonl …] \ | |
| 17 | + --out candidats.jsonl --other data/detected-other-ats.jsonl \ | |
| 18 | + [--cap 1500] [--workers 8] | |
| 19 | + | |
| 20 | +Entrée : JSONL {"name": "...", "url"/"domain"/"domain_hint": "...", | |
| 21 | + "city": "...", "categorie": "..."} (ordre = priorité). | |
| 22 | +""" | |
| 23 | +from __future__ import annotations | |
| 24 | + | |
| 25 | +import argparse | |
| 26 | +import json | |
| 27 | +import re | |
| 28 | +import sys | |
| 29 | +import threading | |
| 30 | +import time | |
| 31 | +from concurrent.futures import ThreadPoolExecutor, as_completed | |
| 32 | +from pathlib import Path | |
| 33 | +from urllib.parse import urljoin, urlparse | |
| 34 | + | |
| 35 | +import requests | |
| 36 | +import urllib3 | |
| 37 | + | |
| 38 | +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) | |
| 39 | + | |
| 40 | +UA = "JobKaBot/1.0 (+https://www.job-ka.com; contact@spboucher.ai)" | |
| 41 | +TIMEOUT = 6 | |
| 42 | +PATHS = ["", "/carrieres", "/careers", "/emplois", "/jobs", "/fr/carrieres"] | |
| 43 | +MAX_HTML = 500_000 | |
| 44 | + | |
| 45 | +# slugs jamais valides (pages génériques des ATS eux-mêmes) | |
| 46 | +BAD_SLUGS = {"www", "app", "api", "apply", "embed", "boards", "jobs", "job", | |
| 47 | + "careers", "career", "fr", "en", "help", "support", "cdn", | |
| 48 | + "assets", "status", "docs", "login", "my", "sso", "static", | |
| 49 | + "oneclick-ui", "attachments", "hire", "home", "account", | |
| 50 | + "js", "css", "images", "img", "media", "email", "click"} | |
| 51 | + | |
| 52 | +# ATS supportés par Job·Ka : (ats, regex, groupes) | |
| 53 | +SUPPORTED = [ | |
| 54 | + ("workday", re.compile( | |
| 55 | + r"https?://([\w-]+)\.(wd\d+)\.myworkdayjobs\.com" | |
| 56 | + r"(?:/(?:[a-z]{2}-[A-Z]{2}/)?([A-Za-z0-9_\-]+))?", re.I)), | |
| 57 | + ("greenhouse", re.compile( | |
| 58 | + r"(?:boards|job-boards)\.greenhouse\.io/([A-Za-z0-9_\-]+)", re.I)), | |
| 59 | + ("greenhouse", re.compile( | |
| 60 | + r"greenhouse\.io/embed/job_board\?[^\"'\s]*for=([A-Za-z0-9_\-]+)", re.I)), | |
| 61 | + ("lever", re.compile(r"jobs\.(?:eu\.)?lever\.co/([A-Za-z0-9_\-]+)", re.I)), | |
| 62 | + ("smartrecruiters", re.compile( | |
| 63 | + r"(?:careers|jobs)\.smartrecruiters\.com/([A-Za-z0-9]+)")), | |
| 64 | + ("ashby", re.compile(r"jobs\.ashbyhq\.com/([A-Za-z0-9_\-.%]+)", re.I)), | |
| 65 | + ("workable", re.compile( | |
| 66 | + r"apply\.workable\.com/(?:api/v\d/accounts/)?([A-Za-z0-9_\-]+)", re.I)), | |
| 67 | + ("recruitee", re.compile(r"https?://([A-Za-z0-9\-]+)\.recruitee\.com", re.I)), | |
| 68 | + ("breezy", re.compile(r"https?://([A-Za-z0-9\-]+)\.breezy\.hr", re.I)), | |
| 69 | + ("bamboohr", re.compile(r"https?://([A-Za-z0-9\-]+)\.bamboohr\.com", re.I)), | |
| 70 | +] | |
| 71 | + | |
| 72 | +# ATS repérés mais non supportés ici -> data/detected-other-ats.jsonl | |
| 73 | +OTHER = [ | |
| 74 | + ("njoyn", re.compile(r"https?://[\w.-]*njoyn\.com[^\"'\s<>]*", re.I)), | |
| 75 | + ("taleo", re.compile(r"https?://[\w.-]*taleo\.net[^\"'\s<>]*", re.I)), | |
| 76 | + ("ukg_ultipro", re.compile( | |
| 77 | + r"https?://[\w.-]*(?:ultipro|ukg)\.com[^\"'\s<>]*", re.I)), | |
| 78 | + ("icims", re.compile(r"https?://[\w-]+\.icims\.com[^\"'\s<>]*", re.I)), | |
| 79 | + ("successfactors", re.compile( | |
| 80 | + r"https?://[\w.-]*successfactors\.(?:com|eu)[^\"'\s<>]*", re.I)), | |
| 81 | + ("adp", re.compile( | |
| 82 | + r"https?://(?:workforcenow|recruiting|jobs)\.adp\.com[^\"'\s<>]*", re.I)), | |
| 83 | +] | |
| 84 | + | |
| 85 | +CAREER_LINK = re.compile( | |
| 86 | + r'href=["\']([^"\']*(?:carri|career|emploi|job|recrut|joignez|joindre|' | |
| 87 | + r'postul|travaill)[^"\']*)["\']', re.I) | |
| 88 | + | |
| 89 | +_print_lock = threading.Lock() | |
| 90 | + | |
| 91 | + | |
| 92 | +def norm_domain(rec: dict) -> str: | |
| 93 | + raw = (rec.get("domain_hint") or rec.get("domain") or rec.get("url") | |
| 94 | + or "").strip() | |
| 95 | + if not raw: | |
| 96 | + return "" | |
| 97 | + if "://" not in raw: | |
| 98 | + raw = "https://" + raw | |
| 99 | + host = urlparse(raw).netloc.lower() | |
| 100 | + return host[4:] if host.startswith("www.") else host | |
| 101 | + | |
| 102 | + | |
| 103 | +def fetch(session: requests.Session, url: str) -> tuple[str, str]: | |
| 104 | + r = session.get(url, timeout=TIMEOUT, allow_redirects=True, verify=False, | |
| 105 | + headers={"User-Agent": UA}) | |
| 106 | + if r.status_code >= 400: | |
| 107 | + return r.url, "" | |
| 108 | + return r.url, (r.text or "")[:MAX_HTML] | |
| 109 | + | |
| 110 | + | |
| 111 | +def scan_text(text: str) -> tuple[list[tuple], list[tuple]]: | |
| 112 | + """-> ([(ats, slug, extra…)], [(ats, url)]).""" | |
| 113 | + hits, others = [], [] | |
| 114 | + for ats, rx in SUPPORTED: | |
| 115 | + for m in rx.finditer(text): | |
| 116 | + if ats == "workday": | |
| 117 | + tenant, host = m.group(1).lower(), m.group(2).lower() | |
| 118 | + site = m.group(3) or "" | |
| 119 | + if tenant in BAD_SLUGS or tenant == "impl": | |
| 120 | + continue | |
| 121 | + hits.append((ats, tenant, host, site)) | |
| 122 | + else: | |
| 123 | + slug = m.group(1) | |
| 124 | + if slug.lower() in BAD_SLUGS: | |
| 125 | + continue | |
| 126 | + hits.append((ats, slug)) | |
| 127 | + for ats, rx in OTHER: | |
| 128 | + m = rx.search(text) | |
| 129 | + if m: | |
| 130 | + others.append((ats, m.group(0)[:300])) | |
| 131 | + return hits, others | |
| 132 | + | |
| 133 | + | |
| 134 | +def detect_one(rec: dict) -> dict: | |
| 135 | + """-> {"candidates": [...], "others": [...], "domain": d}.""" | |
| 136 | + domain = norm_domain(rec) | |
| 137 | + out = {"domain": domain, "candidates": [], "others": []} | |
| 138 | + if not domain: | |
| 139 | + return out | |
| 140 | + session = requests.Session() | |
| 141 | + seen_hits: set[tuple] = set() | |
| 142 | + seen_others: set[str] = set() | |
| 143 | + extra_links: list[str] = [] | |
| 144 | + pages = 0 | |
| 145 | + for i, path in enumerate(PATHS + ["@extra1", "@extra2"]): | |
| 146 | + if path.startswith("@"): | |
| 147 | + if not extra_links: | |
| 148 | + continue | |
| 149 | + url = extra_links.pop(0) | |
| 150 | + else: | |
| 151 | + url = f"https://{domain}{path}" | |
| 152 | + try: | |
| 153 | + final_url, html = fetch(session, url) | |
| 154 | + except requests.RequestException: | |
| 155 | + if path == "": # racine injoignable en https -> essai www/http | |
| 156 | + for alt in (f"https://www.{domain}", f"http://{domain}"): | |
| 157 | + try: | |
| 158 | + final_url, html = fetch(session, alt) | |
| 159 | + break | |
| 160 | + except requests.RequestException: | |
| 161 | + final_url, html = "", "" | |
| 162 | + if not html: | |
| 163 | + continue | |
| 164 | + else: | |
| 165 | + continue | |
| 166 | + pages += 1 | |
| 167 | + hits, others = scan_text(final_url + "\n" + html) | |
| 168 | + for h in hits: | |
| 169 | + if h in seen_hits: | |
| 170 | + continue | |
| 171 | + seen_hits.add(h) | |
| 172 | + for ats, u in others: | |
| 173 | + if ats not in seen_others: | |
| 174 | + seen_others.add(ats) | |
| 175 | + out["others"].append({"name": rec.get("name", ""), | |
| 176 | + "domain": domain, "ats": ats, "url": u}) | |
| 177 | + if path == "" and html and not seen_hits: | |
| 178 | + # relever jusqu'à 2 liens « carrières » à suivre | |
| 179 | + base = final_url or f"https://{domain}" | |
| 180 | + for link in CAREER_LINK.findall(html): | |
| 181 | + if link.startswith(("mailto:", "tel:", "#", "javascript")): | |
| 182 | + continue | |
| 183 | + full = urljoin(base, link) | |
| 184 | + if full not in extra_links: | |
| 185 | + extra_links.append(full) | |
| 186 | + if len(extra_links) >= 2: | |
| 187 | + break | |
| 188 | + if seen_hits: | |
| 189 | + break # ATS supporté trouvé : inutile d'aller plus loin | |
| 190 | + for h in seen_hits: | |
| 191 | + cand = {"employer": rec.get("name") or domain, "domain": domain, | |
| 192 | + "url": f"https://{domain}", | |
| 193 | + "sectors": [s for s in [rec.get("categorie", "")] if s], | |
| 194 | + "cities": [c for c in [rec.get("city", "")] if c], | |
| 195 | + "group": rec.get("name") or domain} | |
| 196 | + if h[0] == "workday": | |
| 197 | + cand.update(ats="workday", slug=h[1], tenant=h[1], host=h[2]) | |
| 198 | + if h[3] and not re.fullmatch(r"[a-z]{2}-[A-Z]{2}", h[3]): | |
| 199 | + cand["site"] = h[3] | |
| 200 | + else: | |
| 201 | + cand.update(ats=h[0], slug=h[1]) | |
| 202 | + out["candidates"].append(cand) | |
| 203 | + return out | |
| 204 | + | |
| 205 | + | |
| 206 | +def main() -> None: | |
| 207 | + ap = argparse.ArgumentParser() | |
| 208 | + ap.add_argument("inputs", nargs="+") | |
| 209 | + ap.add_argument("--out", required=True) | |
| 210 | + ap.add_argument("--other", default="data/detected-other-ats.jsonl") | |
| 211 | + ap.add_argument("--cap", type=int, default=1500) | |
| 212 | + ap.add_argument("--workers", type=int, default=8) | |
| 213 | + args = ap.parse_args() | |
| 214 | + | |
| 215 | + recs, seen = [], set() | |
| 216 | + for f in args.inputs: | |
| 217 | + for line in Path(f).read_text(encoding="utf-8").splitlines(): | |
| 218 | + line = line.strip() | |
| 219 | + if not line: | |
| 220 | + continue | |
| 221 | + rec = json.loads(line) | |
| 222 | + d = norm_domain(rec) | |
| 223 | + if d and d not in seen: | |
| 224 | + seen.add(d) | |
| 225 | + recs.append(rec) | |
| 226 | + recs = recs[:args.cap] | |
| 227 | + print(f"[detect] {len(recs)} domaines à visiter (cap {args.cap})", | |
| 228 | + flush=True) | |
| 229 | + | |
| 230 | + cands, others = [], [] | |
| 231 | + t0 = time.time() | |
| 232 | + done = 0 | |
| 233 | + with ThreadPoolExecutor(max_workers=args.workers) as ex: | |
| 234 | + futs = [ex.submit(detect_one, r) for r in recs] | |
| 235 | + for fut in as_completed(futs): | |
| 236 | + done += 1 | |
| 237 | + try: | |
| 238 | + res = fut.result() | |
| 239 | + except Exception: | |
| 240 | + continue | |
| 241 | + for c in res["candidates"]: | |
| 242 | + cands.append(c) | |
| 243 | + with _print_lock: | |
| 244 | + print(f" ✓ {c['employer']} -> {c['ats']}:{c['slug']}", | |
| 245 | + flush=True) | |
| 246 | + others.extend(res["others"]) | |
| 247 | + if done % 100 == 0: | |
| 248 | + print(f"[detect] {done}/{len(recs)} domaines, " | |
| 249 | + f"{len(cands)} candidats, {len(others)} autres ATS, " | |
| 250 | + f"{time.time()-t0:.0f}s", flush=True) | |
| 251 | + | |
| 252 | + Path(args.out).write_text( | |
| 253 | + "\n".join(json.dumps(c, ensure_ascii=False) for c in cands) + "\n", | |
| 254 | + encoding="utf-8") | |
| 255 | + op = Path(args.other) | |
| 256 | + existing = set() | |
| 257 | + if op.exists(): | |
| 258 | + existing = {l for l in op.read_text(encoding="utf-8").splitlines() | |
| 259 | + if l.strip()} | |
| 260 | + with op.open("a", encoding="utf-8") as fh: | |
| 261 | + for o in others: | |
| 262 | + line = json.dumps(o, ensure_ascii=False) | |
| 263 | + if line not in existing: | |
| 264 | + fh.write(line + "\n") | |
| 265 | + existing.add(line) | |
| 266 | + | |
| 267 | + per = {} | |
| 268 | + for o in others: | |
| 269 | + per[o["ats"]] = per.get(o["ats"], 0) + 1 | |
| 270 | + print(f"\n[detect] terminé en {time.time()-t0:.0f}s : " | |
| 271 | + f"{len(cands)} candidats ATS supportés -> {args.out}") | |
| 272 | + print(f"[detect] autres ATS ({sum(per.values())}) -> {args.other} : " | |
| 273 | + + ", ".join(f"{k}={v}" for k, v in sorted(per.items()))) | |
| 274 | + | |
| 275 | + | |
| 276 | +if __name__ == "__main__": | |
| 277 | + main() | |
added
scripts/probe_ats.py
+500 −0
@@ -0,0 +1,500 @@ | ||
| 1 | +#!/usr/bin/env python3 | |
| 2 | +# ============================================================================= | |
| 3 | +# Job·Ka — Groupe KA | |
| 4 | +# Auteur : Simon-Pierre Boucher | |
| 5 | +# Contact : contact@spboucher.ai | |
| 6 | +# Fichier : scripts/probe_ats.py | |
| 7 | +# Rôle : Sondage massif de slugs candidats sur les 9 ATS supportés — | |
| 8 | +# un slug est CONFIRMÉ si l'API répond ≥1 offre ET ≥1 offre au | |
| 9 | +# Québec (réutilise is_quebec_location du projet). Émet des entrées | |
| 10 | +# prêtes pour data/feeds-*.json (scripts/gen_connectors.py). | |
| 11 | +# Créé : 2026-08-18 Modifié : 2026-08-18 | |
| 12 | +# ============================================================================= | |
| 13 | +"""Sonde des slugs candidats sur les 9 plateformes ATS de Job·Ka. | |
| 14 | + | |
| 15 | +Usage : | |
| 16 | + python3 scripts/probe_ats.py candidats.jsonl --out confirmed.json \ | |
| 17 | + [--rejected rejected.jsonl] [--workers 8] | |
| 18 | + | |
| 19 | +Entrée (JSONL, ou JSON liste) — un candidat par ligne : | |
| 20 | + {"slug": "acme", "employer": "Acme inc.", "ats": "lever"?, | |
| 21 | + "sectors": ["TI"], "cities": ["Montréal"], "group": "Acme"?, | |
| 22 | + "no_workday": true?, "tenant"/"host"/"site" (workday)?} | |
| 23 | + | |
| 24 | +- sans "ats" : les 9 plateformes sont sondées dans l'ordre DEFAULT_ORDER | |
| 25 | + (Workday en dernier — découverte automatique de l'hôte wdN et du site | |
| 26 | + par le redirect de la racine du tenant). | |
| 27 | +- les candidats partageant le même "group" (défaut : employer) sont des | |
| 28 | + variantes du même employeur : on s'arrête à la première confirmation. | |
| 29 | +- les slugs/tenants déjà connectés (sources.json + jobka/connectors/*.py) | |
| 30 | + sont sautés automatiquement. | |
| 31 | + | |
| 32 | +Politesse : timeout 6 s, throttle 0,3 s par domaine d'API, 8 threads. | |
| 33 | +""" | |
| 34 | +from __future__ import annotations | |
| 35 | + | |
| 36 | +import argparse | |
| 37 | +import json | |
| 38 | +import re | |
| 39 | +import sys | |
| 40 | +import threading | |
| 41 | +import time | |
| 42 | +from concurrent.futures import ThreadPoolExecutor, as_completed | |
| 43 | +from pathlib import Path | |
| 44 | +from urllib.parse import urlparse | |
| 45 | + | |
| 46 | +import requests | |
| 47 | + | |
| 48 | +ROOT = Path(__file__).resolve().parent.parent | |
| 49 | +sys.path.insert(0, str(ROOT)) | |
| 50 | + | |
| 51 | +from jobka.normalize import is_quebec_location # noqa: E402 | |
| 52 | + | |
| 53 | +UA = "JobKaBot/1.0 (+https://www.job-ka.com; contact@spboucher.ai)" | |
| 54 | +TIMEOUT = 6 | |
| 55 | +THROTTLE = 0.3 # s entre deux requêtes vers un même domaine d'API | |
| 56 | +WD_HOSTS = ["wd3", "wd1", "wd5", "wd10", "wd12", "wd103", "wd502", "wd504"] | |
| 57 | + | |
| 58 | +# Noms de sites carrières Workday fréquents — essayés quand le site est | |
| 59 | +# inconnu. L'API cxs répond 422 si le tenant/hôte est faux mais 404 si seul | |
| 60 | +# le site l'est : on découvre d'abord l'hôte, puis on devine le site. | |
| 61 | +WD_COMMON_SITES = [ | |
| 62 | + "External", "Careers", "External_Careers", "ExternalCareers", "careers", | |
| 63 | + "External_Career_Site", "CareerSite", "Career", "Global", "external", | |
| 64 | + "Global_Careers", "GlobalCareers", "jobs", "Jobs", "External_Site", | |
| 65 | + "ExternalSite", "Externe", "Carrieres", "carrieres", "Recruiting", | |
| 66 | + "Recrutement", "Emplois", "External_Portal", "EXTERNAL", "Ext", "EXT", | |
| 67 | +] | |
| 68 | + | |
| 69 | +DEFAULT_ORDER = ["lever", "greenhouse", "ashby", "smartrecruiters", | |
| 70 | + "workable", "recruitee", "breezy", "bamboohr", "workday"] | |
| 71 | + | |
| 72 | +# --- throttling par domaine d'API ------------------------------------------- | |
| 73 | +_locks: dict[str, threading.Lock] = {} | |
| 74 | +_last: dict[str, float] = {} | |
| 75 | +_glock = threading.Lock() | |
| 76 | +_nreq = [0] | |
| 77 | + | |
| 78 | + | |
| 79 | +def _req(family: str, method: str, url: str, **kw) -> requests.Response: | |
| 80 | + """Requête HTTP throttlée (verrou + espacement par famille/domaine).""" | |
| 81 | + with _glock: | |
| 82 | + lock = _locks.setdefault(family, threading.Lock()) | |
| 83 | + _nreq[0] += 1 | |
| 84 | + headers = {"User-Agent": UA} | |
| 85 | + headers.update(kw.pop("headers", None) or {}) | |
| 86 | + with lock: | |
| 87 | + wait = THROTTLE - (time.time() - _last.get(family, 0.0)) | |
| 88 | + if wait > 0: | |
| 89 | + time.sleep(wait) | |
| 90 | + try: | |
| 91 | + return requests.request(method, url, timeout=TIMEOUT, | |
| 92 | + headers=headers, **kw) | |
| 93 | + finally: | |
| 94 | + _last[family] = time.time() | |
| 95 | + | |
| 96 | + | |
| 97 | +def _qc_stats(labels: list[list[str]]) -> tuple[int, list[str]]: | |
| 98 | + """[[libellés d'une offre], …] -> (nb d'offres QC, libellés QC exemples).""" | |
| 99 | + qc, ex = 0, [] | |
| 100 | + for locs in labels: | |
| 101 | + hit = next((l for l in locs if l and is_quebec_location(l)), None) | |
| 102 | + if hit: | |
| 103 | + qc += 1 | |
| 104 | + if len(ex) < 5 and hit not in ex: | |
| 105 | + ex.append(hit) | |
| 106 | + return qc, ex | |
| 107 | + | |
| 108 | + | |
| 109 | +# --- sondes par ATS ---------------------------------------------------------- | |
| 110 | +def probe_lever(slug: str, cand: dict) -> dict | None: | |
| 111 | + r = _req("api.lever.co", "GET", | |
| 112 | + f"https://api.lever.co/v0/postings/{slug}?mode=json") | |
| 113 | + if r.status_code != 200: | |
| 114 | + return None | |
| 115 | + data = r.json() | |
| 116 | + if not isinstance(data, list) or not data: | |
| 117 | + return None | |
| 118 | + labels = [] | |
| 119 | + for p in data: | |
| 120 | + locs = [(p.get("categories") or {}).get("location") or ""] | |
| 121 | + locs += [l for l in (p.get("allLocations") or []) if isinstance(l, str)] | |
| 122 | + labels.append(locs) | |
| 123 | + qc, ex = _qc_stats(labels) | |
| 124 | + return {"found": len(data), "qc": qc, "qc_ex": ex, "api_name": ""} | |
| 125 | + | |
| 126 | + | |
| 127 | +def probe_greenhouse(slug: str, cand: dict) -> dict | None: | |
| 128 | + r = _req("boards-api.greenhouse.io", "GET", | |
| 129 | + f"https://boards-api.greenhouse.io/v1/boards/{slug}/jobs") | |
| 130 | + if r.status_code != 200: | |
| 131 | + return None | |
| 132 | + jobs = r.json().get("jobs") or [] | |
| 133 | + if not jobs: | |
| 134 | + return None | |
| 135 | + labels = [[(j.get("location") or {}).get("name") or ""] for j in jobs] | |
| 136 | + qc, ex = _qc_stats(labels) | |
| 137 | + name = "" | |
| 138 | + if qc: | |
| 139 | + try: | |
| 140 | + r2 = _req("boards-api.greenhouse.io", "GET", | |
| 141 | + f"https://boards-api.greenhouse.io/v1/boards/{slug}") | |
| 142 | + if r2.status_code == 200: | |
| 143 | + name = r2.json().get("name") or "" | |
| 144 | + except requests.RequestException: | |
| 145 | + pass | |
| 146 | + return {"found": len(jobs), "qc": qc, "qc_ex": ex, "api_name": name} | |
| 147 | + | |
| 148 | + | |
| 149 | +def probe_ashby(slug: str, cand: dict) -> dict | None: | |
| 150 | + r = _req("api.ashbyhq.com", "GET", | |
| 151 | + f"https://api.ashbyhq.com/posting-api/job-board/{slug}") | |
| 152 | + if r.status_code != 200: | |
| 153 | + return None | |
| 154 | + data = r.json() | |
| 155 | + jobs = data.get("jobs") or [] | |
| 156 | + if not jobs: | |
| 157 | + return None | |
| 158 | + labels = [] | |
| 159 | + for j in jobs: | |
| 160 | + locs = [j.get("location") or ""] | |
| 161 | + locs += [(s.get("location") or "") for s in (j.get("secondaryLocations") or [])] | |
| 162 | + labels.append(locs) | |
| 163 | + qc, ex = _qc_stats(labels) | |
| 164 | + return {"found": len(jobs), "qc": qc, "qc_ex": ex, | |
| 165 | + "api_name": data.get("name") or ""} | |
| 166 | + | |
| 167 | + | |
| 168 | +def probe_smartrecruiters(slug: str, cand: dict) -> dict | None: | |
| 169 | + variants = [slug] | |
| 170 | + if slug != slug.capitalize(): | |
| 171 | + variants.append(slug.capitalize()) | |
| 172 | + for v in variants: | |
| 173 | + r = _req("api.smartrecruiters.com", "GET", | |
| 174 | + f"https://api.smartrecruiters.com/v1/companies/{v}/postings?limit=100") | |
| 175 | + if r.status_code != 200: | |
| 176 | + continue | |
| 177 | + data = r.json() | |
| 178 | + content = data.get("content") or [] | |
| 179 | + total = int(data.get("totalFound") or len(content)) | |
| 180 | + if not content: | |
| 181 | + continue | |
| 182 | + labels, name = [], "" | |
| 183 | + for p in content: | |
| 184 | + loc = p.get("location") or {} | |
| 185 | + country = (loc.get("country") or "").lower() | |
| 186 | + lbl = ", ".join(x for x in (loc.get("city"), loc.get("region"), | |
| 187 | + loc.get("country")) if x) | |
| 188 | + reg = (loc.get("region") or "").lower() | |
| 189 | + ok = reg in ("qc", "quebec", "québec") or ( | |
| 190 | + country in ("ca", "canada") and is_quebec_location(lbl)) | |
| 191 | + labels.append([lbl] if ok else [""]) | |
| 192 | + name = name or (p.get("company") or {}).get("name") or "" | |
| 193 | + qc, ex = _qc_stats(labels) | |
| 194 | + return {"found": total, "qc": qc, "qc_ex": ex, "api_name": name, | |
| 195 | + "org_override": v} | |
| 196 | + return None | |
| 197 | + | |
| 198 | + | |
| 199 | +def probe_workable(slug: str, cand: dict) -> dict | None: | |
| 200 | + r = _req("apply.workable.com", "GET", | |
| 201 | + f"https://apply.workable.com/api/v1/widget/accounts/{slug}?details=false") | |
| 202 | + if r.status_code != 200: | |
| 203 | + return None | |
| 204 | + data = r.json() | |
| 205 | + jobs = data.get("jobs") or [] | |
| 206 | + if not jobs: | |
| 207 | + return None | |
| 208 | + labels = [[", ".join(x for x in (j.get("city"), j.get("state"), | |
| 209 | + j.get("country")) if x)] for j in jobs] | |
| 210 | + qc, ex = _qc_stats(labels) | |
| 211 | + return {"found": len(jobs), "qc": qc, "qc_ex": ex, | |
| 212 | + "api_name": data.get("name") or ""} | |
| 213 | + | |
| 214 | + | |
| 215 | +def probe_recruitee(slug: str, cand: dict) -> dict | None: | |
| 216 | + r = _req(f"{slug}.recruitee.com", "GET", | |
| 217 | + f"https://{slug}.recruitee.com/api/offers/") | |
| 218 | + if r.status_code != 200: | |
| 219 | + return None | |
| 220 | + offers = r.json().get("offers") or [] | |
| 221 | + if not offers: | |
| 222 | + return None | |
| 223 | + labels = [] | |
| 224 | + for o in offers: | |
| 225 | + locs = [o.get("location") or "", | |
| 226 | + ", ".join(x for x in (o.get("city"), o.get("country")) if x)] | |
| 227 | + labels.append(locs) | |
| 228 | + qc, ex = _qc_stats(labels) | |
| 229 | + return {"found": len(offers), "qc": qc, "qc_ex": ex, "api_name": ""} | |
| 230 | + | |
| 231 | + | |
| 232 | +def probe_breezy(slug: str, cand: dict) -> dict | None: | |
| 233 | + r = _req(f"{slug}.breezy.hr", "GET", f"https://{slug}.breezy.hr/json") | |
| 234 | + if r.status_code != 200: | |
| 235 | + return None | |
| 236 | + try: | |
| 237 | + data = r.json() | |
| 238 | + except ValueError: | |
| 239 | + return None | |
| 240 | + if not isinstance(data, list) or not data: | |
| 241 | + return None | |
| 242 | + labels, name = [], "" | |
| 243 | + for p in data: | |
| 244 | + loc = p.get("location") or {} | |
| 245 | + labels.append([loc.get("name") or "", | |
| 246 | + ", ".join(x for x in (loc.get("city"), | |
| 247 | + (loc.get("state") or {}).get("name") | |
| 248 | + if isinstance(loc.get("state"), dict) | |
| 249 | + else loc.get("state"), | |
| 250 | + loc.get("country", {}).get("name") | |
| 251 | + if isinstance(loc.get("country"), dict) | |
| 252 | + else loc.get("country")) if x)]) | |
| 253 | + name = name or (p.get("company") or {}).get("name", "") \ | |
| 254 | + if isinstance(p.get("company"), dict) else name | |
| 255 | + qc, ex = _qc_stats(labels) | |
| 256 | + return {"found": len(data), "qc": qc, "qc_ex": ex, "api_name": name} | |
| 257 | + | |
| 258 | + | |
| 259 | +def probe_bamboohr(slug: str, cand: dict) -> dict | None: | |
| 260 | + r = _req(f"{slug}.bamboohr.com", "GET", | |
| 261 | + f"https://{slug}.bamboohr.com/careers/list", | |
| 262 | + headers={"User-Agent": UA, "Accept": "application/json"}) | |
| 263 | + if r.status_code != 200: | |
| 264 | + return None | |
| 265 | + try: | |
| 266 | + data = r.json() | |
| 267 | + except ValueError: | |
| 268 | + return None | |
| 269 | + jobs = data.get("result") or [] | |
| 270 | + if not jobs: | |
| 271 | + return None | |
| 272 | + labels = [] | |
| 273 | + for j in jobs: | |
| 274 | + loc = j.get("location") or {} | |
| 275 | + labels.append([", ".join(x for x in (loc.get("city"), | |
| 276 | + loc.get("state")) if x)]) | |
| 277 | + qc, ex = _qc_stats(labels) | |
| 278 | + return {"found": len(jobs), "qc": qc, "qc_ex": ex, | |
| 279 | + "api_name": (data.get("meta") or {}).get("companyName") or ""} | |
| 280 | + | |
| 281 | + | |
| 282 | +def _wd_post(tenant: str, host: str, site: str, | |
| 283 | + search: str = "") -> requests.Response: | |
| 284 | + url = (f"https://{tenant}.{host}.myworkdayjobs.com" | |
| 285 | + f"/wday/cxs/{tenant}/{site}/jobs") | |
| 286 | + return _req(f"{tenant}.{host}.myworkdayjobs.com", "POST", url, | |
| 287 | + json={"appliedFacets": {}, "limit": 20, "offset": 0, | |
| 288 | + "searchText": search}) | |
| 289 | + | |
| 290 | + | |
| 291 | +def _wd_eval(tenant: str, host: str, site: str) -> dict | None: | |
| 292 | + """Site valide -> confirme s'il y a ≥1 offre dont ≥1 au Québec | |
| 293 | + (page 1 brute, puis recherches « Québec »).""" | |
| 294 | + total = 0 | |
| 295 | + for st in ("", "Québec", "Quebec, Canada"): | |
| 296 | + try: | |
| 297 | + r = _wd_post(tenant, host, site, st) | |
| 298 | + except requests.RequestException: | |
| 299 | + return None | |
| 300 | + if r.status_code != 200: | |
| 301 | + return None | |
| 302 | + try: | |
| 303 | + data = r.json() | |
| 304 | + except ValueError: | |
| 305 | + return None | |
| 306 | + items = data.get("jobPostings") or [] | |
| 307 | + total = max(total, int(data.get("total") or 0)) | |
| 308 | + if st == "" and not total: | |
| 309 | + return None | |
| 310 | + labels = [[i.get("locationsText") or ""] for i in items] | |
| 311 | + qc, ex = _qc_stats(labels) | |
| 312 | + if qc: | |
| 313 | + return {"found": total, "qc": qc, "qc_ex": ex, "api_name": "", | |
| 314 | + "tenant": tenant, "host": host, "site": site} | |
| 315 | + return None | |
| 316 | + | |
| 317 | + | |
| 318 | +def probe_workday(slug: str, cand: dict) -> dict | None: | |
| 319 | + """La page racine myworkdayjobs répond 406 aux bots : on passe par l'API | |
| 320 | + cxs — 422 = tenant absent de cet hôte, 404 = hôte bon mais site inconnu, | |
| 321 | + 200 = tenant+site valides. Hôte scanné puis site deviné au besoin.""" | |
| 322 | + tenant = (cand.get("tenant") or slug).lower() | |
| 323 | + hosts = [cand["host"]] if cand.get("host") else WD_HOSTS | |
| 324 | + for host in hosts: | |
| 325 | + try: | |
| 326 | + r = _wd_post(tenant, host, cand.get("site") or "__jobka_probe__") | |
| 327 | + except requests.RequestException: | |
| 328 | + continue | |
| 329 | + if r.status_code == 200: # site fourni et valide | |
| 330 | + return _wd_eval(tenant, host, cand["site"]) | |
| 331 | + if r.status_code != 404: | |
| 332 | + continue # 422/5xx : hôte suivant | |
| 333 | + # hôte confirmé — deviner le nom du site | |
| 334 | + t = tenant | |
| 335 | + derived = [f"{t}careers", f"{t}_careers", f"{t.capitalize()}Careers", | |
| 336 | + f"{t.capitalize()}_Careers", f"{t.upper()}_CAREERS", | |
| 337 | + f"{t.capitalize()}_External_Careers", t.capitalize(), | |
| 338 | + f"Carrieres{t.capitalize()}", f"{t}_carrieres"] | |
| 339 | + seen: list[str] = [] | |
| 340 | + for s in ([cand["site"]] if cand.get("site") else []) + derived \ | |
| 341 | + + WD_COMMON_SITES: | |
| 342 | + if s in seen: | |
| 343 | + continue | |
| 344 | + seen.append(s) | |
| 345 | + if len(seen) > 34: | |
| 346 | + break | |
| 347 | + try: | |
| 348 | + r2 = _wd_post(tenant, host, s) | |
| 349 | + except requests.RequestException: | |
| 350 | + continue | |
| 351 | + if r2.status_code == 200: | |
| 352 | + return _wd_eval(tenant, host, s) | |
| 353 | + return None # hôte trouvé mais nom de site introuvable | |
| 354 | + return None | |
| 355 | + | |
| 356 | + | |
| 357 | +PROBES = { | |
| 358 | + "lever": probe_lever, "greenhouse": probe_greenhouse, "ashby": probe_ashby, | |
| 359 | + "smartrecruiters": probe_smartrecruiters, "workable": probe_workable, | |
| 360 | + "recruitee": probe_recruitee, "breezy": probe_breezy, | |
| 361 | + "bamboohr": probe_bamboohr, "workday": probe_workday, | |
| 362 | +} | |
| 363 | + | |
| 364 | + | |
| 365 | +# --- registre existant (pour sauter les slugs déjà connectés) ---------------- | |
| 366 | +def known_slugs() -> set[str]: | |
| 367 | + known: set[str] = set() | |
| 368 | + src = ROOT / "data" / "sources.json" | |
| 369 | + if src.exists(): | |
| 370 | + for s in json.loads(src.read_text())["sources"]: | |
| 371 | + known.add(s["id"]) | |
| 372 | + pat = re.compile(r"^\s*(?:ORG|BOARD|COMPANY|TENANT)\s*=\s*['\"]([^'\"]+)", | |
| 373 | + re.M) | |
| 374 | + for f in (ROOT / "jobka" / "connectors").glob("*.py"): | |
| 375 | + for m in pat.finditer(f.read_text(encoding="utf-8")): | |
| 376 | + known.add(m.group(1).lower()) | |
| 377 | + return known | |
| 378 | + | |
| 379 | + | |
| 380 | +# --- pipeline ----------------------------------------------------------------- | |
| 381 | +def probe_group(group: str, cands: list[dict], stats: dict, | |
| 382 | + slock: threading.Lock) -> tuple[dict | None, dict]: | |
| 383 | + """Essaie chaque variante du groupe ; retourne (feed confirmé, rejet).""" | |
| 384 | + best = None | |
| 385 | + for cand in cands: | |
| 386 | + slug = cand["slug"] | |
| 387 | + order = [cand["ats"]] if cand.get("ats") else [ | |
| 388 | + a for a in DEFAULT_ORDER if not (cand.get("no_workday") | |
| 389 | + and a == "workday")] | |
| 390 | + for ats in order: | |
| 391 | + with slock: | |
| 392 | + stats.setdefault(ats, [0, 0])[0] += 1 | |
| 393 | + try: | |
| 394 | + res = PROBES[ats](slug, cand) | |
| 395 | + except Exception: # API hors-format = slug non confirmé | |
| 396 | + res = None | |
| 397 | + if not res: | |
| 398 | + continue | |
| 399 | + if res["qc"] >= 1: | |
| 400 | + with slock: | |
| 401 | + stats[ats][1] += 1 | |
| 402 | + feed = {"ats": ats, | |
| 403 | + "employer": cand.get("employer") or slug, | |
| 404 | + "sectors": cand.get("sectors") or [], | |
| 405 | + "cities": cand.get("cities") or [], | |
| 406 | + "url": cand.get("url", ""), | |
| 407 | + "_found": res["found"], "_qc": res["qc"], | |
| 408 | + "_qc_locations": res["qc_ex"], | |
| 409 | + "_api_name": res.get("api_name", "")} | |
| 410 | + if ats == "workday": | |
| 411 | + feed.update(tenant=res["tenant"], host=res["host"], | |
| 412 | + site=res["site"]) | |
| 413 | + else: | |
| 414 | + feed["org"] = res.get("org_override", slug) | |
| 415 | + return feed, {} | |
| 416 | + if best is None or res["found"] > best.get("found", 0): | |
| 417 | + best = {"ats": ats, "slug": slug, "found": res["found"]} | |
| 418 | + reject = {"group": group, "slugs": [c["slug"] for c in cands], | |
| 419 | + "reason": "no_qc" if best else "no_api", "best": best} | |
| 420 | + return None, reject | |
| 421 | + | |
| 422 | + | |
| 423 | +def main() -> None: | |
| 424 | + ap = argparse.ArgumentParser() | |
| 425 | + ap.add_argument("candidates") | |
| 426 | + ap.add_argument("--out", required=True) | |
| 427 | + ap.add_argument("--rejected", default="") | |
| 428 | + ap.add_argument("--workers", type=int, default=8) | |
| 429 | + args = ap.parse_args() | |
| 430 | + | |
| 431 | + raw = Path(args.candidates).read_text(encoding="utf-8").strip() | |
| 432 | + if raw.startswith("["): | |
| 433 | + cands = json.loads(raw) | |
| 434 | + else: | |
| 435 | + cands = [json.loads(l) for l in raw.splitlines() if l.strip()] | |
| 436 | + | |
| 437 | + known = known_slugs() | |
| 438 | + groups: dict[str, list[dict]] = {} | |
| 439 | + skipped = 0 | |
| 440 | + for c in cands: | |
| 441 | + slug = (c.get("slug") or "").strip() | |
| 442 | + if not slug: | |
| 443 | + continue | |
| 444 | + if slug.lower() in known or (c.get("tenant") or "").lower() in known: | |
| 445 | + skipped += 1 | |
| 446 | + continue | |
| 447 | + groups.setdefault(c.get("group") or c.get("employer") or slug, | |
| 448 | + []).append(c) | |
| 449 | + | |
| 450 | + n_slugs = sum(len(v) for v in groups.values()) | |
| 451 | + print(f"[probe] {len(groups)} groupes / {n_slugs} slugs à sonder " | |
| 452 | + f"({skipped} déjà connectés, sautés)", flush=True) | |
| 453 | + | |
| 454 | + stats: dict[str, list[int]] = {} | |
| 455 | + slock = threading.Lock() | |
| 456 | + confirmed, rejected = [], [] | |
| 457 | + t0 = time.time() | |
| 458 | + with ThreadPoolExecutor(max_workers=args.workers) as ex: | |
| 459 | + futs = {ex.submit(probe_group, g, cs, stats, slock): g | |
| 460 | + for g, cs in groups.items()} | |
| 461 | + done = 0 | |
| 462 | + for fut in as_completed(futs): | |
| 463 | + done += 1 | |
| 464 | + try: | |
| 465 | + feed, reject = fut.result() | |
| 466 | + except Exception as exc: | |
| 467 | + print(f"[probe] {futs[fut]} : erreur {exc}", flush=True) | |
| 468 | + continue | |
| 469 | + if feed: | |
| 470 | + confirmed.append(feed) | |
| 471 | + print(f" ✓ {feed['employer']} -> {feed['ats']}" | |
| 472 | + f" ({feed.get('org') or feed.get('tenant')}) " | |
| 473 | + f"qc={feed['_qc']}/{feed['_found']}", flush=True) | |
| 474 | + elif reject: | |
| 475 | + rejected.append(reject) | |
| 476 | + if done % 50 == 0: | |
| 477 | + print(f"[probe] {done}/{len(groups)} groupes, " | |
| 478 | + f"{len(confirmed)} confirmés, {_nreq[0]} requêtes, " | |
| 479 | + f"{time.time()-t0:.0f}s", flush=True) | |
| 480 | + | |
| 481 | + confirmed.sort(key=lambda f: (f["ats"], f.get("org") or f.get("tenant", ""))) | |
| 482 | + Path(args.out).write_text( | |
| 483 | + json.dumps(confirmed, ensure_ascii=False, indent=2) + "\n", | |
| 484 | + encoding="utf-8") | |
| 485 | + if args.rejected: | |
| 486 | + Path(args.rejected).write_text( | |
| 487 | + "\n".join(json.dumps(r, ensure_ascii=False) for r in rejected) | |
| 488 | + + "\n", encoding="utf-8") | |
| 489 | + | |
| 490 | + print(f"\n[probe] terminé en {time.time()-t0:.0f}s — {_nreq[0]} requêtes") | |
| 491 | + print(f"[probe] slugs sondés par ATS (sondés/confirmés) :") | |
| 492 | + for ats in DEFAULT_ORDER: | |
| 493 | + p, c = stats.get(ats, [0, 0]) | |
| 494 | + print(f" {ats:16s} {p:5d} / {c}") | |
| 495 | + print(f"[probe] {len(confirmed)} groupes confirmés, " | |
| 496 | + f"{len(rejected)} rejetés -> {args.out}") | |
| 497 | + | |
| 498 | + | |
| 499 | +if __name__ == "__main__": | |
| 500 | + main() | |
| 501 | ||