Zum Inhalt springen
Zurück zum Blog

Immobilien-Web-Scraping: So sammeln Sie Immobiliendaten mit Python

Robert MunceanuZuletzt aktualisiert am 20 min read
Immobilien-Web-Scraping: So sammeln Sie Immobiliendaten mit Python
Kurz gesagt: Beim Immobilien-Web-Scraping werden Inserate, Preise und Objektdaten von Websites gesammelt und in strukturierte Daten überführt. Prüfen Sie vor dem Scraping, ob es Open Data, einen MLS-Feed oder eine Daten-API gibt, denn Zillow, Realtor.com und Redfin verbieten die automatisierte Erfassung in ihren Nutzungsbedingungen. Dieser Leitfaden behandelt Datenmodell, Quellen, rechtliche Grenzen, Python-Code und Qualitätsprüfungen.

Früher oder später bittet Sie jemand, „Immobiliendaten zu besorgen“: Angebotspreise für Vergleichsobjekte, den Bestand für einen Bericht oder einen Feed mit neuen Inseraten. Immobiliendaten finden sich überall im Web, daher wirkt Scraping wie die naheliegende Lösung. Zwei Fehler bringen jedoch die meisten dieser Projekte zu Fall. Der erste: ein Portal zu scrapen, dessen Nutzungsbedingungen das verbieten. Der zweite: einen Angebotspreis als Verkaufspreis zu behandeln und die Analyse auf der falschen Zahl aufzubauen.

Beginnen Sie mit der Entscheidung: Welche Daten gibt es, welche Quelle passt zu welcher Aufgabe und was erlauben die großen Portale? Danach bauen Sie einen Python-Scraper mit requests, BeautifulSoup und pandas auf einer Beispielseite, die Sie selbst kontrollieren, und rufen echte Hauspreise aus einer kostenlosen Open-Data-Datei ab.

Was ist Immobilien-Web-Scraping?

Immobilien-Web-Scraping ist die automatisierte Erfassung von Objektinformationen auf Websites, etwa Angebotspreise, Adressen, Schlafzimmer, Wohnfläche, Fotos und Vermarktungsdauer. Ein Scraper ruft Seiten ab, extrahiert die Felder und speichert sie als Zeilen in einer CSV-Datei oder Datenbank, damit Sie Märkte vergleichen oder Veränderungen im Zeitverlauf verfolgen können.

Scraping ist nur ein Weg zu diesen Informationen. Dieselben Zahlen gibt es oft als kostenlose Downloads, lizenzierte MLS-Feeds oder Daten-APIs, und diese Wege sind meist günstiger im Unterhalt und sicherer in der Nutzung. Vergleichen Sie die Optionen, bevor Sie eine einzige Zeile Code schreiben.

Welche Immobiliendaten lassen sich scrapen?

Die meisten Inseratsseiten zeigen Adresse, Angebotspreis oder Miete, Schlaf- und Badezimmer, Wohnfläche, Grundstücksgröße, Objektart, Status, Einstelldatum, Fotos und den zuständigen Makler. Diese Felder beschreiben drei verschiedene Dinge: die Immobilie, das Inserat, das sie bewirbt, und jeden Preis, den Sie an einem bestimmten Datum beobachtet haben.

Ein Haus kann innerhalb von fünf Jahren dreimal auf den Markt kommen, über zwei Makler und zu fünf verschiedenen Preisen. Wenn Sie all das in einer einzigen Zeile speichern, verlieren Sie die Historie, die die Daten erst wertvoll macht. Modellieren Sie die Daten stattdessen in drei Ebenen:

Ebene

Was sie ist

Beispielfelder

Schlüssel für die Deduplizierung

Immobilie

Das physische Objekt, das sich selten ändert

Adresse, Flurstücksnummer, Schlafzimmer, Badezimmer, Wohnfläche, Grundstücksgröße, Baujahr

Normalisierte Adresse oder Flurstücks-ID

Inseratsphase

Ein Zeitraum, in dem das Objekt auf dem Markt war

Quellseite, Inserats-ID, Status, Einstelldatum, Makler, URL

Quelle + Inserats-ID

Beobachtung

Was Sie zu einem bestimmten Zeitpunkt gesehen haben

Preis, Status, Vermarktungsdauer, collected_at

Inserats-ID + Zeitstempel

Preise erfordern dieselbe Sorgfalt. Eine Inseratsseite kann mehrere Zahlen zeigen, die ähnlich aussehen, aber Unterschiedliches bedeuten:

Preisart

Bedeutung

Ist es eine Transaktion?

Angebotspreis

Was der Verkäufer heute verlangt; er kann sinken oder steigen

Nein

Verkaufspreis

Was der Käufer beim Abschluss bezahlt hat

Ja

Angebotsmiete

Was ein Vermieter pro Zeitraum (Monat oder Woche) verlangt

Nein, und sie braucht einen Zeitraum

Automatische Schätzung

Die Wertschätzung eines Modells, etwa ein Zestimate

Nein

Steuerlicher Einheitswert

Der Wert, den eine Behörde für die Grundsteuer ansetzt

Nein

Speichern Sie jede Preisart in einer eigenen Spalte oder versehen Sie jeden Preis mit seiner Art. Unsere Immobilien-Inseratsdaten folgen derselben Idee: eine Immobilie, die Inserate, die sie bewerben, und datierte Preisbeobachtungen. Denn ein Inserat sagt Ihnen, was jemand verlangt hat, nicht, was jemand bezahlt hat.

Noch eine Regel, bevor Sie irgendetwas erfassen: Namen, Telefonnummern und E-Mail-Adressen von Maklern sind nach den meisten Datenschutzgesetzen personenbezogene Daten. Lassen Sie sie weg, sofern Sie keinen rechtmäßigen Grund haben, sie zu speichern.

Wer nutzt Immobilien-Scraping und wofür?

Makler und Maklerbüros nutzen es für Vergleichsverkäufe und Preisfindung. Investoren suchen damit unterbewertete Objekte und verfolgen Mietrenditen. Proptech-Teams bauen Inserats-Feeds und Bewertungsmodelle. Forscher und Journalisten beobachten Angebotsbestand und Preissenkungen. Käufer und Mieter behalten ein Viertel im Blick.

Entscheidend ist, jede Aufgabe den Feldern zuzuordnen, die sie braucht, und der Quelle, die diese mit dem geringsten Risiko liefert:

Anwendungsfall

Benötigte Felder

Beste erste Quelle

Vergleichsobjekte und Preisfindung

Verkaufspreis, Schlafzimmer, Badezimmer, Fläche, Verkaufsdatum

MLS-Feed über einen Makler oder lizenzierte Daten

Marktbeobachtung

Bestand, Median-Angebotspreis, Vermarktungsdauer nach Metropolregion oder Postleitzahl

Open-Data-Downloads

Investment-Screening

Angebotspreis, Miete, Steuern, Preishistorie

Daten-API oder lizenzierte Daten, ergänzt um offene Mietindizes

Inserats-Aggregation

Vollständige Inseratsdatensätze mit Fotos

