Job Bank Canada Jobs Scraper
Pricing
from $0.84 / 1,000 results
Job Bank Canada Jobs Scraper
Canadian job postings from the Government of Canada's Job Bank: title, employer, city and province, salary with its unit, work arrangement and apply method. Includes LMIA status and employment-equity tags that commercial job boards do not carry.
Pricing
from $0.84 / 1,000 results
Rating
0.0
(0)
Developer
Ibnu Adzim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Job postings from Job Bank (jobbank.gc.ca), the Government of Canada's national employment service and the country's largest single source of vacancies — as structured rows: title, employer, city and province, salary with its unit, work arrangement and how to apply.
Public-sector data. No login, no API key, no browser.
What makes this dataset distinctive
LMIA status. A Labour Market Impact Assessment is what a Canadian employer
must obtain before hiring a foreign worker, so "does this posting have one" is
the single most consequential fact on the page for anyone applying from outside
Canada. It is a first-class filter here (lmia: requested | approved), and no
commercial job board publishes it.
Employment equity tags. Job Bank marks postings that explicitly welcome
Indigenous people, newcomers to Canada, persons with disabilities, veterans,
mature workers, youth and visible minorities. equityGroups filters on them.
Facet counts for the whole search. Every run's summary row carries
facetCounts — the board's own tally behind each filter (67 entries on a
measured search): jobs per province, per salary band, per work term, per equity
group, per LMIA status. That is a free aggregation over the entire result set,
not just the pages you fetched.
What you get
One SEARCH_SUMMARY row per search term, then one JOB row per posting.
| Group | Fields |
|---|---|
| Identity | jobId, jobNumber, jobUrl, title, employer, postedDate |
| Location | locationRaw, city, province |
| Pay | salaryRaw, salaryMin, salaryMax, salaryUnit |
| Nature of the role | workArrangement, applyMethod, isNew, postedOnJobBank |
| Provenance | _input, _source, _scrapedAt, pageFound, raw |
Salary carries its period. Job Bank quotes pay hourly, weekly, bi-weekly,
monthly and annually in a single free-text field, and appends commission
language to it. Comparing an hourly figure to an annual one without reading
salaryUnit is roughly a 2,000x error, so nothing is converted between periods
and the unit sits beside the number.
salaryMax is populated only for a genuine range ("$20.00 to $25.00 hourly").
A trailing "+ 3% commission per sale" stays in salaryRaw and is never
mistaken for an upper bound — an earlier build did exactly that and published a
maximum salary of three dollars.
postedOnJobBank distinguishes postings the employer submitted here
directly from ones syndicated in off external boards — useful when you want the
primary source rather than an aggregator's copy.
Example input
{"queries": ["software developer", "data analyst"],"provinces": ["ON", "BC"],"workTerm": "permanent","postedWithin": "30d","maxPages": 20}
Looking for roles open to foreign applicants:
{"queries": ["cook", "truck driver", "farm worker"],"lmia": "approved","maxPages": 40}
Limits and behaviours worth knowing
This Actor is deliberately slow, and that is the point. Job Bank's
robots.txt disallows nothing at all but asks for Crawl-delay: 5. That request
is honoured as a floor: five seconds between request starts, concurrency 1 by
default, and setting minRequestInterval lower does not speed it up. A public
service that hides nothing and asks politely gets read politely.
Work location and LMIA cannot be combined. Upstream they share a single parameter, so sending both would silently drop one. The Actor refuses the combination instead — run two searches.
"More than 30 days" means older, not within. That is Job Bank's own
wording for the third postedWithin option, kept rather than reinterpreted.
A search matching nothing reports zero. The result count is read from its
own element rather than inferred from the absence of cards, so an empty search
comes back as upstreamTotalResults: 0 with stoppedReason: no_results — not
as an error and not as a missing value.
Bad filter values are refused before any request rather than sent and guessed at.
How it works
HTTP-only. Job Bank is a server-rendered Jakarta Faces application with no JSON
layer anywhere — no __NEXT_DATA__, no JSON-LD, no hydration blob — so the
rows come from its HTML, which is unusually clean and semantically classed.
Two things about that HTML would quietly corrupt a dataset and are handled explicitly:
- Every posting URL carries a session id. Links look like
/jobsearch/jobposting/50209079;jsessionid=F2A25A…, where the path parameter is this crawl's server session. Left in, it would rot immediately and make the same job look like a new URL on every run. It is stripped. - Screen-reader-only labels sit inside the data elements. Job Bank is built
on the Web Experience Toolkit, whose
wb-invclass marks text meant only for assistive technology — and those spans live inside the very<li>elements holding the location and salary. Flattening tags naively yields a city of "Location Surrey". They are removed before any field is read.
No WAF was measured: six different TLS fingerprints all received identical pages.