If you want used-car data from Germany, everyone reaches for mobile.de — but
that's the dealer market. The private-seller market lives on
Kleinanzeigen Autos, and it's where the deals (and the arbitrage) are. This post
shows how to pull structured car listings — make, model, year, mileage, fuel,
gearbox, power and price — out of it.
Why Kleinanzeigen for cars?
- Private sellers — typically cheaper than dealer platforms; ideal for deal-hunting and market analysis.
- Different inventory — a complement to mobile.de, not a duplicate.
- Rich attributes — once you parse the detail page you get the full German spec sheet, not just a title and a price.
Parsing the German car attributes
Kleinanzeigen stores the spec sheet as label/value rows. Map the German labels to
clean English keys, with a regex fallback on the title for year and mileage when a
field is missing:
import re
from bs4 import BeautifulSoup
YEAR = re.compile(r"\b(?:19|20)\d{2}\b")
KM = re.compile(r"([\d.]+)\s*km\b", re.I)
def parse_car(attrs: dict, title: str):
a = {k.lower(): v for k, v in attrs.items()}
def find(*keys):
for label, val in a.items():
if any(k in label for k in keys):
return val
er = find("erstzulassung") or ""
ym = YEAR.search(er) or YEAR.search(title)
return {
"make": find("marke"),
"model": find("modell"),
"year": int(ym.group()) if ym else None,
"mileage_km": find("kilometerstand"),
"fuel": find("kraftstoff"),
"transmission": find("getriebe"),
"power": find("leistung"),
}
The attribute rows themselves come off the detail page like this:
soup = BeautifulSoup(html, "lxml")
attrs = {}
for li in soup.select(".addetailslist--detail"):
val = li.select_one(".addetailslist--detail--value")
if not val:
continue
v = val.get_text(" ", strip=True)
label = li.get_text(" ", strip=True).replace(v, "", 1).strip()
attrs[label] = v
As with any Kleinanzeigen section, you'll want a residential DE proxy and the
location-autocomplete endpoint to turn a city name into the internal location ID.
One gotcha: make is a facet, not free text
Kleinanzeigen treats the car make as a structured filter, and many listing titles
omit the brand (e.g. "320d Touring, Automatik"). So a naive keyword search on
"BMW" misses cars. The robust approach is to browse the Autos category by location
and filter make/model client-side from the parsed make field — or paste a search
URL with the make facet already selected.
The catch: scale and upkeep
Paging hundreds of results, fetching each detail page politely, normalizing the
German spec sheet, handling the make-facet quirk, and rotating residential IPs —
then keeping it alive as the site changes — is real, ongoing work.
The no-code option
The Kleinanzeigen Autos Scraper
on Apify does it for you: pick a location (and optional price/year/mileage filters),
click Run, get clean rows.
{
"locationCode": "berlin",
"maxPrice": 20000,
"minYear": 2016,
"maxMileage": 120000,
"maxResults": 100
}
Output is one clean row per car — make, model, year, first registration, mileage,
price, fuel, transmission, power, condition, color, city and the listing URL —
ready for a spreadsheet, a database, or an LLM.
Common use cases
- Deal-hunting & arbitrage — spot underpriced private-seller cars fast.
- Price & market analysis — track asking prices by make/model/region over time.
- Dealers & resellers — source private inventory and leads.
- Automotive apps — power a search product with structured listings.
FAQ
How is this different from mobile.de? Kleinanzeigen is dominated by private
sellers and budget cars — a different inventory, useful for arbitrage and broader
coverage.
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 car data? The Kleinanzeigen Autos Scraper handles the scraping so you can focus on the product.
Top comments (0)