MLS-IDX oder ein lizenzierter Feed; Scraping ist hier der riskanteste Weg

Lead-Generierung

Kontakte von Eigentümern oder Maklern

Mit Vorsicht: Datenschutz- und Anti-Spam-Regeln gelten

Private Immobiliensuche

Benachrichtigungen zu einer Handvoll Inseraten

Die Suchaufträge des Portals selbst

Wenn Ihre Aufgabe in eine der ersten drei Zeilen fällt, brauchen Sie möglicherweise gar keinen Scraper.

Sollten Sie Immobiliendaten scrapen, herunterladen oder lizenzieren?

Laden Sie zuerst herunter, wenn Sie Zahlen auf Marktebene brauchen, denn Zillow, Redfin und Realtor.com veröffentlichen kostenlose Wohnungsmarktdaten. Lizenzieren Sie einen MLS-Feed oder eine Daten-API, wenn Sie Inseratsdatensätze in großem Umfang benötigen. Scrapen Sie nur Seiten, deren Nutzungsbedingungen das erlauben, oder Ihre eigenen Websites, die Ihrer Partner und öffentliche Quellen, die automatisierten Zugriff gestatten.

Weg

Liefert

Kosten und Aufwand

Zugangshürde

Am besten für

Achten Sie auf

Open-Data-Downloads (Zillow Research, Redfin Data Center, Realtor.com-Datenbibliothek, FHFA HPI)

Aggregate nach Metropolregion, County und Postleitzahl

Kostenlos; ein paar Zeilen pandas

Keine

Trends, Berichte, Markt-Screening

Monatlicher Rhythmus; keine Zeilen auf Inseratsebene

MLS über RESO Web API

Maßgebliche Inseratsdatensätze, einschließlich Verkaufsdaten

Lizenzgebühren und Verträge

Hoch: Mitgliedschaft, Makler oder zugelassener Anbieter

Maklerbüros, IDX-Websites, Bewertung

Anzeige- und Nutzungsregeln

Immobilien-Daten-API oder Datensatz

Strukturierte Inseratsdatensätze, ohne selbst Scraper zu betreiben

Auf Anfrage

Gering bis mittel

Produkte, die Inserate ohne eigenes Parser-Team brauchen

Anbieterbedingungen, Abdeckung und Aktualität

Scraper API

Gerendertes HTML von Seiten, die Sie erfassen dürfen; den Parser schreiben Sie selbst

Bezahlung pro Anfrage

Gering

Makler-Websites, Partner-Feeds, erlaubte öffentliche Quellen

Parser und Compliance-Prüfung bleiben Ihre Aufgabe

Eigener Scraper (requests, BeautifulSoup, Playwright)

Was immer Sie bauen

Ihre Zeit, Server und Proxys

Gering beim Start, hoch im Unterhalt

Kleine, erlaubte Aufgaben und Prototypen

Ausfälle, Sperren und Compliance

Die meisten Teams kombinieren am Ende mehrere Wege: Open Data für das Marktbild, einen Feed oder eine API für Inseratsdatensätze und einen Scraper für den Long Tail erlaubter Websites.

Ihre Nutzungsbedingungen verbieten es. Zillow untersagt „automated queries“, einschließlich Scraping und dem Umgehen von Captchas. Realtor.com verbietet Screen- und Database-Scraping. Redfin verbietet automatisiertes Crawling ohne schriftliche Genehmigung. Verstöße gegen die Nutzungsbedingungen können zu Kontosperren, blockierten IP-Adressen oder vertraglichen Ansprüchen führen, selbst dort, wo das Scraping öffentlicher Seiten keine Straftat ist. Nutzen Sie stattdessen ihre Daten-Downloads oder eine lizenzierte Quelle.

Das sagen die Nutzungsbedingungen der großen Portale im Wortlaut (Zitate im englischen Original):

Portal

Was die Bedingungen sagen

robots.txt

Offizielle Alternative

Zillow

Die Nutzungsbedingungen von Zillow (aktualisiert am 28. Oktober 2025) untersagen „automated queries (including screen and database scraping, spiders, robots, crawlers, bypassing 'captcha' or similar precautions…)“. Kopieren ist nur „without the aid of any automated processes“ erlaubt. Aggregierte Local-Info-Daten dürfen mit dem Hinweis „Data Provided by Zillow Group“ weiterverwendet werden.

Lange Datei mit Regeln auf Pfadebene

Zillow-Research-Downloads; Zillow-Group-APIs zu deren eigenen Bedingungen

Realtor.com

Die Nutzungsbedingungen von Realtor.com verbieten „screen scraping“ und „database scraping“ sowie die Erfassung „by automated means“ wie per „robot, spider, script“. Zudem heißt es, dass Einstellungen in der robots.txt Ihre Rechte nicht erweitern.

Vorhanden, hat aber keinen Vorrang vor den Bedingungen

Realtor.com-Datenbibliothek für Wohnimmobilien (CSV)

Redfin

Die Nutzungsbedingungen von Redfin enthalten „No Scrubbing or Scraping“: kein automatisiertes Crawling oder Abfragen, „unless you have received prior express written permission“. MLS-Hinweise auf den Inseratsseiten wiederholen das Verbot.

Vorhanden, mit Regeln auf Pfadebene

Downloads aus dem Redfin Data Center

Rightmove (UK)

Im Footer der Nutzungsbedingungen von Rightmove heißt es: „Rightmove prohibits the scraping of its content.“

Das Verbot gilt unabhängig von der robots.txt

Rightmove um schriftliche Genehmigung bitten

Andere Portale (Zoopla, Idealista, realestate.com.au, Domain, Homes.com)

Lesen Sie die Nutzungsbedingungen jeder Website, bevor Sie etwas erfassen

Je Website prüfen

Je Website prüfen

In den USA entschied der Ninth Circuit im Fall hiQ Labs v. LinkedIn (2022), dass das Scraping öffentlich zugänglicher Seiten wahrscheinlich kein „Zugriff ohne Befugnis“ im Sinne des Computer Fraud and Abuse Act ist. Dieses Urteil hebt die übrigen Regeln nicht auf. Nutzungsbedingungen sind Verträge, Inseratsfotos und -beschreibungen sind urheberrechtlich geschützt, und Datenschutzgesetze schützen die Personen in den Daten. Laut den eigenen Bedingungen beansprucht Zillow kein Urheberrecht an Inseratsbildern und -beschreibungen. Das Urheberrecht liegt bei den Eigentümern. Außerhalb der USA setzen das EU-Datenbankrecht und die DSGVO eigene Grenzen.

Dies ist keine Rechtsberatung. Holen Sie anwaltlichen Rat ein, bevor Sie Daten von einer Website erfassen, deren Bedingungen das verbieten. Einen breiteren Überblick bieten die rechtlichen Grundlagen des Web-Scrapings.

Darf man MLS-Daten scrapen?

