AcademicPositions Job Scraper — EU Academic Jobs avatar

AcademicPositions Job Scraper — EU Academic Jobs

Pricing

from $6.50 / 1,000 job results

Go to Apify Store
AcademicPositions Job Scraper — EU Academic Jobs

AcademicPositions Job Scraper — EU Academic Jobs

Scrape postdoc jobs, PhD positions & faculty jobs from academicpositions.com (EU, UK & Switzerland). A real browser via residential proxy passes Cloudflare. Returns title, institution, location, field, salary, posted date & apply URL — with delta mode for new-only scheduled runs.

Pricing

from $6.50 / 1,000 job results

Rating

0.0

(0)

Developer

Nomad.Dev

Nomad.Dev

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Fetch postdoc, PhD, faculty and early-career-researcher openings from academicpositions.com, covering institutions across the EU, UK and Switzerland.

How it works

academicpositions.com sits behind Cloudflare's bot protection, so this Actor drives a real headless browser (Playwright/Chromium) through an Apify Residential proxy to load pages the same way a person's browser would. Each posting is parsed from the page's structured JobPosting data (schema.org JSON-LD), with a plain-HTML fallback for the rare page that omits it — so results stay accurate even as the site's front-end layout changes.

What data does this Actor extract?

Each result is one flat JSON record per job posting:

FieldTypeDescription
titlestringJob title as posted
companystring | nullHiring institution name
locationstring | nullPosting location (city/region/country, or "remote" wording for remote roles)
fieldstring | nullResearch area / discipline the posting itself labels (e.g. "Physics", "Life sciences"), read verbatim from JSON-LD occupationalCategory/industry or a discipline chip — never inferred from the title
urlstringDirect link to the posting
postedAtstring | nullPosting date (ISO 8601, e.g. "2026-06-20"), when the source provides one
snippetstring | nullPlain-text excerpt of the job description
salarystring | nullHuman-readable pay summary (e.g. "3000-4200 EUR MONTH"), only when the posting discloses baseSalary — most academic postings don't, so usually null
salaryMin / salaryMaxnumber | nullStructured pay range endpoints from JSON-LD baseSalary, when present
salaryCurrencystring | nullCurrency code for the salary range (e.g. "EUR"), when present
globalIdstring | nullStable cross-run id (academicpositions:<detail-path>) — the dedup key for delta mode
isNewboolean | nullOnly present in delta mode (onlyNewSinceLastRun) — always true (already-seen postings are dropped, never emitted with isNew: false)
sourcestringAlways "academicpositions"

Fields come back as null (never an empty string) on the rare posting where the source doesn't provide that piece of data.

How to scrape academicpositions.com with this Actor

  1. Click Try for free / Run — the default input needs no changes.
  2. Optionally set a keyword, countryFilter or postedSince to narrow results, and adjust maxItems.
  3. 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 ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("nomad-agent/academicpositions-scraper").call(
run_input={"maxItems": 30, "keyword": "machine learning postdoc"})
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~academicpositions-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"maxItems": 30}'

Input

FieldTypeDefaultNotes
keywordstring(empty)Free-text query appended to the listing URL (e.g. "postdoc", "computer science"). Leave empty to scrape the default listing.
countryFilterstring(empty)Case-insensitive substring match on the extracted location field (e.g. "Germany"). Applied client-side, after extraction. Leave empty to keep every location.
postedSincestring(empty)Only return postings dated on or after this date (YYYY-MM-DD). Postings without a parseable date are kept, not dropped. Leave empty to disable.
maxItemsinteger30Maximum number of postings to return. Each returned posting is billed as one dataset result — capped at 500 per run.
onlyNewSinceLastRunbooleanfalseDelta / monitoring mode: only return postings not already seen on a previous run made with this flag on. Already-seen postings are dropped before push, so you are never billed for them (see "Delta mode / monitoring").
proxyConfigurationobjectApify Residential proxyProxy used to load the site. Keep the Residential group selected — academicpositions.com blocks non-residential IPs.
startUrl (Advanced)stringhttps://academicpositions.com/find-jobsThe listing page the Actor starts from and harvests job links from. Change only to start from a specific saved-search URL instead of the default listing.
detailUrlContains (Advanced)string/ad/Only links whose URL contains this text are treated as job-detail pages. Change only if the site's URL structure changes and the Actor stops finding postings.
useResidentialProxy (Advanced, deprecated)booleantrueSuperseded by proxyConfiguration above. Still honored when proxyConfiguration is left unset, for older integrations.

Output example

{
"title": "Postdoctoral Researcher in Quantum Computing",
"company": "TU Delft",
"location": "Delft, Netherlands",
"field": "Physics",
"url": "https://academicpositions.com/ad/tu-delft/2026/postdoctoral-researcher-in-quantum-computing/12345",
"postedAt": "2026-06-20",
"snippet": "Join our lab working on superconducting qubits and scalable quantum error correction...",
"salary": null,
"salaryMin": null,
"salaryMax": null,
"salaryCurrency": null,
"globalId": "academicpositions:ad/tu-delft/2026/postdoctoral-researcher-in-quantum-computing/12345",
"source": "academicpositions"
}

Delta mode / monitoring

Set onlyNewSinceLastRun: true to turn this Actor into a "what's new" monitor. Postings already delivered on a previous run made with this flag on are dropped before the billed push step — you are not charged for them — so pairing this with an Apify schedule (cron) means every run only returns, and only bills for, academic jobs that appeared since the last flagged run. Each emitted record is stamped isNew: true.

How it works: seen postings are tracked in a dedicated key-value store keyed by each posting's globalId (a stable id derived from its canonical detail-page URL), capped at ~50,000 entries with the oldest evicted first. The first run made with the flag on has nothing to compare against, so it emits everything. There is no isNew: false in the output — unseen-yet postings simply aren't included.

Pricing

Pay per event: $0.02 per Actor start and $0.008 per posting returned ($8 / 1,000 postings, less on higher Apify plans — down to $6.50 / 1,000). 100 postings ≈ $0.82. No subscription, no rental — you pay only for what you fetch. The price covers the real headed browser + residential proxy each run needs to pass Cloudflare.

This Actor also routes every request through Apify's Residential proxy group (required to get past academicpositions.com's bot protection), which is billed separately by Apify against your account's residential proxy GB allowance in addition to the per-event charges above.

Integrations

Export results as JSON, CSV or Excel, pull them via the Apify API or run-sync-get-dataset-items, wire this Actor into Make, Zapier or n8n, or call it from AI agents through the Apify MCP server.

Use cases

  • Academic job boards and alert bots for postdocs, PhD candidates and faculty
  • University career-services aggregation
  • Research on hiring trends across EU/UK/CH institutions
  • Building a searchable database of research openings

FAQ

Is it legal to scrape academicpositions.com? This Actor reads only publicly available job postings — data any visitor can see without logging in. Review the target site's terms and your local regulations for your specific use case.

Do I need an account on academicpositions.com? No. Postings are fetched from public pages — no login, cookies or session tokens required.

Why does this Actor need a residential proxy? academicpositions.com fronts its pages with Cloudflare Bot Fight Mode, which blocks datacenter IPs outright. A residential exit IP plus a real browser is what reliably gets through the challenge.

How fresh is the data? Every run fetches live listings directly from the site — there's no cache.

Something broken or missing? Open an issue on the Actor's Issues tab — it is monitored and reliability fixes ship fast.