AI Jobs Scraper (aijobs.net) — ML & Data Roles
Pricing
Pay per usage
AI Jobs Scraper (aijobs.net) — ML & Data Roles
Extract curated AI and machine-learning vacancies from aijobs.net: ML engineer, data scientist, MLOps, research scientist and more. Records include title, company, location, salary band, seniority and apply URL. The cleanest single source for AI hiring data.
Fetch curated AI / ML / data-science openings from aijobs.net with salary bands (where disclosed) and seniority levels.
What AI jobs data does this scraper extract?
Each result is one flat JSON record per job posting:
| Field | Meaning |
|---|---|
id | Stable source-side identifier |
slug | URL slug segment of the posting |
title | Job title as posted |
company | Hiring company / organisation. null by default — the listing page never shows it, only each job's own detail page does. Set includeCompany: true to fetch it (one extra request per job). |
location | Location / duty station (may include remote hints), or null |
url | Direct link to the posting |
postedAt | Relative posting age as shown by the source (e.g. "5d ago"), or null |
seniority | Experience-level badge from the card: Entry-level, Mid-level, Senior-level or Executive-level, or null |
snippet | Short description excerpt (from the listing card, ~400 chars) |
description | Fuller JD text (Tasks / Perks / Skills / Education / Roles) assembled from the job's detail page, up to 5000 chars. Only populated when includeCompany: true fetches that page (same request, no extra cost); null otherwise |
salary | Raw salary-band text, e.g. "USD 80K-160K". Only ~half of postings disclose one; null otherwise |
salaryMin / salaryMax | Parsed band bounds (whole currency units, e.g. 80000), or null |
salaryCurrency | 3-letter currency code parsed from the badge, or null |
salaryPeriod | Pay period (year/month/hour) — always null; the source never labels which period the band covers |
How to scrape AI jobs with this Actor
- Click Try for free / Run — no login to the target site, no cookies, no proxies to configure.
- Adjust the input (
maxItems,euBias,includeCompany) or keep the defaults. - Run it and export the dataset as JSON, CSV or Excel, or read it over the API.
Run it from your own code:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("nomad-agent/ai-jobs-net-scraper").call(run_input={"maxItems": 50, "includeCompany": True})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["title"], "—", item["company"], item["url"])
Or a single HTTP call that runs the Actor and returns items in one response:
curl -X POST \"https://api.apify.com/v2/acts/nomad-agent~ai-jobs-net-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H "Content-Type: application/json" \-d '{"maxItems": 50}'
Input
| Field | Type | Default | Notes |
|---|---|---|---|
maxItems | integer | 50 | Maximum number of job listings to return. aijobs.net's listing is a single, non-paginated page holding roughly 40-50 cards — this Actor cannot structurally return more than that page has, however high you set this. Set 0 to return every card found. |
euBias | boolean | false | When enabled, listings whose location or title hints at a European country or remote-EU are sorted to the top. Non-EU jobs are still returned; they just appear later. |
includeCompany | boolean | false | The listing page never shows the company name — only the per-job detail page does. Enable this to fetch that page (one extra request per job) and populate company and description. Off by default, in which case both stay null. |
cacheTtlSeconds | integer | 1800 | (Advanced) Cache the upstream fetch(es) in the key-value store for this many seconds; re-runs within the window skip the network call. Set 0 to disable. |
Output example
Default run (includeCompany: false):
{"id": "200475","slug": "competitive-coder-remote","title": "Competitive Coder","company": null,"location": "Remote","url": "https://aijobs.net/job/competitive-coder-remote-200475/","postedAt": "5d ago","seniority": "Entry-level","snippet": "Competitive Coder USD 80K-160K C plus plus | Codeforces | Competitive programming ...","description": null,"salary": "USD 80K-160K","salaryMin": 80000,"salaryMax": 160000,"salaryCurrency": "USD","salaryPeriod": null}
With includeCompany: true, company and description are both populated (e.g. company: "micro1", description: "Tasks: ... | Perks/Benefits: ... | Skills/Tech-stack: ... | Education: ... | Roles: ...") at the cost of one extra HTTP request per job — the same detail-page fetch fills both fields. Roughly half of postings don't disclose a salary band at all; on those, salary, salaryMin, salaryMax and salaryCurrency are all null.
Pricing
Pay per event: $0.05 per Actor start and $0.004 per job returned.
100 jobs ≈ $0.45. No subscription, no rental — you pay only for what you fetch. Enabling includeCompany adds an extra request per job but does not change the per-job price.
Use cases
- AI-specialist job boards and newsletters
- Tracking ML-engineer demand and salaries
- Sourcing AI talent pipelines
- Feeding the ml-ai-dev-bundle with anchor data
FAQ
Is it legal to scrape AI jobs? This Actor reads only publicly available job postings — data any visitor can see without logging in. No personal data behind authentication is touched. Review the target site's terms and your local regulations for your specific use case.
Do I need an account on the target site? No. Postings are fetched from public pages/APIs — no login, cookies or session tokens.
How fresh is the data?
Every run fetches live listings. Results are cached for cacheTtlSeconds (default 30 min, set 0 to always hit the source live).
How many jobs can I get?
maxItems caps the run, up to whatever the aijobs.net homepage currently holds — typically 40-50 listings. This is a single, non-paginated page, so that's the hard ceiling; there's no "page 2" to crawl for more.
Why is company empty?
By default this Actor doesn't fetch it — the listing page never includes the company name, only each job's own detail page does. Set includeCompany: true to fetch it (one extra request per job).
Something broken or missing? Open an issue on the Actor's Issues tab — it is monitored and reliability fixes ship fast.
Integrations
Export the dataset as JSON, CSV, Excel/XLSX, or plug it straight into Make, Zapier or n8n via the Apify integrations. For one-shot pulls, call run-sync-get-dataset-items to run the Actor and get items back in a single HTTP response, or drive it through the Apify MCP server from any MCP-compatible agent.