Nein, nicht auf legitime Weise. MLS-Daten sind an Mitglieder lizenziert, und die IDX-Regeln erlauben Maklern, Inserate Verbrauchern anzuzeigen, nicht aber Dritten, sie zu kopieren. Der legitime Weg ist ein RESO-Web-API-Feed, den Sie über eine MLS-Mitgliedschaft, einen Partnermakler oder einen zugelassenen Datenanbieter erhalten. Für MLS-basierte Seiten der Portale gelten dieselben Einschränkungen.

Die RESO Web API ist ein Standard, keine Datenquelle. RESO veröffentlicht ein gemeinsames Data Dictionary, sodass Felder wie ListPrice, StandardStatus und BedroomsTotal in jedem konformen MLS dasselbe bedeuten. Die Web API liefert diese Felder per REST nach den OData-Konventionen. Trotzdem muss Ihnen jemand den Zugang gewähren. Die üblichen Wege sind:

  • Verantwortlicher Makler (Broker of Record). Ein lizenziertes Maklerbüro, für das Sie arbeiten oder mit dem Sie kooperieren, beantragt den Feed bei seinem MLS.
  • Vom MLS zugelassener Anbieter. Viele MLS lizenzieren Daten im Rahmen eines Anbietervertrags an Technologieanbieter.
  • Multi-MLS-Aggregatoren. Unternehmen, die Vereinbarungen mit vielen MLS haben und einen normalisierten Zugang weiterverkaufen.

Zwei weitere Abkürzungen tauchen oft auf. IDX (Internet Data Exchange) erlaubt teilnehmenden Maklern, die Inserate der anderen auf ihren eigenen Websites zu zeigen. Eine VOW (Virtual Office Website) zeigt registrierten Kunden eines Maklers mehr Details. Beides sind Anzeigeprogramme mit Regeln, die das MLS festlegt. Keines erlaubt Dritten, die Inserate in eine eigene Datenbank zu kopieren.

Sobald Sie Zugangsdaten haben, sieht eine Anfrage ungefähr so aus. Sie zeigt nur die Struktur. Ihr MLS nennt Ihnen den Endpunkt und die Felder, die Sie laut Lizenz lesen dürfen.

import os

import requests

# Shape only: your MLS or data vendor supplies the endpoint, token, and fields.
BASE_URL = os.environ["RESO_BASE_URL"]
TOKEN = os.environ["RESO_ACCESS_TOKEN"]

response = requests.get(
    f"{BASE_URL}/Property",
    headers={"Authorization": f"Bearer {TOKEN}"},
    params={
        "$select": "ListingKey,ListPrice,StandardStatus,BedroomsTotal,City",
        "$filter": "StandardStatus eq 'Active' and City eq 'Springfield'",
        "$top": 100,
    },
    timeout=30,
)
listings = response.json()["value"]

Die Parameter $select, $filter und $top stammen aus OData. Dasselbe Muster funktioniert daher auf allen RESO-zertifizierten Servern, mit kleinen Unterschieden in der Filtersyntax.

Wie funktionieren Immobilien-Scraper?

Ein Immobilien-Scraper arbeitet in fünf Schritten. Er ermittelt Inserats-URLs aus Such- oder Sitemap-Seiten, ruft jede Seite ab und rendert bei Bedarf JavaScript. Dann extrahiert er Felder aus strukturierten Daten oder HTML. Anschließend normalisiert er Preise, Flächen und Adressen. Zum Schluss speichert er jede Beobachtung mit Zeitstempel, damit spätere Läufe Preis- und Statusänderungen erkennen.

Inserats-URLs ermitteln

Inserats-URLs stammen aus Sitemaps, Suchergebnisseiten und Paginierungslinks. Suchseiten brechen oft nach einer festen Zahl von Ergebnissen ab. Teilen Sie große Gebiete daher in kleinere auf, nach Postleitzahl oder Preisspanne. Crawlen Sie nicht jede Filterkombination. Sortierungen und Filter vervielfachen sich zu Millionen von URLs, die größtenteils dieselben Inserate wiederholen. Wenn eine Website, die Sie erfassen dürfen, eine Sitemap veröffentlicht, beginnen Sie dort: Sie listet die kanonischen Inserats-URLs auf, und die lastmod-Daten zeigen, welche Seiten sich seit Ihrem letzten Lauf geändert haben.

Seiten abrufen

Manche Websites liefern vollständiges HTML. Andere bauen die Seite im Browser per JavaScript auf. Rufen Sie nach Möglichkeit die statische Version ab, denn das ist schneller und günstiger. Cachen Sie Antworten, halten Sie die Anfragerate niedrig und beachten Sie die robots.txt, wie im Robots Exclusion Protocol beschrieben. Denken Sie daran: Die robots.txt erteilt nie eine Erlaubnis, die die Nutzungsbedingungen verweigern.

Felder extrahieren

Prüfen Sie die Quellen in dieser Reihenfolge. Erstens JSON-LD-Blöcke mit schema.org-Typen wie RealEstateListing oder SingleFamilyResidence. Zweitens JSON, das das Frontend-Framework der Website in Script-Tags einbettet. Lesen Sie dazu, wie Sie in eine Seite eingebettetes JSON parsen. Drittens HTML-Selektoren. Strukturierte Daten ändern sich seltener als das Markup, und Ihr Scraper bricht weniger oft.

Normalisieren und deduplizieren

Machen Sie aus „$1,250,000“ den Wert 1250000 plus Währung. Rechnen Sie alle Flächen in eine Einheit um. Machen Sie den Mietzeitraum explizit. Normalisieren Sie Adressen, damit dasselbe Objekt quellenübergreifend zugeordnet wird, und deduplizieren Sie anhand dieser normalisierten Adresse oder einer Flurstücks-ID.

Beobachtungen speichern und Änderungen erkennen

Hängen Sie bei jedem Lauf eine neue Zeile an, statt die alte zu überschreiben. Speichern Sie collected_at, die Quell-URL und den Rohwert neben dem geparsten Wert. Der Vergleich der heutigen Zeilen mit denen der Vorwoche zeigt Preissenkungen, Statusänderungen und neue Inserate. In pandas ist das ein Merge auf die Inserats-ID zwischen zwei Läufen. Zeilen, die nur im neuen Lauf vorkommen, sind neue Inserate. Zeilen, die nur im alten Lauf vorkommen, sind vom Markt verschwunden. Zeilen in beiden Läufen mit unterschiedlichem Preis zeigen Preisänderungen.

Wie scrapen Sie Immobiliendaten mit Python?

Installieren Sie requests, BeautifulSoup und pandas. Rufen Sie eine Inseratsseite ab, die Sie erfassen dürfen, lesen Sie zuerst ihr JSON-LD und greifen Sie für fehlende Felder auf HTML-Selektoren zurück. Wandeln Sie Preise und Flächen in Zahlen um, entfernen Sie doppelte Inserate und exportieren Sie als CSV. Nutzen Sie eine Scraper-API, wenn Seiten JavaScript-Rendering oder standortspezifische Ergebnisse erfordern.

