# Ausbildung.de Scraper (`steadyscrape/ausbildung-de-scraper`) Actor

Scrape Ausbildung.de apprenticeship places (Ausbildungsplätze), dual study and school internships by job title and city: employer, location, start date, places, training pay per year, school qualification and full description. Export to JSON, CSV or Excel, or via API.

- **URL**: https://apify.com/steadyscrape/ausbildung-de-scraper.md
- **Developed by:** [Steady Scrape](https://apify.com/steadyscrape) (community)
- **Categories:** Jobs, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 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

## Ausbildung.de Scraper

Scrape apprenticeship places (**Ausbildungsplätze**) from **[Ausbildung.de](https://www.ausbildung.de)**, Germany's apprenticeship
board, by **job title or keyword** and **city or postcode**. This Ausbildung.de scraper gives every listing with its
**employer** and hiring company, **location and postcode**, **number of open places** and other locations, **occupation**,
**training type** (Ausbildung, **duales Studium**, schulische Ausbildung…), **school-leaving qualification** (Abitur, Mittlere
Reife, Hauptschulabschluss), **start date**, duration and employer rating — and, from each listing's own page, the **full
description**, the **training pay per year** (Ausbildungsvergütung) when the employer gives it, the **application deadline**,
earliest start, address with the German state, industry, and the employer's website and profile. **School internships**
(**Schülerpraktikum**) are a second list, with minimum age, school class, length and tasks.

No start fee, no login, no proxy. Pay only for the listings you get; searches that find nothing cost nothing.

> This Actor is unofficial and is not affiliated with, endorsed by or connected to Ausbildung.de or Ausbildung.de GmbH.

### What you can do with this Ausbildung.de scraper

- **Recruiting and employer branding**: every company training Mechatroniker, Kaufleute or Pflegefachkräfte in your region,
  with how many places each one offers and when they start.
- **Training-pay benchmarking**: Ausbildungsvergütung per training year as numbers, by occupation, employer and state.
- **Lead generation for HR, recruiting and education services**: which employers train apprentices, how many places and
  locations they have, their websites and ausbildung.de profiles.
- **Apprenticeship and dual-study job feeds**: schedule it daily with **Only new listings** for a feed of new places into a
  spreadsheet, Slack, email or your ATS through Apify's integrations.
- **Labour-market and education research**: demand for apprenticeships and dual study by occupation, city and qualification.
- **School internship lists** for schools, career advisers and job portals.

### Input

| Field | What it does |
|---|---|
| **What to list** | Apprenticeships (with dual study and the other training types) or school internships (Schülerpraktikum). |
| **Keywords** | Occupations, study programmes or employers as people type them into ausbildung.de: `Mechatroniker`, `Kaufmann im Einzelhandel`, `Pflegefachmann`, `Informatik`, `Deutsche Bahn`. Leave empty to list every place in your cities. |
| **Cities or postcodes** | `Berlin`, `München`, `50667`… Each keyword is searched in each place. Empty for all of Germany. A place ausbildung.de does not know gives a free row instead of listings from elsewhere. |
| **Radius around each place** | 5, 10, 25 (the site's default), 50, 200, 500 or 1000 km. |
| **Training types** | Ausbildung, Duales Studium, Weiterbildung, Abiturientenprogramm, Betriebsinterne, Schulische, Schulische und duale Ausbildung. |
| **School-leaving qualification** | Abitur, Fachabitur, Mittlere Reife, Qualifizierter Hauptschulabschluss, Hauptschulabschluss, Kein Schulabschluss. |
| **Sort by** | Relevance, newest, start date or distance — the site's own sort. |
| **ausbildung.de search links** | Result lists copied from ausbildung.de with their filters (`/suche/?search=…` or `/schuelerpraktikum/stellen/?search=…`). |
| **Include job details** | On by default: opens each listing's page (charged as job-with-details). |
| **Max listings per search** | 100 by default; 0 for every listing the search shows. |
| **Only new listings since the last run** | Monitor mode for scheduled runs: listings delivered before are skipped and not charged. |

Example — dual study in computer science in Berlin and Hamburg, 50 km around, asking for Abitur:

```json
{
    "keywords": ["Informatik", "Wirtschaftsinformatik"],
    "locations": ["Berlin", "Hamburg"],
    "radiusKm": "50",
    "trainingTypes": ["duales-studium"],
    "schoolQualifications": ["abitur"],
    "maxJobsPerSearch": 0
}
```

Example — a daily feed of new Mechatroniker and Elektroniker places across Germany:

```json
{
    "keywords": ["Mechatroniker", "Elektroniker"],
    "sortBy": "newest",
    "onlyNewJobs": true,
    "maxJobsPerSearch": 200
}
```

Example — school internships in München:

```json
{
    "listingKind": "internship",
    "locations": ["München"],
    "maxJobsPerSearch": 0
}
```

### Output

One row per apprenticeship place (with job details on):

```json
{
    "jobId": "a4b009d3-37a4-4516-b54c-8e8e029b3c13",
    "postingId": "e43850ea-5bf7-4c07-aadf-57c80acc7ce8",
    "url": "https://www.ausbildung.de/stellen/ausbildung-mechatroniker-in-m-w-d-in-2027-bei-dhl-group-in-berlin-a4b009d3-37a4-4516-b54c-8e8e029b3c13/",
    "title": "Ausbildung Mechatroniker/-in (m/w/d) in 2027",
    "employer": "DHL Group",
    "hiringCompany": "Deutsche Post AG",
    "employerId": "514c3585f6497bc6f4000009",
    "employerLogo": "https://www.ausbildung.de/uploads/image/31/31c00388-d9ee-47a4-ae50-04ac20402ddc/200402_DP_DHL_Logo.jpg",
    "places": 96,
    "otherLocations": 85,
    "applicationOptions": [
        "online"
    ],
    "location": "Berlin",
    "postcode": null,
    "city": "Berlin",
    "profession": "Mechatroniker/in",
    "trainingType": "Ausbildung",
    "schoolQualification": "Mittlere Reife",
    "startDate": null,
    "duration": "3,5 Jahre",
    "applicationDeadline": null,
    "directApplication": false,
    "employerRating": 5,
    "employerReviewCount": 3,
    "topRatedEmployer": false,
    "highlighted": false,
    "postingCreatedAt": "2024-12-16T08:43:01.028Z",
    "rowType": "apprenticeship",
    "status": "ok",
    "search": "Mechatroniker · Berlin",
    "scrapedAt": "2026-10-31T12:00:00.000Z",
    "searchUrl": "https://www.ausbildung.de/suche/?search=Mechatroniker%7CBerlin",
    "position": 2,
    "details": {
        "description": "Wo? Berlin Zentrum, Eresburgstr. 21 Wann? 01.08.2027 Wie lange? 3,5 Jahre   Deine Vorteile bei der Ausbildung Mechatroniker/-in (m/w/d)  …",
        "descriptionHtml": "\n\n<ul> <li>\n<strong>Wo?</strong> Berlin Zentrum, Eresburgstr. 21</li> <li>\n<stro…",
        "employmentType": "FULL_TIME",
        "postedAt": "2026-10-09T17:03:07.340Z",
        "validThrough": null,
        "industry": "Dienstleistung",
        "street": null,
        "postcode": null,
        "city": "Berlin",
        "region": "Berlin",
        "country": "DE",
        "employerWebsite": "https://careers.dhl.com/eu/de/ausbildung",
        "employerProfileUrl": "https://www.ausbildung.de/unternehmen/deutsche-post/stellen/",
        "employerAddress": "Charles-de-Gaulle-Str. 20, 53113 Bonn",
        "parentCompany": "DHL Group",
        "applicationDeadlineText": "Laufend",
        "earliestStartText": "Nach Absprache",
        "trainingKind": "Klassische duale Berufsausbildung",
        "professionUrl": "https://www.ausbildung.de/berufe/mechatroniker/",
        "trainingPayMin": null,
        "trainingPayMax": null,
        "trainingPayByYear": []
    }
}
```

When the employer publishes its pay table, `details` also holds it, e.g. `"trainingPayMin": 1117`, `"trainingPayMax": 1294`
and `"trainingPayByYear": [{"year": 1, "monthlyEur": 1117}, {"year": 2, "monthlyEur": 1201}, {"year": 3, "monthlyEur": 1294}]`
(about a third of the pages surveyed had one).

A school internship row (`rowType: "internship"`):

```json
{
    "title": "Schülerpraktikum",
    "employer": "Sparda-Bank Hamburg eG",
    "city": "Hamburg",
    "places": 17,
    "otherLocations": 5,
    "minAge": 15,
    "minSchoolClass": 9,
    "durationMin": {
        "value": 5,
        "unit": "day"
    },
    "durationMax": {
        "value": 3,
        "unit": "week"
    },
    "internshipKinds": [
        "Pflichtpraktikum"
    ],
    "tasks": [
        "Beraten & Verkaufen"
    ],
    "relatedProfessions": [
        "Bankkaufmann/-frau",
        "Duales Studium Bank"
    ],
    "rowType": "internship",
    "url": "https://www.ausbildung.de/schuelerpraktikum/stellen/schuelerpraktikum-bei-sparda-bank-hamburg-eg-in-hamburg-2c7269d0-2a03-4a86-8025-8cba6f7d862c/"
}
```

A search that gives nothing to charge for gives one **free** row with the reason: `no_results` (nothing listed, or only
listings already delivered), `not_found` (a place ausbildung.de does not know, a page that is gone), `invalid` (a link that
is not an ausbildung.de result list), `disallowed` (a page robots.txt closes) or `blocked` (the site stopped answering). The
run's **SUMMARY** record lists, per search, the listings delivered, the postings and places the site counted, the place it
searched around, and the pages read.

#### Fields

| Field | Description |
|---|---|
| `rowType` | `apprenticeship`, `internship` or `status` (a free row with a `reason`). |
| `jobId`, `postingId`, `url`, `title` | The listing's place id (one posting can be offered at many places), the posting id, its page and title. |
| `employer`, `hiringCompany`, `employerId`, `employerLogo` | The employer's brand ("DHL Group"), the company that hires ("Deutsche Post AG"), its id and logo. |
| `places`, `otherLocations` | Open places at this location (`null` when the employer hides the count) and further locations of the same posting. |
| `location`, `postcode`, `city` | The location as shown ("53129 Bonn") and split. |
| `profession`, `trainingType`, `schoolQualification` | The occupation or study programme, the training type ("Ausbildung", "Duales Studium"…) and the qualification asked for. |
| `startDate`, `duration`, `applicationDeadline` | Earliest start (ISO date), duration as written ("3,5 Jahre", "7 Semester"), deadline (ISO date) when given. |
| `applicationOptions`, `directApplication` | How applications are taken (online, email, snailmail) and whether ausbildung.de's one-click application is on. |
| `employerRating`, `employerReviewCount`, `topRatedEmployer` | Trainees' recent reviews of the employer on ausbildung.de (1–5). |
| `highlighted`, `postingCreatedAt` | A card the site puts in its spotlight, and when the posting was first put on ausbildung.de. |
| `minAge`, `minSchoolClass`, `durationMin`, `durationMax` | Internships: youngest age, lowest school class, shortest and longest stay (`{value, unit}`). |
| `internshipKinds`, `tasks`, `relatedProfessions` | Internships: Pflicht-, freiwilliges or Schnupperpraktikum, the tasks, and the apprenticeships it leads into. |
| `search`, `searchUrl`, `position`, `scrapedAt` | Which search found the listing, the list it came from, its place in that search, and when. |
| `details.description`, `details.descriptionHtml` | The full description as text and as HTML. |
| `details.trainingPayMin`, `trainingPayMax`, `trainingPayByYear` | Monthly gross training pay in euros, per training year, when the employer gives it. |
| `details.earliestStartText`, `applicationDeadlineText`, `trainingKind`, `professionUrl` | The page's facts box as shown ("Nach Absprache", "Laufend", "Klassische duale Berufsausbildung") and the occupation's page. |
| `details.possibleDuration`, `schoolClass`, `recommendedAge`, `internshipPay` | Internships: the page's facts box as shown ("1 Woche - 3 Wochen", "Mindestens 9. Klasse", "Unvergütet"). |
| `details.street`, `postcode`, `city`, `region`, `country` | The listing's address and German state (Bundesland). |
| `details.employmentType`, `postedAt`, `validThrough`, `industry` | `FULL_TIME`, `INTERN`…, posting date, closing date, the employer's industry. |
| `details.employerWebsite`, `employerProfileUrl`, `employerAddress`, `parentCompany` | The employer's own website, its ausbildung.de profile and address, and its group. |

### Pricing

Pay per event, no start fee:

| Event | Price |
|---|---|
| `job` — a listing as its result card shows it | US$0.001 |
| `job-with-details` — a listing with its own page read | US$0.002 |

Rows with a reason and listings already delivered earlier in the run are free. Set a maximum cost per run in Apify and the
Actor stops at it.

### Limits

- **States are one point to the site**: ausbildung.de searches `Bayern` around a single spot (near Ingolstadt), so give
  cities or postcodes. A place the site cannot find gives a free `not_found` row: the Actor asks its first page twice and,
  when the two answers list different places, knows the site fell back to a spot of its own.
- **Without a place, searches are read newest first**: the site's other orders start from a spot it guesses from the
  visitor's IP, a different one on every request, so pages would not follow on from each other.
- The site breaks ties in its order anew on each request, so a card can slide from one page to the next while a list is
  read. When a whole list comes out short of the count the site gave, the Actor reads it once more for the missing cards.
- A search shows at most 10,000 postings; split a bigger one by city or training type.
- The training pay, application deadline and start date are delivered only when the employer gives them.
- The internship list's own filters (age, class, tasks) are not offered; its results carry those fields to filter on.

### Is it legal to scrape Ausbildung.de?

This Actor reads public listings that anyone can see without an account, follows the site's robots.txt, and asks for one
page a second. The **contact person's box** on each listing (name, photo, phone, e-mail) is **never read**. Descriptions are
delivered as the employer wrote them and can name a contact person. Check that your use of the data complies with
Ausbildung.de's terms, the GDPR and other laws that apply to you. This Actor is unofficial and not affiliated with
Ausbildung.de GmbH.

# Actor input Schema

## `listingKind` (type: `string`):

Apprenticeship places (Ausbildungsplätze), which include dual study (duales Studium) and the other training types below, or school internships (Schülerpraktikum), ausbildung.de's separate list for pupils.

## `keywords` (type: `array`):

Occupations, study programmes or employers as people type them into ausbildung.de, e.g. <code>Mechatroniker</code>, <code>Kaufmann im Einzelhandel</code>, <code>Pflegefachmann</code>, <code>Informatik</code>, <code>Deutsche Bahn</code>. Each is searched in each place below. Leave empty to list every place in your cities. Give at least one keyword, a city or a search link.

## `locations` (type: `array`):

German cities or postcodes, e.g. <code>Berlin</code>, <code>München</code>, <code>50667</code>. Leave empty for all of Germany (read newest first: without a place the site ranks from a spot it guesses from the visitor's IP). A place ausbildung.de does not know gives a free row instead of listings from elsewhere. States such as <code>Bayern</code> are searched as one point by the site, so give cities.

## `radiusKm` (type: `string`):

How far from each city or postcode, as ausbildung.de's radius filter offers it.

## `trainingTypes` (type: `array`):

ausbildung.de's own Art filter. Empty for every type. Not used for school internships.

## `schoolQualifications` (type: `array`):

Only places asking for one of these, as ausbildung.de's Schulabschluss filter offers them. Empty for any. Not used for school internships.

## `sortBy` (type: `string`):

The site's own sort. Without a place every search is read newest first; school internships offer only distance and newest (other choices read as distance).

## `searchUrls` (type: `array`):

Result lists copied from ausbildung.de with their filters, e.g. <code>https://www.ausbildung.de/suche/?search=Mechatroniker%7CBerlin\&radius=50</code> or <code>https://www.ausbildung.de/schuelerpraktikum/stellen/?search=Verkauf%7CHamburg</code>. The page offset is dropped; job pages are not taken.

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

Open each listing's page for the full description, address, industry, posting date, application deadline, earliest start, duration, the training pay per year when the employer gives it, and the employer's website and profile. Charged as job-with-details instead of job.

## `maxJobsPerSearch` (type: `integer`):

Stop each search (each keyword in each place, and each link) after this many listings. 0 means every listing the search shows (at most 10,000).

## `onlyNewJobs` (type: `boolean`):

Deliver, and charge, only listings that an earlier run with the same searches has not delivered. Made for scheduled runs.

## Actor input object example

```json
{
  "listingKind": "apprenticeship",
  "keywords": [
    "Mechatroniker"
  ],
  "locations": [
    "Berlin"
  ],
  "radiusKm": "25",
  "trainingTypes": [],
  "schoolQualifications": [],
  "sortBy": "relevance",
  "searchUrls": [],
  "includeDetails": true,
  "maxJobsPerSearch": 2,
  "onlyNewJobs": false
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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": [
        "Mechatroniker"
    ],
    "locations": [
        "Berlin"
    ],
    "maxJobsPerSearch": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyscrape/ausbildung-de-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": ["Mechatroniker"],
    "locations": ["Berlin"],
    "maxJobsPerSearch": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("steadyscrape/ausbildung-de-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": [
    "Mechatroniker"
  ],
  "locations": [
    "Berlin"
  ],
  "maxJobsPerSearch": 2
}' |
apify call steadyscrape/ausbildung-de-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadyscrape/ausbildung-de-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/GNjagdzh3bZjR5r4p/builds/T349aHU6a8bPz3x2s/openapi.json
