Über 160 Millionen US-Immobilien-Datensätze liegen bei Zillow – und genau dieser Schatz lässt sich überraschend schwer heben. Wer schon einmal versucht hat, Zillow per Python auszulesen, kennt das Ergebnis: Statt sauberer Inserate landet man auf einer CAPTCHA-Seite. Damit bist du in guter Gesellschaft.
Ich habe über längere Zeit verschiedene Wege ausprobiert, Zillow-Daten zu gewinnen – einmal klassisch mit Python, einmal über die No-Code-Werkzeuge, die wir bei Thunderbit gebaut haben. Beide Ansätze stehen in diesem Leitfaden nebeneinander. Wenn du das komplette Python-Tutorial samt Anti-Bot-Tricks willst, wirst du fündig. Wenn du bis zur Mittagspause schlicht 200 Inserate in einer Tabelle brauchst, ebenfalls. Wir klären, was Zillow-Daten so wertvoll macht, wie die Seite technisch tickt, gehen das Python-Tutorial Schritt für Schritt durch, sezieren die genauen Gründe, an denen Scraper scheitern, und richten am Ende automatisierte Scrapes für die Preisüberwachung ein.
Wofür lohnt sich Zillow-Scraping überhaupt?
Zillow ist die zentrale Anlaufstelle für Wohnimmobilien-Daten in den USA. 210 Millionen Besuche pro Monat verzeichnet die Plattform, dazu rund 750.000+ aktive Kaufangebote und 1,9 Millionen Mietobjekte. Über die Hälfte des gesamten US-Traffics auf Immobilienportalen läuft über Zillow – mehr als doppelt so viel wie beim direkten Verfolger.