Das Tutorial verwendet eine kleine Beispielseite mit fiktiven Inseraten, sodass Sie jeden Schritt ausführen können, ohne fremde Server zu belasten. Derselbe Code funktioniert auf der Website Ihres eigenen Maklerbüros oder auf den Seiten eines Partners, sobald Sie die Selektoren anpassen.

Projekt einrichten

Sie benötigen Python 3.12 oder neuer. Legen Sie einen Ordner und eine virtuelle Umgebung an und installieren Sie die vier Pakete:

mkdir property-scraper && cd property-scraper
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install requests beautifulsoup4 lxml pandas

Mit einer Beispiel-Inseratsseite beginnen

Speichern Sie die folgende Beispielseite als sample_listings.html. Sie enthält vier fiktive Inserate. Zwei davon erscheinen zusätzlich in einem JSON-LD-Block, so wie viele echte Websites strukturierte Daten bereitstellen. Eines ist eine Mietwohnung, eines ein Studio-Apartment. Der Parser muss also beides verarbeiten.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Homes for sale and rent in Springfield (sample page)</title>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "ItemList",
    "itemListElement": [
      {
        "@type": "RealEstateListing",
        "identifier": "SPR-1001",
        "url": "https://example.com/listings/SPR-1001",
        "datePosted": "2026-10-12",
        "offers": {"@type": "Offer", "price": 425000, "priceCurrency": "USD"},
        "about": {
          "@type": "SingleFamilyResidence",
          "address": {"@type": "PostalAddress", "streetAddress": "123 Example St",
                      "addressLocality": "Springfield", "addressRegion": "ST", "postalCode": "00001"},
          "numberOfBedrooms": 3,
          "numberOfBathroomsTotal": 2,
          "floorSize": {"@type": "QuantitativeValue", "value": 1850, "unitCode": "FTK"}
        }
      },
      {
        "@type": "RealEstateListing",
        "identifier": "SPR-1002",
        "url": "https://example.com/listings/SPR-1002",
        "datePosted": "2026-10-20",
        "offers": {"@type": "Offer", "price": 1250000, "priceCurrency": "USD"},
        "about": {
          "@type": "SingleFamilyResidence",
          "address": {"@type": "PostalAddress", "streetAddress": "45 Sample Ave",
                      "addressLocality": "Springfield", "addressRegion": "ST", "postalCode": "00002"},
          "numberOfBedrooms": 5,
          "numberOfBathroomsTotal": 4.5,
          "floorSize": {"@type": "QuantitativeValue", "value": 4100, "unitCode": "FTK"}
        }
      }
    ]
  }
  </script>
</head>
<body>
  <ul class="results">
    <li class="listing-card" data-listing-id="SPR-1001" data-status="for_sale">
      <a class="listing-link" href="https://example.com/listings/SPR-1001">123 Example St, Springfield, ST 00001</a>
      <span class="price">$425,000</span>
      <span class="beds">3 bd</span> <span class="baths">2 ba</span> <span class="area">1,850 sqft</span>
    </li>
    <li class="listing-card" data-listing-id="SPR-1002" data-status="for_sale">
      <a class="listing-link" href="https://example.com/listings/SPR-1002">45 Sample Ave, Springfield, ST 00002</a>
      <span class="price">$1,250,000</span>
      <span class="beds">5 bd</span> <span class="baths">4.5 ba</span> <span class="area">4,100 sqft</span>
    </li>
    <li class="listing-card" data-listing-id="SPR-1003" data-status="for_rent">
      <a class="listing-link" href="https://example.com/listings/SPR-1003">7 Placeholder Ln, Unit 2B, Springfield, ST 00001</a>
      <span class="price">$2,400/mo</span>
      <span class="beds">2 bd</span> <span class="baths">1 ba</span> <span class="area">950 sqft</span>
    </li>
    <li class="listing-card" data-listing-id="SPR-1004" data-status="for_sale">
      <a class="listing-link" href="https://example.com/listings/SPR-1004">88 Demo Rd, Springfield, ST 00003</a>
      <span class="price">$389,900</span>
      <span class="beds">Studio</span> <span class="baths">1 ba</span> <span class="area">610 sqft</span>
    </li>
  </ul>
  <a class="next" href="sample_listings_2.html">Next</a>
</body>
</html>

Der Link „Next“ verweist auf eine zweite Beispielseite. Speichern Sie sie als sample_listings_2.html. Sie wiederholt ein Inserat von Seite 1, was auf echten Websites vorkommt, wenn neue Inserate ältere nach unten schieben:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>Homes in Springfield, page 2 (sample page)</title></head>
<body>
  <ul class="results">
    <li class="listing-card" data-listing-id="SPR-1004" data-status="for_sale">
      <a class="listing-link" href="https://example.com/listings/SPR-1004">88 Demo Rd, Springfield, ST 00003</a>
      <span class="price">$389,900</span>
      <span class="beds">Studio</span> <span class="baths">1 ba</span> <span class="area">610 sqft</span>
    </li>
    <li class="listing-card" data-listing-id="SPR-1005" data-status="for_sale">
      <a class="listing-link" href="https://example.com/listings/SPR-1005">19 Fixture Ct, Springfield, ST 00002</a>
      <span class="price">$615,000</span>
      <span class="beds">4 bd</span> <span class="baths">2.5 ba</span> <span class="area">2,300 sqft</span>
    </li>
  </ul>
</body>
</html>

Stellen Sie den Ordner lokal bereit, damit Ihr Scraper die Seiten per HTTP abruft wie auf einer echten Website:

python -m http.server 8000

Lassen Sie den Server laufen und öffnen Sie für die nächsten Schritte ein zweites Terminal. Fügen Sie den Code aus diesem und den nächsten fünf Schritten der Reihe nach in eine einzige Datei namens scraper.py ein. Beginnen Sie mit den Imports und einer Abruffunktion, die einen ehrlichen User-Agent sendet und bei HTTP-Fehlern sofort mit einem Fehler abbricht:

import json
import re
import time
from datetime import datetime, timezone
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

HEADERS = {"User-Agent": "property-research/1.0 (you@example.com)"}


def fetch(url: str) -> str:
    response = requests.get(url, headers=HEADERS, timeout=30)
    response.raise_for_status()
    return response.text

Zuerst JSON-LD extrahieren

JSON-LD steht in <script type="application/ld+json">-Tags. Eine Seite kann ein Objekt, eine Liste von Objekten oder eine ItemList enthalten, die die Inserate umschließt. Die Hilfsfunktion entpackt daher alle drei Formen. Anschließend bildet sie jedes RealEstateListing auf flache Felder ab:

def iter_jsonld(soup: BeautifulSoup):
    """Yield every JSON-LD object on the page, unwrapping lists and ItemLists."""
    for tag in soup.find_all("script", type="application/ld+json"):
        try:
            data = json.loads(tag.string or "")
        except json.JSONDecodeError:
            continue
        for item in data if isinstance(data, list) else [data]:
            if item.get("@type") == "ItemList":
                for element in item.get("itemListElement", []):
                    yield element.get("item", element)
            else:
                yield item


