# Academic Jobs Scraper: Nature, Science, Chronicle, THE (`maxqim/academic-science-jobs-scraper`) Actor

Scrape academic, faculty, postdoc and research jobs from Nature Careers, Science Careers, The Chronicle of Higher Education, THE Unijobs and Inside Higher Ed (plus any Madgex job board). Salary, closing date, discipline, full description. Pay per result.

- **URL**: https://apify.com/maxqim/academic-science-jobs-scraper.md
- **Developed by:** [miao qi](https://apify.com/maxqim) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 job listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Academic Jobs Scraper: Nature Careers, Science Careers, Chronicle & THE Unijobs

Scrape **academic, faculty, postdoc, PhD and research jobs** from five of the biggest higher-education and science job boards in one run:

| Board | Coverage |
| --- | --- |
| **Nature Careers** (nature.com/naturecareers) | Science & research jobs worldwide (Europe, China, US) |
| **Science Careers** (jobs.sciencecareers.org, AAAS) | Faculty, postdoc and industry science jobs |
| **The Chronicle of Higher Education Jobs** (jobs.chronicle.com) | US faculty, administrative and executive jobs in higher ed |
| **THE Unijobs** (Times Higher Education) | UK, Europe, Middle East and Asia university jobs |
| **Inside Higher Ed Careers** (careers.insidehighered.com) | US college and university jobs |

All five run on the Madgex job-board platform, so you can also paste search URLs from **other public Madgex job boards** and get the same clean output.

No login, no browser, no cookies. Plain HTTP requests, so runs are fast and cheap.

### What data do you get?

For every job:

- Job title, URL and board job ID
- Employer (university / institute / company) and logo
- Location, plus country, region and city when the board provides them
- Salary text as published (e.g. "$75,000 per year plus benefits", "Grade 7, £38,000 - £45,000")
- Date posted and closing date / valid-through date
- Discipline / academic field, job type, position type, contract type (permanent / fixed term), hours (full / part time), qualification, sector, institution type
- Full job description as plain text (optional: original HTML)
- Promoted/premium flag
- All "facts" shown on the job page as a key-value `attributes` object, so nothing is lost when a board uses its own labels

### Use cases

- **Academic job aggregators and newsletters**: one feed of postdoc and faculty openings from Nature, Science, Chronicle, THE and Inside Higher Ed
- **University recruitment and HR benchmarking**: who is hiring, in which disciplines, at what salary
- **Recruitment agencies and executive search** in higher education: new leadership roles (dean, provost, president) the day they appear
- **Market research / labor market analytics**: hiring demand by field, country and contract type over time
- **Career services**: daily alerts for students and postdocs in a specific field
- **AI agents and RAG**: structured, deduplicated job data with full text

### How to use

1. Type **keywords** (e.g. `postdoc machine learning`, `assistant professor chemistry`, `lecturer nursing`) or leave empty for everything.
2. Pick the **job boards** you want.
3. Set **Max jobs** and click Start. Download as JSON, CSV, Excel, or use the API.

Want a filter the form does not have (country, discipline, salary band, job type)? Apply it on the board's website, copy the URL from the address bar and paste it into **Start URLs**.

#### Input example

```json
{
  "keywords": "postdoc",
  "sites": ["nature", "science", "chronicle", "the", "insidehighered"],
  "maxItems": 500,
  "includeDetails": true,
  "locationContains": ""
}
```

Using start URLs (any Madgex board, any filters):

```json
{
  "sites": [],
  "startUrls": [
    { "url": "https://jobs.chronicle.com/searchjobs/?Keywords=nursing" },
    { "url": "https://www.timeshighereducation.com/unijobs/searchjobs/?Keywords=lecturer" }
  ],
  "maxItems": 200
}
```

#### Output example

```json
{
  "jobId": "680679",
  "title": "PhD Student or Postdoc (f/m/x)",
  "url": "https://jobs.sciencecareers.org/job/680679/phd-student-or-postdoc-f-m-x-/",
  "employer": "Max Planck Institute for Multidisciplinary Sciences",
  "location": "Göttingen (Stadt), Niedersachsen (DE)",
  "salary": "German Public Service Payscale",
  "shortDescription": "PhD/Postdoc in theoretical and computational biophysics at the Max Planck Institute Göttingen, focusing on biomolecular simulations and methods.",
  "isPromoted": false,
  "site": "science",
  "siteName": "Science Careers",
  "descriptionText": "The Max Planck Institute for Multidisciplinary Sciences is a leading international research institute with exc ...",
  "datePosted": "2026-10-09",
  "validThrough": "2026-11-09",
  "employmentType": [
    "FULL_TIME"
  ],
  "country": "DE",
  "attributes": {
    "Employer": "Max Planck Institute for Multidisciplinary Sciences",
    "Location": "Göttingen (Stadt), Niedersachsen (DE)",
    "Salary": "German Public Service Payscale",
    "Closing date": "Nov 8, 2026",
    "Discipline": "Life Sciences, Biophysics",
    "Position Type": "Full Time",
    "Job Type": "Postdoc",
    "Organization Type": "Academia"
  },
  "closingDate": "Nov 8, 2026",
  "discipline": "Life Sciences, Biophysics",
  "positionType": "Full Time",
  "jobType": "Postdoc",
  "institutionType": "Academia",
  "scrapedAt": "2026-10-28T05:07:25+00:00"
}
```

See `sample_output.json` for 10 real records (2 per board).

### Pricing

Pay per result: **$3.00 per 1,000 jobs** (event `job`, charged once per job saved), detail pages included. No charge for jobs filtered out by your location filter. Set **Max jobs** or a maximum cost per run and the Actor stops exactly there.

### Tips

- Turn off **Open job detail pages** if you only need title, employer, location and salary: about 10x faster.
- Each listing page has ~20 jobs; **Max listing pages per board** is a safety limit.
- For other Madgex boards that block datacenter IPs, enable Apify Proxy (residential).
- Schedule the Actor daily with `maxItems` and compare by `jobId` to get only new postings.

### FAQ

**Is it legal to scrape these job boards?** The Actor only reads publicly available job advertisements that anyone can open without logging in, at a polite rate, and it does not collect applicant data or personal contact details. You are responsible for how you use the data; check the boards' terms for your use case.

**Why are some fields empty?** Each board shows different facts (e.g. Chronicle has "Institution Type", Nature has "Qualification"). Everything the board shows is kept in `attributes`.

**Can you add another academic job board?** Yes. Open an issue with the URL. If it runs on Madgex (look for `/searchjobs/` and `/job/<id>/` in its URLs), try it with Start URLs first: it probably already works.

**The run returned fewer jobs than the website shows.** Check `maxItems`, `maxPagesPerSource` and `locationContains`. Duplicate jobs (same ID on the same board) are removed.

# Actor input Schema

## `keywords` (type: `string`):

Search phrase, e.g. "postdoc machine learning", "assistant professor chemistry". Leave empty to get all jobs on the selected boards.

## `sites` (type: `array`):

Which boards to search.

## `startUrls` (type: `array`):

Any search or browse URL from a supported board (with your filters applied in the browser), or from another public Madgex-powered job board. Example: https://jobs.chronicle.com/searchjobs/?Keywords=nursing

## `maxItems` (type: `integer`):

Stop after this many jobs in total (0 = no limit). You pay per job saved.

## `includeDetails` (type: `boolean`):

Adds full description, date posted, closing date, discipline, contract type, hours and other facts. Slower but much richer.

## `includeDescriptionHtml` (type: `boolean`):

Also return the original HTML of the job description (plain text is always included when details are on).

## `locationContains` (type: `string`):

Keep only jobs whose location contains this text, e.g. "London", "CA", "Germany".

## `maxPagesPerSource` (type: `integer`):

Safety limit; each page has ~20 jobs.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep it low to be polite to the boards.

## `proxyConfiguration` (type: `object`):

Not needed for the default boards. Enable for other Madgex boards that block datacenter traffic.

## Actor input object example

```json
{
  "keywords": "postdoc",
  "sites": [
    "nature",
    "science",
    "chronicle",
    "the",
    "insidehighered"
  ],
  "maxItems": 100,
  "includeDetails": true,
  "includeDescriptionHtml": false,
  "maxPagesPerSource": 50,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped job listings, one item per job.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": "postdoc"
};

// Run the Actor and wait for it to finish
const run = await client.actor("maxqim/academic-science-jobs-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "keywords": "postdoc" }

# Run the Actor and wait for it to finish
run = client.actor("maxqim/academic-science-jobs-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": "postdoc"
}' |
apify call maxqim/academic-science-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maxqim/academic-science-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HZtetrA4SFxUS0eJK/builds/qgAcsXmaG3jOYb6M7/openapi.json