Eines vorweg, bevor wir uns in Python stürzen: Der Weg über Python ist nur einer von vielen, und die falsche Wahl kostet schnell ganze Stunden. Python mit httpx und BeautifulSoup verlangt mittlere Kenntnisse, dazu das manuelle Jonglieren mit Headern und Proxys; das Tempo ist mäßig (1–3 Sekunden pro Seite), die Wartung dauerhaft – dafür kostet es nichts. Selenium oder Playwright rendern JavaScript und kommen damit besser gegen Bot-Sperren an, sind aber langsamer (5–15 Sekunden pro Seite) und ebenso pflegeintensiv. Scraping-APIs wie ScraperAPI oder ScrapFly bringen den Anti-Bot-Schutz fertig mit, arbeiten zügig und brauchen mittleren Pflegeaufwand, schlagen aber mit 30–599 US-Dollar pro Monat zu Buche. Die offizielle Zillow-API über Bridge Interactive läuft schnell und wartungsarm, ist im Zugriff aber stark begrenzt und kostet rund 500 US-Dollar pro Monat. Und No-Code-Werkzeuge wie Thunderbit sind einsteigerfreundlich, schnell, halten sich dank KI-Anpassung selbst instand und arbeiten meist nach dem Freemium-Prinzip.
Schon die Zeitersparnis macht den Unterschied. Wer 50+ Postleitzahlgebiete von Hand durchsucht, ist gut und gerne 15–20 Stunden pro Woche beschäftigt. Automatisiertes Scraping erledigt dasselbe in wenigen Minuten – das sind 99,7 % weniger Aufwand.
Alle Wege im Vergleich: Python, API oder No-Code
Bevor du mit Python loslegst, lohnt der Blick auf die Alternativen – denn „Zillow mit Python scrapen" ist eben nur eine Möglichkeit von mehreren, und die unpassende kostet unnötig Zeit. Hier der direkte Vergleich zur Orientierung:
| Methode | Kenntnisstand | Anti-Bot-Schutz | Geschwindigkeit | Wartung | Kosten |
|---|---|---|---|---|---|
| Python + httpx/BeautifulSoup | Mittelstufe | Manuell (Header, Proxys) | Mittel (1–3 s/Seite) | Hoch (Selektoren brechen) | Kostenlos |
| Python + Selenium/Playwright | Mittelstufe | Besser (rendert JS) | Langsam (5–15 s/Seite) | Hoch | Kostenlos |
| Scraping-API (ScraperAPI, ScrapFly) | Mittelstufe | Integriert | Schnell | Mittel | 30–599 $/Monat |
| Offizielle Zillow-API (Bridge Interactive) | Anfänger–Mittelstufe | N/A | Schnell | Gering | ca. 500 $/Monat, eingeschränkter Zugriff |
| No-Code-Tool (Thunderbit) | Anfänger | Integriert (KI passt sich an) | Schnell | Keine (KI liest die Seite neu) | Freemium |
Brauchst du die Daten sofort und ohne eine Zeile Code, fang mit Thunderbit an. Willst du verstehen, was unter der Haube passiert, oder brauchst volle Kontrolle, dann bleib dran für die Python-Anleitung.
Der Express-Weg: Zillow in 2 Minuten mit Thunderbit auslesen (ohne Code)
Für alle, die schnell an Zillow-Daten wollen – ohne Python-Setup, ohne Proxy-Gefummel, ohne Selektoren-Pflege – kommt zuerst der direkte Weg. Genau für diesen Fall haben wir den Workflow bei Thunderbit gebaut: strukturierte Immobiliendaten ohne technischen Ballast.
Schwierigkeitsgrad: Anfänger Zeitaufwand: ca. 2 Minuten Benötigt: Chrome-Browser, Thunderbit Chrome-Erweiterung (die kostenlose Stufe reicht)
Schritt 1: Thunderbit installieren und Zillow öffnen
Hol dir die Thunderbit-Erweiterung aus dem Chrome Web Store. Dann öffnest du eine Zillow-Suchergebnisseite – etwa eine Suche nach Häusern in Houston, TX.
Schritt 2: „AI Suggest Fields" anklicken
Öffne die Thunderbit-Seitenleiste und klick auf „AI Suggest Fields". Die KI liest die Seite und schlägt von selbst Spalten vor: Preis, Adresse, Schlafzimmer, Badezimmer, Wohnfläche, Zestimate, Inserats-URL und einiges mehr. In meinen Tests landet sie meist bei über 20 Feldern, ganz ohne Handarbeit.
Schritt 3: „Scrape" anklicken
Ein Klick auf den Scrape-Button genügt. Die Daten erscheinen als strukturierte Tabelle direkt in der Erweiterung. Mit Zillows Seitennavigation kommt Thunderbit von allein zurecht – sowohl beim Klicken durch Seiten als auch beim endlosen Scrollen.
Schritt 4: Mit Unterseiten-Scraping anreichern
Du brauchst auch Daten von den Detailseiten – Steuerhistorie, Schulbewertungen, Preisverlauf? Dann erweiterst du deine Tabelle über „Scrape Subpages". Thunderbit folgt jeder Inserats-URL und holt die zusätzlichen Felder, ohne dass du eine Zeile Code schreibst.
Schritt 5: Exportieren
Raus geht es nach Google Sheets, Excel, Airtable oder Notion. Der Export kostet nichts.
Warum Thunderbit bei Zillow so gut greift
Der eigentliche Pluspunkt ist die Robustheit. Thunderbits KI liest die Seitenstruktur bei jedem Durchlauf frisch ein. Stellt Zillow sein Layout um – und das tut es oft –, musst du keine brüchigen CSS-Selektoren nachziehen; die KI stellt sich von selbst darauf ein. Damit ist das chronische Problem klassischer Code-Scraper, ihre eingebaute Zerbrechlichkeit, tatsächlich vom Tisch.
Welche Daten gibt Zillow her? (20+ Felder)
Die meisten Anleitungen begnügen sich mit Preis und Adresse – dabei steckt in Zillow-Exposés deutlich mehr, als viele vermuten. Zur Übersicht:
| Feld | Wo es zu finden ist | Schwierigkeitsgrad der Extraktion |
|---|---|---|
| Angebotspreis | Suche + Detailseite | Einfach |
| Adresse / PLZ | Suche + Detailseite | Einfach |
| Zestimate | Suche + Detailseite | Einfach |
| Preisverlauf (jedes Ereignis) | Detailseite | Schwer (verschachteltes JSON) |
| Steuerhistorie | Detailseite | Schwer (verschachteltes JSON) |
| Schlafzimmer / Badezimmer / Wohnfläche | Suche + Detailseite | Einfach |
| Baujahr | Detailseite | Einfach |
| HOA-Gebühr | Detailseite | Mittel |
| Walk Score / Transit Score | Detailseite (iFrame) | Schwer (erfordert JS-Rendering) |
| Schulbewertungen | Detailseite | Mittel |
| Grundstücksgröße | Detailseite | Einfach |
| Tage auf Zillow | Suche | Einfach |
| Makler / Brokerage | Suche + Detailseite | Mittel |
| MLS-Nummer | Detailseite | Einfach |
| Immobilientyp | Suche + Detailseite | Einfach |
| Breitengrad / Längengrad | JSON in __NEXT_DATA__ | Mittel |
| Beschreibungstext | Detailseite | Einfach |
| Foto-URLs | Suche + Detailseite | Mittel |
| Miet-Zestimate | Detailseite | Mittel |
| Vergleichbare Verkäufe in der Nähe | Detailseite | Schwer |
Die kniffligen Felder – Preisverlauf, Steuerhistorie, vergleichbare Verkäufe – liegen auf den Detailseiten in verschachteltem JSON. Wie du sie herausholst, zeigt der Python-Teil weiter unten ganz konkret. Wer den Code überspringen will: Thunderbit erkennt mit „AI Suggest Fields" die meisten dieser Spalten von allein, und das Unterseiten-Scraping zieht die Detailseiten-Felder gleich mit.
Die Python-Umgebung fürs Zillow-Scraping aufsetzen
Schwierigkeitsgrad: Mittelstufe Zeitaufwand: ca. 5 Minuten fürs Setup, ca. 30 Minuten fürs komplette Tutorial Benötigt: Python 3.8+, Chrome-Browser (zum Prüfen der Seiten), ein Texteditor oder eine IDE
Installiere die benötigten Bibliotheken:
pip install httpx beautifulsoup4 pandas lxml
Was die einzelnen Pakete erledigen:
- httpx — HTTP-Client mit besserer Performance als
requestsund Unterstützung für asynchrone Aufrufe - beautifulsoup4 + lxml — HTML-Parsing
- pandas — Datenexport nach CSV/Excel
- Optional: selenium oder playwright, wenn du JavaScript-lastige Seiten rendern musst
Zillows Seitenaufbau verstehen, bevor der erste Code fällt