def listings_from_jsonld(soup: BeautifulSoup) -> dict:
    found = {}
    for item in iter_jsonld(soup):
        if item.get("@type") != "RealEstateListing":
            continue
        home = item.get("about", {})
        addr = home.get("address", {})
        offer = item.get("offers", {})
        found[item["identifier"]] = {
            "listing_id": item["identifier"],
            "url": item.get("url"),
            "address": f"{addr.get('streetAddress')}, {addr.get('addressLocality')}, "
                       f"{addr.get('addressRegion')} {addr.get('postalCode')}",
            "price": offer.get("price"),
            "currency": offer.get("priceCurrency"),
            "beds": home.get("numberOfBedrooms"),
            "baths": home.get("numberOfBathroomsTotal"),
            "sqft": home.get("floorSize", {}).get("value"),
            "source": "json-ld",
        }
    return found

Werte aus JSON-LD sind bereits Zahlen, was Ihnen den Großteil der Bereinigung erspart.

Auf HTML-Selektoren zurückgreifen

Zwei der vier Karten auf Seite 1 haben kein JSON-LD, und keine enthält den Inseratsstatus in den strukturierten Daten. Der HTML-Parser liest jede Karte über ihre data-*-Attribute und Klassennamen und behält den Rohtext jedes Felds. Wenn Selektoren neu für Sie sind, beginnen Sie mit unserem BeautifulSoup-Tutorial.

def text_of(card, selector: str) -> str | None:
    node = card.select_one(selector)
    return node.get_text(strip=True) if node else None


def listings_from_html(soup: BeautifulSoup, base_url: str) -> dict:
    found = {}
    for card in soup.select("li.listing-card"):
        link = card.select_one("a.listing-link")
        listing_id = card["data-listing-id"]
        found[listing_id] = {
            "listing_id": listing_id,
            "status": card.get("data-status"),
            "url": urljoin(base_url, link["href"]),
            "address": link.get_text(strip=True),
            "price_raw": text_of(card, ".price"),
            "beds_raw": text_of(card, ".beds"),
            "baths_raw": text_of(card, ".baths"),
            "sqft_raw": text_of(card, ".area"),
        }
    return found

Bevorzugen Sie auf echten Websites data-*-Attribute und stabile Klassennamen gegenüber langen CSS-Pfaden. Sie überstehen Redesigns besser.

Felder bereinigen und normalisieren

Machen Sie jetzt aus Rohtexten Zahlen. parse_price entfernt alles außer Ziffern, sodass „$1,250,000“ zu 1250000 und „$2,400/mo“ zu 2400 wird. rent_period hält die Information „/mo“ in einer eigenen Spalte fest. normalize führt beide Quellen zusammen, gibt JSON-LD Vorrang, wo es einen Wert hat, kennzeichnet jeden Preis als Angebotspreis oder Angebotsmiete und versieht die Zeile mit einem UTC-Zeitstempel:

def parse_price(text: str | None) -> int | None:
    """'$1,250,000' -> 1250000 and '$2,400/mo' -> 2400."""
    if not text:
        return None
    digits = re.sub(r"[^\d]", "", text.split("/")[0])
    return int(digits) if digits else None


def rent_period(text: str | None) -> str | None:
    if text and re.search(r"/\s*(mo|month)", text, re.I):
        return "month"
    if text and re.search(r"/\s*(wk|week)", text, re.I):
        return "week"
    return None


def parse_number(text: str | None) -> float | None:
    if not text:
        return None
    if "studio" in text.lower():
        return 0.0
    match = re.search(r"\d[\d,]*(\.\d+)?", text)
    return float(match.group().replace(",", "")) if match else None


def normalize(html_row: dict, jsonld_row: dict | None) -> dict:
    raw_price = html_row.get("price_raw")
    row = {
        "listing_id": html_row["listing_id"],
        "status": html_row.get("status"),
        "price": parse_price(raw_price),
        "currency": "USD" if raw_price and "$" in raw_price else None,
        "rent_period": rent_period(raw_price),
        "beds": parse_number(html_row.get("beds_raw")),
        "baths": parse_number(html_row.get("baths_raw")),
        "sqft": parse_number(html_row.get("sqft_raw")),
        "address": html_row.get("address"),
        "url": html_row.get("url"),
        "source": "html",
    }
    # Structured data wins wherever it has a value.
    for key, value in (jsonld_row or {}).items():
        if value is not None:
            row[key] = value
    row["price_type"] = "asking_rent" if row["status"] == "for_rent" else "asking_price"
    row["sqft"] = int(row["sqft"]) if row["sqft"] is not None else None
    row["collected_at"] = datetime.now(timezone.utc).isoformat(timespec="seconds")
    row["price_raw"] = raw_price
    return row


def parse_page(html: str, base_url: str) -> list[dict]:
    soup = BeautifulSoup(html, "lxml")
    structured = listings_from_jsonld(soup)
    cards = listings_from_html(soup, base_url)
    return [normalize(card, structured.get(lid)) for lid, card in cards.items()]

Die Spalte source hält fest, woher die Werte jeder Zeile stammen. Verschwindet JSON-LD nach einem Redesign von einer Seite, merken Sie es an dieser Spalte, bevor Ihre Zahlen falsch werden.

Paginierung und Duplikate behandeln

Der Crawler folgt dem Link „Next“, bis es keinen mehr gibt, wartet zwischen den Anfragen und überspringt bereits gesehene Inserats-IDs. Er stoppt außerdem bei einer leeren Seite und nach max_pages, damit ihn ein defekter Link nicht in eine Endlosschleife schickt:

def crawl(start_url: str, max_pages: int = 20, delay: float = 2.0) -> list[dict]:
    rows, seen, url = [], set(), start_url
    for _ in range(max_pages):
        html = fetch(url)
        page_rows = parse_page(html, url)
        new_rows = [r for r in page_rows if r["listing_id"] not in seen]
        seen.update(r["listing_id"] for r in new_rows)
        rows.extend(new_rows)
        print(f"{url}: {len(page_rows)} cards, {len(new_rows)} new")

        next_link = BeautifulSoup(html, "lxml").select_one("a.next")
        if not page_rows or not next_link:
            break
        url = urljoin(url, next_link["href"])
        time.sleep(delay)
    return rows

Auf einer echten Website ist eine Verzögerung von zwei Sekunden oder mehr ein sinnvoller Standardwert. Erhöhen Sie sie, wenn der Server langsamer wird oder Fehler zurückgibt.

Als CSV exportieren

Der letzte Block startet den Crawl und schreibt listings.csv mit pandas:

if __name__ == "__main__":
    import pandas as pd

    rows = crawl("http://localhost:8000/sample_listings.html", delay=1.0)
    df = pd.DataFrame(rows)
    df.to_csv("listings.csv", index=False)
    print(df[["listing_id", "price_type", "price", "rent_period",
              "beds", "baths", "sqft", "source"]].to_string(index=False, na_rep=""))

Führen Sie python scraper.py aus. Ausgabe für die Beispielseiten:

