Most job-scraping guides point you at corporate ATS boards — Greenhouse, Lever,
Ashby. Those only carry mid-to-large-company tech and office roles. The entire
local German labour market — trades, care, hospitality, retail, mini-jobs — is
posted somewhere else entirely: the Jobs (Stellenangebote) section of
Kleinanzeigen. If you want hyper-local hiring data, that's the source.
Why Kleinanzeigen for jobs?
- Hidden inventory — small businesses, shops, restaurants and private employers post here directly; these roles are absent from corporate boards and aggregators.
- Hyper-local — search any city or PLZ with a radius.
- Structured fields — employment type, job category, hourly/monthly pay and experience level, once you parse the detail page.
Parsing the German job attributes
The key insight is what each German attribute actually means — it's easy to get
these backwards:
-
Arbeitszeit→ employment type (Vollzeit / Teilzeit / Minijob) -
Art→ job category (Reinigungskraft, Verkäufer/-in, …) -
Stundenlohn→ hourly wage -
Berufserfahrung→ experience level
def parse_job(attrs: dict):
a = {k.lower(): v for k, v in attrs.items()}
def find(*keys): # keys tried in priority order
for k in keys:
for label, val in a.items():
if k in label:
return val
return {
"employment_type": find("arbeitszeit", "anstellung"),
"job_category": find("art"),
"experience": find("berufserfahrung", "erfahrung"),
"salary": find("stundenlohn", "gehalt"),
}
The attribute rows come off the detail page the same way as any Kleinanzeigen
section (read the .addetailslist--detail--value node, strip it from the row text
to get the label), and you'll want a residential DE proxy plus the
location-autocomplete endpoint to turn a city name into the internal location ID.
One handy quirk: titles contain the role
Unlike cars (where titles often omit the make), job titles reliably contain the
role — "Reinigungskraft (m/w/d)", "LKW Fahrer in Vollzeit". So a client-side
title filter on a keyword like fahrer or pflegekraft works well, on top of the
location browse.
The catch: scale and upkeep
Paging results, fetching each detail page politely, mapping the German attributes
correctly, extracting pay from messy free text, and rotating residential IPs — then
maintaining it — adds up fast.
The no-code option
The Kleinanzeigen Jobs Scraper
on Apify does it for you: enter a role and a location (or leave the role blank for
everything in the area), click Run, get clean rows.
{
"keyword": "fahrer",
"locationCode": "münchen",
"radiusKm": 20,
"employmentType": "Vollzeit",
"maxResults": 100
}
Output is one clean row per ad — title, job category, employment type, salary +
period, experience, company, city, PLZ, posting date and the listing URL — ready
for a spreadsheet, a database, or an LLM.
Common use cases
- Recruiting & sourcing — find local hires and employers outside the big boards.
- Labour-market analysis — track local demand, wages and employment types by region.
- Job-board aggregation — enrich your board with hyper-local German listings.
- Lead generation — small employers actively hiring are strong B2B leads.
FAQ
How is this different from an ATS scraper? Corporate boards carry mid/large-company
roles only. Kleinanzeigen carries local, hourly, trade, care and mini-jobs — a
completely different, hyper-local inventory.
Do I need an API key? No — a residential DE proxy is used automatically.
Is this legal? You're reading publicly available listing data. Use it responsibly
and within applicable laws and Kleinanzeigen's terms.
Building something with German job data? The Kleinanzeigen Jobs Scraper handles the scraping so you can focus on the product.
Top comments (0)