ConstructionJobs.com Scraper — Full Board
Pricing
from $1.70 / 1,000 jobs
ConstructionJobs.com Scraper — Full Board
Scrape US construction job postings from ConstructionJobs.com: superintendents, estimators, project managers, foremen and skilled trades. Get title, hiring company, location, job category, employment type, posted and expiry dates and the full description. Export to CSV, Excel or JSON.
Pricing
from $1.70 / 1,000 jobs
Rating
0.0
(0)
Developer
Piquno
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Security
Limited permissionsShare
Scrape all live jobs (about 1,550 in November 2026) on ConstructionJobs.com, the main US construction-trades board. Superintendents, estimators, project managers, skilled trades, equipment operators.
HTTP-only, no browser. 29 flat fields per job, ready for CSV or Excel.
$2.00 per 1,000 jobs. No charge for empty rows.
Why this one
Nothing else on the Store covers this site. Four searches for it returned only unrelated boards.
More importantly, the obvious way to scrape it is broken, and quietly so.
The paged listing hides part of the board
/jobs?page=N shows 21 jobs a page, and in November 2026 its pagination ran to page 48 — about 1,000 jobs — while the sitemap listed roughly 1,550.
A page-loop scraper therefore misses the rest of the board — and reports success the whole time. This actor seeds from the sitemap instead and reaches the entire board. The paged listing is used only as a deliberate "recent only" mode for cheap daily watches, or as a fallback, named in the run's status message, when the sitemap yields no job URL.
The site's structured data has not always parsed
Every job page carries a JSON-LD JobPosting block. When checked in August 2026, JSON.parse threw on 100% of them, for two independent reasons:
- The
descriptionfield held raw HTML with unescaped double quotes (<div style="margin-left:auto;">), which terminated the JSON string early. PostalAddresscarried a trailing comma before its closing brace.
The pages checked in November 2026 parse as they are; this actor still repairs both faults if they return, and recovers the complete record, description included.
Its salary figure is wrong, so we don't use it
The JSON-LD baseSalary has been observed as minValue: 0, maxValue: 0 on postings that display a real range, and elsewhere as min == max with the wrong period. Salary is read from the page's own Salary block instead — scoped to the posting, because the page also renders a "Related Jobs" rail containing other jobs' pay. A body-wide match silently attaches a different job's salary, and there's a regression test for exactly that.
Input
{"seedMode": "sitemap","maxJobs": 500,"titleContains": "superintendent","locationState": "Texas"}
Defaults: maxJobs is 50, a quick sample that finishes in about 80 seconds. Each job is one request at roughly one per second, so raise it for a full extract and give the run enough time.
| Mode | Reaches | Use for |
|---|---|---|
| Full board (sitemap) | all jobs (about 1,550 in November 2026) | complete extracts, market analysis |
| Recent only (paged) | newest ~714 | cheap daily monitoring |
Each job checked is one request, so without filters maxJobs is also your request count.
Monitoring the board
Set incremental: true with seedMode: "recent" and its own stateKey. Only postings not seen before are emitted, tagged changeType: "new".
Output
{"jobId": "yard-truck-driver-yard-jockey","title": "Yard Truck Driver - Yard Jockey","normalizedJobTitle": "CDL Driver, Yard Associate","jobFunction": "Equipment & Fleet, Warehouse & Distribution","employmentType": "FULL_TIME","employerName": "48forty Solutions and Relogistics Services","employerProfileUrl": "https://constructionjobs.com/employer/48forty-solutions-and-relogistics-services","locationCity": "Fontana","locationState": "California","locationPostalCode": "92335","salaryMin": 30,"salaryMax": 30,"salaryPeriod": "hourly","educationLevel": "Any","experienceLevel": "N/A","vacancies": 1,"datePosted": "2026-07-09T17:02:26.000Z","validThrough": "2026-09-21T00:00:00.000Z","fieldsPopulated": 28}
employerSlug and employerProfileUrl let you join postings to the site's employer profiles.
Field fill rates
| Field | Fill |
|---|---|
jobId, title, employerName, locationCity, datePosted | 100% across all test fixtures |
jobFunction, educationLevel, experienceLevel, vacancies | high |
salaryMin / salaryMax | a minority — most construction postings withhold pay |
description | 100%, from the JSON-LD (repaired when malformed) |
Nothing is inferred. A posting whose own block reads "Salary Not Specified" returns null, not a number borrowed from elsewhere on the page.
Pricing
| Event | Price |
|---|---|
| Job | $0.002 ($2.00 / 1,000) |
| Actor start | $0.00005 |
A row is billed only if its page holds a job posting (a JSON-LD JobPosting block or a title), and it is billed before it is pushed — so you are never charged for a row you did not receive. Rows removed by your filters are never billed.
Limitations — read before you buy
- One request per job. There is no bulk endpoint; a full-board extract is as many requests as the board has jobs (about 1,550 in November 2026). Budget the time.
- Salary is often absent. Use
withSalaryOnlyif you need it, and expect a much smaller result set. - Employer contact details are not available. Phone and email sit behind a login wall on employer profiles and are simply not in the HTML. This actor does not promise them.
experienceLevelis frequently "N/A" — that is what the employer entered, not a parsing failure.- Format risk. The JSON-LD parsed as is on the pages checked in November 2026; if its two old faults return, the repair path takes over automatically. If the structure changes more deeply, a page that holds no job posting is skipped and never billed (30 in a row stop the run); a page that still holds one is saved, and billed, with whatever fields still parse.
Running locally
npm installnpm test
Tests run against captured live pages in test/fixtures/ — no network required. They assert the things that actually break this scraper: that the sitemap index is followed to its job sitemap, that malformed JSON-LD repairs on every fixture that has it, that a trailing-comma fix alone is not sufficient, and that salary is never borrowed from the Related Jobs rail.