http://localhost:8000/sample_listings.html: 4 cards, 4 new
http://localhost:8000/sample_listings_2.html: 2 cards, 1 new
listing_id   price_type   price rent_period  beds  baths  sqft  source
  SPR-1001 asking_price  425000               3.0    2.0  1850 json-ld
  SPR-1002 asking_price 1250000               5.0    4.5  4100 json-ld
  SPR-1003  asking_rent    2400       month   2.0    1.0   950    html
  SPR-1004 asking_price  389900               0.0    1.0   610    html
  SPR-1005 asking_price  615000               4.0    2.5  2300    html

Aus sechs Karten wurden fünf eindeutige Inserate: Das wiederholte SPR-1004 auf Seite 2 wurde übersprungen. Die ersten beiden Zeilen haben ihre Werte aus JSON-LD, die übrigen aus HTML. Die Mietwohnung behält ihren monatlichen Zeitraum, und das Studio hat null Schlafzimmer statt eines fehlenden Werts. Die CSV-Datei enthält zusätzlich status, currency, address, url, collected_at und den rohen Preistext für jede Zeile.

JavaScript-lastige Seiten mit einer Scraper-API abrufen

Die Beispielseite ist statisch. Viele echte Inseratsseiten laden ihre Daten per JavaScript, und manche zeigen je nach Standort des Besuchers andere Ergebnisse. In diesen Fällen kann eine Scraper-API die Seite über einen echten Browser aus dem Land Ihrer Wahl abrufen und das fertige HTML zurückgeben. Rendering und Standort sind zugleich die beiden Einstellungen, die am häufigsten darüber entscheiden, ob Sie dieselbe Seite sehen wie ein Besucher. Lesen Sie dazu auch, wie Sie Sperren und Rate Limits vermeiden.

Die folgende Anfrage nutzt den v2-Endpunkt von WebScrapingAPI. Lesen Sie den Schlüssel aus einer Umgebungsvariable und geben Sie ihn nie aus. TARGET_URL ist ein Platzhalter für eine Seite, die Sie erfassen dürfen, etwa die Website Ihres eigenen Maklerbüros oder die eines Partners:

import os

import requests

from scraper import parse_page

TARGET_URL = "https://www.your-brokerage.example/listings?city=springfield"

response = requests.get(
    "https://api.webscrapingapi.com/v2",
    params={
        "api_key": os.environ["WSA_API_KEY"],
        "url": TARGET_URL,
        "render_js": 1,
        "country": "us",
    },
    timeout=90,
)
response.raise_for_status()
rows = parse_page(response.text, TARGET_URL)
print(f"{len(rows)} listings parsed")

Setzen Sie den Schlüssel zuerst in Ihrer Shell mit export WSA_API_KEY=.... Der Antwort-Body ist das gerenderte HTML, daher verarbeitet parse_page aus Ihrem Scraper ihn unverändert. Nur die Selektoren müssen zur Zielseite passen.

Wie kommen Sie ohne Scraping an Hauspreise?

Laden Sie sie herunter. Realtor.com, Zillow und Redfin veröffentlichen kostenlose Wohnungsmarktdateien mit Median-Angebotspreisen, Bestand, Vermarktungsdauer und Preissenkungen nach Metropolregion, County oder Postleitzahl, monatlich aktualisiert. Der House Price Index der FHFA verfolgt Wiederverkaufspreise. Diese Daten beantworten Fragen auf Marktebene ganz ohne Scraping.

Die wichtigsten Quellen:

  • Realtor.com-Datenbibliothek für Wohnimmobilien. Die Realtor.com-Datenbibliothek für Wohnimmobilien bietet monatliche CSV-Dateien nach Land, Bundesstaat, Metropolregion, County und Postleitzahl, in aktuellen und historischen Versionen.
  • Zillow Research. Die Daten von Zillow Research umfassen Immobilienwert- und Mietindizes, Bestands- und Verkaufspreisdateien, veröffentlicht für Ihre eigene Analyse.
  • Redfin Data Center. Das Redfin Data Center veröffentlicht Market-Tracker-Dateien mit Verkaufspreisen, Bestand und Preissenkungen.
  • FHFA. Der House Price Index der FHFA misst Preisveränderungen anhand wiederholter Verkäufe derselben Häuser.

Dieses Beispiel liest die Metro-Datei von Realtor.com direkt in pandas ein und listet die 10 Metropolregionen mit dem höchsten Median-Angebotspreis:

import pandas as pd

CSV_URL = ("https://econdata.s3-us-west-2.amazonaws.com/"
           "Reports/Core/RDC_Inventory_Core_Metrics_Metro.csv")

metros = pd.read_csv(CSV_URL)
month = metros["month_date_yyyymm"].iloc[0]
top = (metros.dropna(subset=["median_listing_price"])
             .nlargest(10, "median_listing_price")
             [["cbsa_title", "median_listing_price",
               "active_listing_count", "median_days_on_market"]])
print(f"Data month: {month}")
print(top.to_string(index=False))

Ausgabe:

Data month: 202609
                        cbsa_title  median_listing_price  active_listing_count  median_days_on_market
                     Nantucket, MA             5873250.0                   145                   84.0
                Vineyard Haven, MA             2495000.0                   260                   99.0
                    Jackson, WY-ID             2150000.0                   418                  108.0
     Santa Maria-Santa Barbara, CA             1720750.0                   718                   58.0
                         Heber, UT             1594500.0                  1595                   90.0
                         Rifle, CO             1510750.0                   875                   93.0
                         Kapaa, HI             1507750.0                   385                  116.0
San Jose-Sunnyvale-Santa Clara, CA             1388472.0                  2112                   35.0
                       Salinas, CA             1289500.0                   551                   66.0
                          Napa, CA             1272500.0                   572                   81.0

Quelle: Realtor.com Residential Data Library, Kernkennzahlen nach Metropolregion, September 2026 (month_date_yyyymm 202609).

Die Datei enthält außerdem price_reduced_share, new_listing_count, pending_listing_count und median_listing_price_per_square_foot sowie jeweils die Veränderungen zum Vormonat und zum Vorjahr. Geben Sie bei jedem Lauf den Monat aus, denn die Datei wird monatlich aktualisiert und Ihr Bericht sollte angeben, welchen Monat er beschreibt. Nennen Sie die Quelle unter jedem Diagramm und jeder Tabelle, die Sie veröffentlichen.

Für Trends im Zeitverlauf bietet dieselbe Bibliothek von jeder Datei eine _History-Version mit einer Zeile pro Metropolregion und Monat. Tauschen Sie den Dateinamen in CSV_URL aus, filtern Sie nach cbsa_title und stellen Sie median_listing_price gegen month_date_yyyymm dar. Dateien auf Postleitzahlebene verwenden dieselben Kennzahlenspalten mit eigenen Geografiespalten, daher ändert sich der Code kaum.

Wie prüfen Sie, ob gescrapte Immobiliendaten korrekt sind?