Das ist der wichtigste Punkt überhaupt, noch vor der ersten Codezeile. Zillow ist eine Next.js-Anwendung – das bestätigen sogar Engineering-Posts von Zillow-Mitarbeitern. Konkret heißt das: Die meisten Daten, die du willst, stecken gar nicht im sichtbaren HTML. Sie liegen als JSON-Block im <script id="__NEXT_DATA__">.
Öffne irgendeine Zillow-Immobilienseite, drück F12, geh zu „Elements" und such nach __NEXT_DATA__. Dahinter wartet ein riesiges JSON-Objekt mit allen Inserats-Daten – Preise, Koordinaten, Objektdetails, Preisverlauf, Steuerdaten, Schulbewertungen und mehr.
Warum das so zentral ist? Zillows CSS-Klassennamen sind gehasht (von styled-components erzeugt) und ändern sich bei jedem Deployment. Eine Klasse wie StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0 sieht nächste Woche schon wieder völlig anders aus. Jeder Scraper, der sich auf CSS-Selektoren stützt, geht deshalb regelmäßig zu Bruch.
Der Weg über das __NEXT_DATA__-JSON ist deutlich stabiler, weil er von der HTML-Struktur schlicht unabhängig ist.
Die wichtigen JSON-Pfade für Suchergebnisse:
| Pfad | Inhalt |
|---|---|
props.pageProps.searchPageState.cat1.searchResults.listResults | Array mit Suchergebnissen |
props.pageProps.searchPageState.cat1.searchResults.mapResults | Ergebnisse der Kartenansicht |
props.pageProps.searchPageState.cat1.searchList.totalPages | Gesamtzahl verfügbarer Seiten |
Bei den Detailseiten setzen manche auf __NEXT_DATA__, andere auf einen alternativen Script-Tag namens hdpApolloPreloadedData. Der folgende Code deckt beide Fälle ab.
Schritt für Schritt: Zillow mit Python scrapen
Schritt 1: HTTP-Header setzen, damit du nicht sofort fliegst
Ein nacktes httpx.get() gegen Zillow bringt dir keine Inserate, sondern eine CAPTCHA-Seite. Zillow kombiniert PerimeterX (HUMAN Security) mit Cloudflare – beide gelten in Scraping-Benchmarks mit Schwierigkeitsgrad 8/10 als harte Brocken. Geprüft werden dein TLS-Fingerprint, deine HTTP-Header und der Ruf deiner IP.
Das sind die minimalen Header, die 2025 funktionieren:
import httpx
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,"
"image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Ch-Ua": '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
"Sec-Ch-Ua-Platform": '"Windows"',
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "none",
"Sec-Fetch-User": "?1",
"Upgrade-Insecure-Requests": "1",
}
Entscheidend sind die Sec-Ch-Ua-Header. Viele Anleitungen lassen sie weg – und genau daran scheitert ihr Code gegen PerimeterX.
Schritt 2: Zillow-Suchergebnisse scrapen
Zillows Such-URLs folgen einem festen Muster. Für Houston, TX:
- Seite 1:
https://www.zillow.com/houston-tx/ - Seite 2:
https://www.zillow.com/houston-tx/2_p/ - Seite 3:
https://www.zillow.com/houston-tx/3_p/
Pro Seite kommen etwa 41 Inserate zusammen. Bei 20 Seiten ist Schluss (also rund 820 Inserate); für mehr musst du die Suche geografisch aufteilen – dazu gleich mehr.
Hier der Code, der die Suchergebnisse aus dem __NEXT_DATA__-JSON holt:
from bs4 import BeautifulSoup
import json
import time
import random
def scrape_zillow_search(url):
"""Listing-Daten von einer Zillow-Suchergebnisseite scrapen."""
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code != 200:
print(f"Status {response.status_code} für {url}")
return []
soup = BeautifulSoup(response.text, "lxml")
script_tag = soup.find("script", {"id": "__NEXT_DATA__"})
if not script_tag:
print("Kein __NEXT_DATA__ gefunden — vermutlich durch CAPTCHA blockiert")
return []
next_data = json.loads(script_tag.string)
try:
results = (
next_data["props"]["pageProps"]["searchPageState"]
["cat1"]["searchResults"]["listResults"]
)
except KeyError:
print("Unerwartete JSON-Struktur — Zillow hat das Format möglicherweise geändert")
return []
listings = []
for item in results:
listing = {
"zpid": item.get("zpid"),
"address": item.get("addressStreet"),
"city": item.get("addressCity"),
"state": item.get("addressState"),
"zipcode": item.get("addressZipcode"),
"price": item.get("unformattedPrice") or item.get("price"),
"beds": item.get("beds"),
"baths": item.get("baths"),
"sqft": item.get("area"),
"zestimate": item.get("zestimate"),
"days_on_zillow": item.get("daysOnZillow"),
"listing_url": item.get("detailUrl"),
"img_src": item.get("imgSrc"),
"property_type": item.get("hdpData", {}).get("homeInfo", {}).get("homeType"),
"latitude": item.get("latLong", {}).get("latitude"),
"longitude": item.get("latLong", {}).get("longitude"),
}
listings.append(listing)
return listings
Für mehrere Seiten läufst du mit Pausen durch:
all_listings = []
base_url = "https://www.zillow.com/houston-tx/"
for page in range(1, 6): # Erste 5 Seiten
url = base_url if page == 1 else f"{base_url}{page}_p/"
print(f"Seite {page} wird gescrapt...")
page_listings = scrape_zillow_search(url)
all_listings.extend(page_listings)
# Zufällige Pause zwischen 3 und 7 Sekunden
delay = random.uniform(3, 7)
time.sleep(delay)
print(f"Insgesamt gescrapte Inserate: {len(all_listings)}")
In all_listings solltest du jetzt strukturierte Inserats-Daten finden. Bleibt das Ergebnis leer, hilft der Abschnitt „Warum Scraper brechen" weiter unten.
Schritt 3: Zillow-Detailseiten scrapen
Die Suchergebnisse liefern das Grundgerüst. Die Tiefe steckt auf den Detailseiten: Preisverlauf, Steuerhistorie, Schulbewertungen, Maklerdaten, Objektbeschreibungen. Jede Inserats-URL aus Schritt 2 führt zu so einer Detailseite.
Zillow-Detailseiten kommen in zwei möglichen Datenformaten. Der folgende Code fängt beide ab:
def scrape_zillow_detail(url):
"""Detaillierte Immobiliendaten von einer Zillow-Inseratsseite scrapen."""
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code != 200:
return None
soup = BeautifulSoup(response.text, "lxml")
# Zuerst __NEXT_DATA__ versuchen (am häufigsten)
script_tag = soup.find("script", {"id": "__NEXT_DATA__"})
if script_tag:
next_data = json.loads(script_tag.string)
try:
cache_str = next_data["props"]["pageProps"]["componentProps"]["gdpClientCache"]
cache = json.loads(cache_str)
first_key = next(iter(cache))
prop = cache[first_key]["property"]
return extract_property_fields(prop)
except (KeyError, StopIteration):
pass
# Fallback: hdpApolloPreloadedData
apollo_tag = soup.find("script", {"id": "hdpApolloPreloadedData"})
if apollo_tag:
raw = json.loads(apollo_tag.string)
api_cache = json.loads(raw["apiCache"])
for key, value in api_cache.items():
if "ForSale" in key or "property" in str(value)[:100]:
prop = value.get("property", value)
return extract_property_fields(prop)
return None
def extract_property_fields(prop):
"""Strukturierte Felder aus einem Zillow-Property-JSON-Objekt extrahieren."""
return {
"zpid": prop.get("zpid"),
"zestimate": prop.get("zestimate"),
"rent_zestimate": prop.get("rentZestimate"),
"description": prop.get("description"),
"year_built": prop.get("yearBuilt"),
"lot_size": prop.get("lotSize"),
"hoa_fee": prop.get("monthlyHoaFee"),
"mls_id": prop.get("mlsid"),
"broker_name": prop.get("brokerName") or prop.get("attributionInfo", {}).get("brokerName"),
"price_history": [
{
"date": event.get("date"),
"event": event.get("event"),
"price": event.get("price"),
}
for event in prop.get("priceHistory", [])
],
"tax_history": [
{
"year": record.get("time"),
"tax_paid": record.get("taxPaid"),
"value": record.get("value"),
}
for record in prop.get("taxHistory", [])
],
"schools": [
{
"name": school.get("name"),
"rating": school.get("rating"),
"distance": school.get("distance"),
}
for school in prop.get("schools", [])
],
}
Auch hier läufst du mit Verzögerungen durch deine Inserats-URLs:
detail_data = []
for listing in all_listings[:10]: # Erst 10 zum Testen
detail_url = listing.get("listing_url")
if not detail_url:
continue
if not detail_url.startswith("http"):
detail_url = f"https://www.zillow.com{detail_url}"
print(f"Detailseite wird gescrapt: {detail_url}")
detail = scrape_zillow_detail(detail_url)
if detail:
detail_data.append({**listing, **detail})
time.sleep(random.uniform(3, 8))
Danach hast du eine Liste von Dictionaries vor dir, die für jede Immobilie sowohl Such- als auch Detaildaten bündelt.
Schritt 4: Pagination über mehrere Seiten hinweg
Bei Gebieten mit mehr als 820 Inseraten (dem 20-Seiten-Limit) führt kein Weg an einer geografischen Aufteilung vorbei. Zillows interne API nimmt mapBounds-Parameter entgegen. Die Idee: Du zerlegst die Karte in Quadranten und scrapest jeden Ausschnitt einzeln.
def split_bounds(bounds):
"""Kartengrenzen in 4 Quadranten aufteilen."""
mid_lat = (bounds["north"] + bounds["south"]) / 2
mid_lng = (bounds["east"] + bounds["west"]) / 2
return [
{"north": bounds["north"], "south": mid_lat, "east": bounds["east"], "west": mid_lng},
{"north": bounds["north"], "south": mid_lat, "east": mid_lng, "west": bounds["west"]},
{"north": mid_lat, "south": bounds["south"], "east": bounds["east"], "west": mid_lng},
{"north": mid_lat, "south": bounds["south"], "east": mid_lng, "west": bounds["west"]},
]
Für die meisten Vorhaben – etwa die Beobachtung von 50–200 Inseraten in einem bestimmten Gebiet – genügt die normale URL-Pagination völlig. Der Quadranten-Trick zielt eher auf stadt- oder landesweite Scrapes.
Schritt 5: Die gescrapten Zillow-Daten exportieren
Mit pandas schreibst du alles als CSV weg:
import pandas as pd
df = pd.DataFrame(detail_data)
df.to_csv("zillow_houston_listings.csv", index=False)
print(f"{len(df)} Inserate nach zillow_houston_listings.csv exportiert")
Für den JSON-Export:
with open("zillow_houston_listings.json", "w") as f:
json.dump(detail_data, f, indent=2)
Wer sich den Export ganz sparen möchte: Thunderbit schreibt kostenlos nach Google Sheets, Airtable und Notion – praktisch, wenn die Daten gleich in einem kollaborativen Format gebraucht werden.
Warum Zillow-Scraper kaputtgehen — und wie du robuste baust
Dies ist der Überlebensteil.
Aus meiner Erfahrung gehen Scraper bei Zillow aus drei klar benennbaren Gründen kaputt – und für jeden gibt es eine ebenso klare Antwort.
PerimeterX und CAPTCHAs: Warum deine Requests leer zurückkommen
Zillows PerimeterX-Integration wertet mehrere Signale gleichzeitig aus: TLS-Fingerprint, HTTP-Header, IP-Reputation, Request-Muster. Wittert das System Automatik, schickt es dir eine „Press & Hold"-CAPTCHA-Seite statt der Inserate.
So sieht der Fehler genau aus: Du schickst eine Anfrage mit Standard-Python-Headern. Im Antwort-HTML stecken PerimeterX-Challenge-Skripte statt Immobiliendaten – und dein BeautifulSoup-Parse findet kein __NEXT_DATA__-Tag.
Die Antwort darauf: Nimm die vollständigen, browserähnlichen Header aus Schritt 1. Bei mehr als ein paar Dutzend Anfragen kommt zusätzlich Proxy-Rotation dazu (siehe unten). Für umfangreiches Scraping bietet sich curl_cffi mit impersonate="chrome" an – der einzige Python-HTTP-Client, der einen echten Chrome-TLS-Fingerprint einigermaßen überzeugend nachbildet.
Dynamische CSS-Selektoren: Warum BeautifulSoup None liefert
Setzt du auf CSS-Selektoren wie .list-card-price oder auf gehashte Klassennamen, geht dein Scraper jedes Mal zu Bruch, sobald Zillow neuen Code ausrollt.
Zillow nutzt styled-components, die Klassennamen wie StyledPropertyCardHomeDetailsList-c11n-8-109-3__sc-1j0som5-0 erzeugen. Der Hash-Teil wechselt mit jedem Build.
Die Antwort darauf: Verzichte komplett auf CSS-Selektoren. Hol die Daten aus dem __NEXT_DATA__-JSON, wie im Code oben gezeigt. Dieser Weg hält schon seit Jahren, weil sich die JSON-Struktur viel seltener verändert als das HTML-Markup.
Brauchst du HTML-Parsing partout, halt dich an data-test-Attribute (z. B. data-test="property-card") oder arbeite mit Teilstring-Treffern bei Klassen wie [class*="PropertyCard"]. Verlässlicher bleibt aber die JSON-Extraktion.
Proxy-Rotation und exponentielles Backoff: Code, der IP-Sperren übersteht
Rechenzentrums-IPs landen bei Zillow umgehend auf der Blockliste. Für verlässlichen Zugriff brauchst du Residential Proxies. Sicher fährst du mit 1 Request alle 3–8 Sekunden pro IP, also unter etwa 500 Requests pro Stunde.
Hier ein Retry-Dekorator mit exponentiellem Backoff und Jitter:
import random
import time
def backoff_with_jitter(attempt, base_delay=2, max_delay=60):
"""AWS-ähnliches exponentielles Backoff mit vollem Jitter."""
delay = min(max_delay, base_delay * (2 ** attempt))
return random.uniform(0, delay)
def fetch_with_retry(url, max_retries=5):
for attempt in range(max_retries):
try:
response = httpx.get(url, headers=headers, timeout=15)
if response.status_code == 200:
return response
if response.status_code in (403, 429):
delay = backoff_with_jitter(attempt, base_delay=5)
print(f"Blockiert ({response.status_code}). Neuer Versuch in {delay:.1f}s...")
time.sleep(delay)
continue
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(backoff_with_jitter(attempt))
return None
Und ein schlichter Proxy-Rotation-Pool:
class ProxyPool:
def __init__(self, proxies):
self.proxies = proxies
self.index = 0
self.failures = {}
def get_next(self):
proxy = self.proxies[self.index % len(self.proxies)]
self.index += 1
return {"http://": proxy, "https://": proxy}
def report_failure(self, proxy):
self.failures[proxy] = self.failures.get(proxy, 0) + 1
if self.failures[proxy] > 3:
self.proxies.remove(proxy)
# Nutzung:
pool = ProxyPool(proxies=[
"http://user:pass@residential1.example.com:8080",
"http://user:pass@residential2.example.com:8080",
])
Was die Anbieter angeht: DataImpulse liefert Residential Proxies ab rund 1 $/GB und ist damit die günstigste Wahl, während IPRoyal und Smartproxy mit 4–7 $/GB solide im Mittelfeld liegen.
Die wartungsfreie Alternative
Wenn du Zillow regelmäßig scrapest und keine Lust mehr auf kaputte Selektoren oder Proxy-Pools hast: Thunderbits KI liest die Seitenstruktur bei jedem Durchlauf frisch ein. Keine Selektoren, die gepflegt werden wollen, keine Proxy-Konfiguration. Damit ist das Zerbrechlichkeitsproblem, das klassische Scraper zum Dauerärgernis macht, wirklich gelöst.
Zillow-Scraping automatisieren: Zeitplan und Preisüberwachung
Genau danach fragt jeder Immobilieninvestor, mit dem ich gesprochen habe – und kein anderer Zillow-Guide behandelt es: wiederkehrende, automatisierte Scrapes fürs Preis-Tracking.
Für Python-Nutzer: Cron-Jobs und Erkennung von Preisänderungen
Richte einen Cron-Job ein, der deinen Scraper wöchentlich startet und Preisänderungen markiert:
import pandas as pd
from datetime import datetime
def detect_price_changes(new_data, historical_file, threshold=0.05):
"""Neuen Scrape mit historischen Daten vergleichen und Änderungen > Schwellenwert markieren."""
try:
old = pd.read_csv(historical_file)
except FileNotFoundError:
new_data.to_csv(historical_file, index=False)
print("Erster Lauf — Basisdaten gespeichert.")
return pd.DataFrame()
merged = new_data.merge(old, on="zpid", suffixes=("_new", "_old"))
merged["price_change_pct"] = (
(merged["price_new"] - merged["price_old"]) / merged["price_old"]
)
alerts = merged[merged["price_change_pct"].abs() > threshold]
# Neue Daten mit Zeitstempel anhängen
new_data["scraped_at"] = datetime.now().isoformat()
new_data.to_csv(historical_file, mode="a", header=False, index=False)
return alerts
Trag es so in deine Crontab ein, dass es jeden Montag um 6 Uhr läuft:
0 6 * * 1 cd /path/to/scraper && python zillow_monitor.py
Ein Beispiel aus der Praxis: Du beobachtest wöchentlich 50 Listings in Austin, TX. Jeden Montag scrapt das Skript die aktuellen Preise, gleicht sie mit der Vorwoche ab und legt eine CSV mit allen Preisrückgängen über 5 % an.
Für Nicht-Programmierer: Thunderbit Scheduled Scraper
Mit Thunderbits „Scheduled Scraper" gibst du das Intervall einfach in natürlicher Sprache an („jeden Montag um 9 Uhr"), fügst deine Zillow-Such-URLs ein und klickst auf „Schedule". Bei jedem Lauf wandern die Daten automatisch nach Google Sheets. Kein Python, kein Cron, kein Server, um den du dich kümmern müsstest. Besonders praktisch für Makler oder Operations-Teams, die verlässliches Preis-Monitoring ohne technische Hilfe brauchen.
Tipps für verantwortungsvolles Zillow-Scraping
Ein paar Hinweise, damit du auf der sicheren Seite bleibst:
- Scrape nur öffentlich zugängliche Daten. Lass Seiten hinter Login- oder Authentifizierungswänden außen vor.
- Halte vernünftige Request-Raten ein. 3–8 Sekunden zwischen den Anfragen. Den Server nicht mit Requests überrollen.
- Scrape keine persönlichen oder privaten Nutzerdaten. Makler- und Brokerage-Angaben in Inseraten sind öffentlich; Kontodaten von Nutzern sind es nicht.
- Speichere und nutze Daten ethisch. Marktanalysen, Investment-Research und Lead-Generierung sind legitime Zwecke. Kein Spam.
- Rechtlicher Rahmen: Das Urteil hiQ gegen LinkedIn hat klargestellt, dass das Scrapen öffentlich zugänglicher Daten nicht gegen den CFAA verstößt. Das Urteil Meta v. Bright Data (2024) bestätigte ähnliche Grundsätze. Trotzdem schränken Zillows Nutzungsbedingungen den automatisierten Zugriff ein, und durchgesetzt wird das über IP-Bans und CAPTCHAs, kaum über Klagen. Prüfe immer die aktuelle Rechtslage und beachte die robots.txt.
Die passende Methode zum Zillow-Scraping mit Python finden
Welcher Weg der beste ist, hängt von deiner Lage ab:
Du brauchst schnell Daten, ganz ohne Code? Thunderbit bringt dich von einer Zillow-Suchergebnisseite in rund 2 Minuten zur strukturierten Tabelle. Die KI stellt sich auf Layout-Änderungen ein, übernimmt die Pagination und exportiert kostenlos. Installier die Chrome-Erweiterung und probier sie auf einer Zillow-Suchergebnisseite aus.
Du willst die volle Kontrolle? Dann nimm den Python-Code aus diesem Leitfaden. Hol die Daten aus dem __NEXT_DATA__-JSON (nicht über CSS-Selektoren), das sorgt für Stabilität. Setz passende browserähnliche Header. Und für mehr Verlässlichkeit Residential Proxies plus exponentielles Backoff.
Du skalierst nach oben? Scraping-APIs wie ScrapFly (99 % Erfolgsrate bei Zillow) oder ScraperAPI nehmen dir die Proxy- und CAPTCHA-Infrastruktur ab, je nach Volumen für 30–599 $/Monat.
Du willst Preise über die Zeit verfolgen? Dann richte einen Cron-Job mit dem Skript zur Preisänderungs-Erkennung ein oder greif für den wartungsfreien Weg zu Thunderbits Scheduled Scraper.
Die Daten liegen bereit. Die einzige Frage ist, wie viel Entwicklungszeit du hineinstecken willst, um sie herauszuholen. Wie du Webdaten ganz allgemein in Tabellen überführst, zeigt unser Leitfaden zum Scrapen von Daten von Websites nach Excel; aktuelle Plattformzahlen findest du in unserem Zillow-Statistiken-Überblick. Und Tutorials gibt es auf dem Thunderbit YouTube-Kanal.
Thunderbit für Zillow-Scraping testen Get Started Free
FAQs
Kann man Zillow mit Python kostenlos scrapen?
Ja – httpx, BeautifulSoup und pandas sind allesamt kostenlos und Open Source. Der Preis dafür ist deine Zeit: Header, Proxy-Rotation und die Pflege der Selektoren liegen bei dir. Rechne mit 4–8 Stunden für die Ersteinrichtung und 4–10 Stunden pro Monat für die Wartung, sobald Zillow seine Seite umbaut. Wer sich den Programmieraufwand komplett sparen will, findet auch bei Thunderbit einen kostenlosen Tarif.
Hat Zillow eine offizielle API?
Zillow hat seine kostenlose öffentliche API im September 2021 abgeschaltet. Der Zugriff läuft heute über Bridge Interactive, setzt eine Freigabe voraus, kostet rund 500 US-Dollar pro Monat und richtet sich an lizenzierte Immobilienprofis. Für die meisten – Investoren, Forschende, Makler mit Marktanalyse-Bedarf – ist Scraping die praktikable Alternative. Allerdings stellt Zillow weiterhin kostenlose Forschungsdaten als CSV-Downloads unter zillow.com/research/data/ bereit, darunter den Zillow Home Value Index und den Zillow Observed Rent Index.
Wie umgehe ich Blockaden beim Zillow-Scraping?
Drei Dinge: (1) Nimm realistische Browser-Header samt Sec-Ch-Ua – das ist der Header, den die meisten Anleitungen vergessen, und genau darauf schaut PerimeterX zuerst; (2) rotiere Residential Proxies – Rechenzentrums-IPs fliegen sofort raus; (3) hol die Daten aus dem __NEXT_DATA__-JSON statt über HTML-Selektoren, dann hauen dir Layout-Änderungen keine Fehler rein. Halte die Request-Rate bei 1 Anfrage pro 3–8 Sekunden und IP. Oder nutz ein Tool wie Thunderbit, das den Anti-Bot-Schutz von allein übernimmt.
Wie scrapt man Zillow am besten ohne Programmieren?
Am schnellsten geht es mit Thunderbits AI Web Scraper. Installier die Chrome-Erweiterung, öffne eine Zillow-Suchergebnisseite, klick auf „AI Suggest Fields", um die Spalten automatisch zu erkennen, und danach auf „Scrape". Anschließend exportierst du ohne Code nach Google Sheets, Excel, Airtable oder Notion. Die KI liest die Seite jedes Mal neu ein und bricht deshalb nicht, wenn Zillow das Layout umstellt.
Wie oft ändert Zillow seine Website-Struktur, und was heißt das für Scraper?
Zillow spielt häufig Updates aus – mitunter wöchentlich. Weil dort styled-components zum Einsatz kommen, wechseln die CSS-Klassennamen mit jedem Deployment, und Scraper auf Basis von CSS-Selektoren gehen regelmäßig zu Bruch. Der robusteste Weg in Python ist die Extraktion aus dem __NEXT_DATA__-JSON-Block, dessen Struktur sich viel seltener verändert. Wer es wartungsfrei mag: Thunderbits KI liest die Seitenstruktur bei jedem Durchlauf neu ein und passt sich automatisch an Layout-Änderungen an.
Mehr erfahren
- Wie man Web Scraping in Python ohne Blockierung durchführt
- Python Web Scraping: Blocks mit smarter Proxy-Nutzung vermeiden
- So scrapen Sie Daten von einer Website effizient mit Python
- Wie man mit Python einen Web Scraper schreibt: Von Anfang bis Ende
- Umfassender Leitfaden für Web Scraping in Python: Schritt für Schritt