Prüfen Sie jeden Lauf anhand einiger Regeln. Jede Zeile hat eine Adresse, einen Preis und eine Quell-URL. Die Preise liegen in einer für den Markt plausiblen Spanne. Die Zeilenzahl liegt nahe an der Gesamtzahl, die die Website angibt. Keine Inserats-ID kommt doppelt vor. Kauf-, Miet- und Schätzwerte teilen sich nie eine Preisspalte.

Ein Scraper, der HTTP 200 zurückgibt, kann trotzdem Unsinn liefern. Diese Prüfungen fangen die häufigsten Fehler ab:

Prüfung

Regel

Maßnahme bei Fehlschlag

Pflichtfelder

Jede Zeile hat eine Adresse, einen Preis und eine Quell-URL

Lauf anhalten und die Zeilen prüfen

Plausibilität der Preise

Preis über null, im normalen Bereich des Markts, Währung gesetzt

Zeilen markieren; auf fehlende Ziffer oder eine Miete in der Kaufpreisspalte prüfen

Mietzeitraum

Jede Mietwohnung hat einen Zeitraum (Monat oder Woche)

Parser vor dem Laden korrigieren

Zeilenzahl

Nahe an der Gesamtzahl, die die Website für die Suche anzeigt

Nach einem Paginierungslimit oder einer verpassten Seite suchen

Doppelte IDs

Keine Inserats-ID kommt in einem Lauf doppelt vor

Deduplizierung korrigieren; prüfen, ob sich IDs zwischen Seiten ändern

Feld-Drift

Der Anteil leerer Werte pro Feld bleibt nahe am letzten Lauf

Mit dem vorherigen Lauf vergleichen; ein Sprung bedeutet einen defekten Selektor

Veraltete Seiten

Verkaufte und vom Markt genommene Inserate sind markiert, nicht als aktiv gezählt

Status aktualisieren und die Historie behalten

Parser-Ausfall

Null Zeilen oder plötzlicher Einbruch der Zeilenzahl

Alarm auslösen und die Daten von gestern live lassen

Einige dieser Prüfungen passen in ein kurzes pandas-Skript, das nach jedem Crawl läuft:

import pandas as pd

df = pd.read_csv("listings.csv")
problems = []

missing = df[df[["address", "price", "url"]].isna().any(axis=1)]
if len(missing):
    problems.append(f"{len(missing)} rows missing address, price, or URL")

sale = df[df["price_type"] == "asking_price"]
if not sale["price"].between(10_000, 50_000_000).all():
    problems.append("sale price outside the plausible range")

rent = df[df["price_type"] == "asking_rent"]
if rent["rent_period"].isna().any():
    problems.append("rental without a rent period")

if df["listing_id"].duplicated().any():
    problems.append("duplicate listing IDs")

null_share = df.isna().mean().round(2)
print(null_share[null_share > 0].to_dict())
print("OK" if not problems else problems)

Ausgabe für die Beispieldaten:

{'rent_period': 0.8}
OK

Nur rent_period enthält leere Werte, und das ist zu erwarten: Vier der fünf Inserate stehen zum Verkauf. Speichern Sie die Anteile leerer Werte jedes Laufs, damit die Feld-Drift-Prüfung eine Vergleichsbasis hat.

Welche Tools für Immobilien-Scraping sollten Sie nutzen?

Wählen Sie danach, wie viel Sie selbst betreiben möchten. Python-Bibliotheken wie requests und BeautifulSoup eignen sich für statische Seiten. Playwright bewältigt JavaScript-lastige Websites. Eine Scraper-API ergänzt Rendering, Proxys und Geotargeting ohne eigene Infrastruktur. Eine Daten-API oder ein Datensatz liefert strukturierte Inserate ganz ohne Parser. MLS-Feeds bleiben die maßgebliche Quelle für lizenzierte Inseratsdaten.

Kategorie

Beispiele

Was Sie pflegen

Am besten für

Grenzen

HTTP- und Parser-Bibliotheken

requests, httpx, BeautifulSoup, lxml

Alles: Abruf, Parsing, Zeitplanung, Proxys

Statische Seiten, kleine erlaubte Aufgaben

Kein JavaScript; Sperren sind Ihre Sache

Browser-Automatisierung

Playwright, Selenium

Browser, Parsing, Server

JavaScript-lastige Seiten

Langsamer und ressourcenintensiver pro Seite

Scraper-APIs

Scraper API von WebScrapingAPI und ähnliche Dienste

Parsing und Zeitplanung

Gerenderte Seiten erlaubter Websites in jedem Umfang

Den Parser schreiben und reparieren Sie weiterhin selbst

Daten-APIs und Datensätze

Data API von WebScrapingAPI (Zillow, Redfin, Zoopla) und andere Anbieter

Nichts außer Ihrer Pipeline

Strukturierte Inseratsdatensätze ohne Parser-Team

Abdeckung und Felder legt der Anbieter fest; auf Anfrage

No-Code-Tools

Visuelle Point-and-Click-Scraper und Browser-Erweiterungen

Point-and-Click-Konfigurationen

Einmalige Abzüge durch Nicht-Entwickler

Schwer zu versionieren, zu testen und zu skalieren

MLS-Feeds und Aggregatoren

RESO Web API über ein MLS oder einen zugelassenen Anbieter

Integration und Anzeige-Compliance

Maßgebliche Inserats- und Verkaufsdaten

Lizenzen, Verträge, Anzeigeregeln

Wenn Sie Zillow-Inserate in großem Umfang brauchen, liefert Ihnen ein gepflegter Zillow-Datenfeed strukturierte Datensätze von einem Anbieter, der die Erfassung übernimmt, statt eines Scrapers, den Sie selbst bauen und verteidigen müssten. An den Aussagen der Zillow-Bedingungen zu Ihrem eigenen Scraping ändert das nichts. Wenn Sie eigenen Code gegen einen Dienst abwägen, lesen Sie, wie Sie sich zwischen selbst bauen oder kaufen entscheiden.

Wo finden Sie Leitfäden für bestimmte Immobilienseiten?

Wir haben Schritt-für-Schritt-Anleitungen für mehrere Immobilienseiten, jeweils mit eigenen rechtlichen Hinweisen:

FAQ

Das hängt von der Website, den Daten und Ihrem Land ab. Viele große Portale verbieten Scraping in ihren Nutzungsbedingungen, und Inseratsfotos sind oft urheberrechtlich geschützt. Öffentliche, nicht personenbezogene Daten von Websites, die automatisierten Zugriff erlauben, bergen deutlich weniger Risiko. Wenn die Bedingungen es verbieten, nutzen Sie Open Data oder einen lizenzierten Feed und holen Sie anwaltlichen Rat ein.

Darf ich Zillow scrapen?

Die Nutzungsbedingungen von Zillow verbieten automatisierte Abfragen, einschließlich Screen-Scraping, Crawlern und dem Umgehen von Captchas. Für Markttrends laden Sie die Daten von Zillow Research herunter, die Zillow für Ihre eigene Analyse veröffentlicht. Für Datensätze auf Inseratsebene nutzen Sie einen lizenzierten Datenanbieter oder einen MLS-Feed. Bauen Sie kein Geschäft auf Daten auf, die entgegen den Bedingungen erfasst wurden.

Was ist der beste Immobilien-Scraper?

Das eine beste Tool gibt es nicht. Für statische Seiten, die Sie erfassen dürfen, reicht Python mit requests und BeautifulSoup. Für JavaScript-lastige Seiten nutzen Sie Playwright oder eine Scraper-API. Wenn Sie keine Parser pflegen möchten, liefert eine Immobilien-Daten-API oder ein lizenzierter Datensatz strukturierte Inserate direkt.

Gibt es eine kostenlose Immobilien-Daten-API?

Auf Inseratsebene sind nur wenige kostenlos. Kostenlose Angebote bewegen sich meist auf Marktebene: Realtor.com, Zillow und Redfin veröffentlichen herunterladbare Wohnungsmarktdateien, und die FHFA veröffentlicht ihren House Price Index. APIs auf Inseratsebene und MLS-Feeds erfordern meist einen kostenpflichtigen Tarif, eine Lizenz oder eine Maklerbeziehung. Prüfen Sie die Bedingungen jeder Quelle, bevor Sie die Daten weiterverwenden.

Wie oft sollte man Immobilieninserate scrapen?

Richten Sie den Zeitplan danach, wie schnell sich die Daten ändern. Tägliche Läufe erfassen in aktiven Märkten neue Inserate, Preissenkungen und Statusänderungen. Wöchentliche Läufe eignen sich für ruhigere Märkte und für die Forschung. Für Trendanalysen genügen monatliche Open-Data-Dateien. Rufen Sie nur geänderte Inserate erneut ab, um die Last auf der Quellseite zu senken.

Braucht man Proxys, um Immobilien-Websites zu scrapen?

Nicht für kleine, rücksichtsvolle Aufgaben auf Websites, die die Erfassung erlauben. Große Läufe brauchen oft Proxys, JavaScript-Rendering und standortspezifische Ergebnisse, die eine Scraper-API bündelt. Proxys ändern nichts an den Nutzungsbedingungen einer Website. Wenn ein Portal Scraping verbietet, erhöht das Rotieren von IP-Adressen zum Umgehen seiner Sperren das rechtliche Risiko.

Wie sammelt man Objektfotos in großem Umfang?

Speichern Sie Bild-URLs und Metadaten statt Kopien, sofern Sie keine Rechte an den Fotos haben. Inseratsfotos gehören meist dem Fotografen, dem Makler oder dem MLS, nicht dem Portal. Für eine lizenzierte Weiterverwendung beziehen Sie Bilder über einen MLS- oder IDX-Feed oder einen Datenanbieter, dessen Lizenz die Anzeige abdeckt, und behalten Sie die Quellenangabe bei.

Welchen Ansatz sollten Sie wählen?

Gehen Sie von der Frage aus, die Sie beantworten müssen, nicht vom Scraper:

  • Zahlen auf Marktebene wie Medianpreise, Bestand und Vermarktungsdauer: Laden Sie Open Data herunter.
  • Datensätze auf Inseratsebene in großem Umfang: Lizenzieren Sie einen MLS-Feed oder nutzen Sie eine Daten-API.
  • Ihre eigenen Websites, die Ihrer Partner und erlaubte öffentliche Quellen: Nutzen Sie eine Scraper-API oder den Python-Scraper aus diesem Leitfaden.

Welchen Weg Sie auch wählen: Halten Sie die drei Ebenen getrennt, kennzeichnen Sie jeden Preis mit seiner Art und führen Sie die Qualitätsprüfungen bei jedem Ladevorgang aus.

Immobiliendaten erhalten, ohne Scraper zu pflegen

Sie brauchen Inseratsdatensätze, Preise und Historien für Ihre Märkte? Nennen Sie uns die Quellen und Felder, und wir stellen einen passenden Feed zusammen. Immobiliendaten entdecken

Sie erfassen Daten von eigenen oder erlaubten Websites? Starten Sie mit Scraper API und 5.000 kostenlosen Anfragen. Keine zusätzlichen Credits für JavaScript-Rendering oder Geotargeting, und fehlgeschlagene Anfragen werden nicht berechnet. Scraper-API-Tarife ansehen

Über den Autor

Robert Munceanu, Full-Stack-Entwickler @ WebScrapingAPI

Robert Munceanu

Full-Stack-Entwickler

Robert Munceanu ist Full-Stack-Entwickler bei WebScrapingAPI, wo er in allen Bereichen des Produkts mitwirkt und an der Entwicklung zuverlässiger Tools und Funktionen zur Unterstützung der Plattform mitwirkt.

Web-Scraping mit AWS Lambda: Leitfaden für Python und Java 2026
Anleitungen

Web-Scraping mit AWS Lambda: Leitfaden für Python und Java 2026

TL;DR: Kurz gesagt: Web-Scraping mit AWS Lambda funktioniert am besten, wenn jeder Aufruf kurz, begrenzt und unabhängig wiederholbar ist. Beginnen Sie mit direktem HTTP, AWS SAM und S3 und fügen Sie erst dann SQS, Container, Browser-Rendering, Proxys oder eine verwaltete Abrufebene hinzu, wenn sich im Rahmen der Arbeitslast herausstellt, dass diese erforderlich sind.

Suciu Dan26 min read
Artikel lesen
So verwenden Sie GoSpider: Crawlen, URLs bereinigen und Daten extrahieren
Anleitungen

So verwenden Sie GoSpider: Crawlen, URLs bereinigen und Daten extrahieren

TL;DR: GoSpider ist ein Befehlszeilen-Crawler zum Auffinden von URLs, kein vollständiger Scraper für strukturierte Daten. Diese Anleitung zur Verwendung von GoSpider zeigt einen begrenzten Crawl, die saubere Verarbeitung der Ausgabe, die Übergabe von Colly an CSV sowie einen Diagnosepfad für 403-Antworten oder Seiten, die eine JavaScript-Darstellung erfordern.

Suciu Dan20 min read
Artikel lesen
Wie man Redfin scrappt: Python-Leitfaden für Immobiliendaten
Anleitungen

Wie man Redfin scrappt: Python-Leitfaden für Immobiliendaten

TL;DR: Redfin stellt versteckte API-Endpunkte zur Verfügung, die strukturiertes JSON für Immobilienangebote zurückgeben, wodurch das fragile HTML-Parsing vollständig übersprungen werden kann. Diese Anleitung führt Sie durch den Aufbau eines Python-Scrapers, der Miet- und Verkaufsdaten extrahiert, nach Standort sucht, neue Angebote über XML-Sitemaps überwacht und saubere Ergebnisse in CSV oder JSON exportiert.

Suciu Dan11 min read
Artikel lesen

Los geht’s

Sind Sie bereit, Ihre Datenerfassung zu erweitern?

Schließen Sie sich den über 2.000 Unternehmen an, die WebScrapingAPI nutzen, um Webdaten im Unternehmensmaßstab ohne zusätzlichen Infrastrukturaufwand zu extrahieren.