ImmobilienScout24 Mining Tutorial: Der Web Scraper

Wie versprochen gibt es hier das Tutorial zur Artikelreihe über ImmobilienScout24 Mining. Hier erfährst du genau, wie du den Web Scraper baust, mit dem die Daten geschürft wurden.

Auchtung! Um dieses Tutorial genau nachvollziehen zu können, sind zumindest grundlegende Programmierkenntnisse wünschenswert. Den Scraper habe ich in Python geschrieben. Hier ist das komplette Skript als HTML: ImmobilienScout24 Mining

Der Scraper: Grundidee und Vorgehensweise

Bevor wir detailliert in die Beschreibung des Codes einsteigen, möchte ich kurz zusammenfassen, was der Scraper überhaupt macht.

Als erstes besucht der Scraper genau diese Seite. Sieht aus wie die normale erste Ergebnisseite ohne sonstige Suchkriterien. Das stimmt auch fast. Alle auf ImmobilienScour24 zu findenden Wohnungen in Deutschland werden vorgeschlagen. Allerdings sind die Angebote hier schon so sortiert, dass die neuesten ganz oben stehen. Wichtig! Ändert man die Art der Sortierung nämlich nicht und bleibt bei der Standardsortierung, dann sind die Wohnungen zuerst zu sehen, die eine bezahlte Premiumplatzierung haben. Mit dieser Sortierung würden wir immer wieder dieselben Daten speichern.

Nachdem der Scraper auf der Seite angelangt ist, durchsucht er den Quellcode nach URLs, die den Text “/expose/” enthalten und speichert diese in einer Liste. Die gespeicherten URLs führen nämlich zu den einzelnen Wohnungsangeboten. Insgesamt sind auf der ersten Ergebnisseite 20 Wohnungen zu sehen. Nachdem die Liste mit den URLs befüllt wurde, geht der Scraper diese Schritt für Schritt durch. In jedem Schritt besucht der Scraper eine der URLs und durchforstet auch hier den Quellcode. Die relevanten Stellen werden ausgelesen und mit diesen Daten wird eine Tabelle befüllt. Mit jeder URL wird unsere Datenbasis eine Zeile länger. Wenn die Daten aller 20 Wohnungen in der Tabelle gespeichert wurden, wird diese als  CSV-Datei in einem Ordner abgelegt.

So weit, so gut. Und dann?

Da wir nicht nur von 20 Wohnungen die Daten speichern wollen, durchläuft der Scraper eine (Endlos-)Schleife.  Nach jeden Durchlauf “schläft” der Scraper für eine gewisse Zeit, damit die Seite sich aktualisieren kann. Dann speichert er erneut die aktuellsten 20 Angebote. Je kürzer die Pause, desto weniger Wohnungen entwischen dem Programm. Damit kann jedoch auch der Prozentsatz der Duplikate größer werden. Wählt man die Schlafzeit hingegen sehr großzügig, dann sind gar keine Duplikate im Datensatz enthalten. Dafür sind einem mit Sicherheit einige Daten durch die Lappen gegangen.

Ich habe mich für eine Pause von einer Minute entschieden. Allerdings befürchte ich, dass vor allem nachts sehr viele Duplikate in den Datensatz fließen, da wahrscheinlich nur die wenigsten Makler und Privatpersonen Angebote um diese Uhrzeit posten. Nach einem 24-stündigen Testlauf betrug der Prozentsatz eindeutiger Wohnungen unter allen Angeboten nur rund 10 Prozent. Trotzdem habe ich mich dafür entschieden, die Schlafzeit des Scrapers nicht zu verlängern, da die Duplikate im endgültigen Datensatz ohne weiteres wieder gelöscht werden können. Man sollte natürlich immer den noch verfügbaren Speicherplatz im Auge behalten. Bei sehr großen Datensätzen bzw. geringem Speicherplatz kann es sich lohnen, die Zahl der Duplikate möglichst klein zu halten.

Und jetzt zum Code!

21 Gedanken zu „ImmobilienScout24 Mining Tutorial: Der Web Scraper

  • 11. Februar 2018 um 13:43
    Permalink

    Hallo,

    danke für die detaillierte Erklärung der einzelnen Codezeilen. Beim nachbauen habe ich allerdings die Orientierung verloren, welche COdezeile zu welchem Block (Try, For, etc.) gehört. Könntest Du vielleicht nochmal den kompletten Code posten, damit man sieht, wie die Einrückungen sind?

    Danke
    ein Pythonanfänger

    Antwort
    • 11. Februar 2018 um 13:49
      Permalink

      … jetzt habe ich es selbst gefunden. Sorry.

      Antwort
      • 15. Februar 2018 um 20:02
        Permalink

        Kein Ding! Hat’s funktioniert? Bei weiteren Fragen kannst du auch gern eine Mail schreiben.

        Antwort
  • 13. August 2018 um 00:26
    Permalink

    Danke für das Tutorial! Sehr gut erklärt.
    Ich möchte mit der gesamelten Data noch ein paar Rechnungen innerhalb des Skriptes einbauen.
    Wie könnte ich z.B. Python jetzt sagen “mit obj_purchasePrice und obj_livingSpace rechne mir den m² -Preis”? Leider bin ich Anfänger und komme hier nicht weiter.

    Antwort
    • 13. August 2018 um 10:20
      Permalink

      Hi Matthias,

      danke für das Feedback!

      Zu deiner Frage: Wenn du das Tutorial abgeschlossen hast, liegen ja alle Daten gesammelt in einem DataFrame vor. Mit den Spalten des DataFrames kannst du natürlich auch weitere Berechnungen durchführen. Um mit Hilfe der Merkmale “obj_purchasePrice” und “obj_livingSpace” eine neue Spalte mit dem Quadratmeterpreis zu erstellen, machst du folgendes:

      df[“qm_preis”] = df.obj_purchasePrice/df.obj_livingSpace

      oder

      df[“qm_preis”] = df[“obj_purchasePrice”]/df[“obj_livingSpace”]

      Beide Befehle äquivalent zueinander. In derselben Weise kannst du mit “*”,”+” und “-” auch Spalten miteinander multiplizieren, addieren und voneinander subtrahieren.

      Sag Bescheid, wenn’s geklappt hat! 🙂

      Antwort
  • 25. September 2018 um 08:54
    Permalink

    Hallo Cris
    ist es auch möglich nicht nur aktuelle Daten auszulesen, oder besteht die Möglichkeit auch historische
    Immobiliendaten beim Scout auszulesen.
    Finde deine Projekte extrem spannend.

    LG

    Klaus

    Antwort
    • 30. September 2018 um 11:44
      Permalink

      Hi Klaus,

      danke für dein Feedback! 🙂
      Natürlich kannst du generell nur das scrapen, was sich auch auf der Seite finden lässt. Allerdings gibt es die Möglichkeit, nicht nur immer die neuen Angebote auf der ersten Seite zu scrapen, sondern alle Angebote auszulesen, die im Moment online sind. Genau das habe ich im Beitrag zu Häusern auf ImmobilienScout24 gemacht.

      Der Web Scraper für Häuser

      Bei Fragen schreib mir gern auf meiner Facebookseite eine Nachricht. -> StatisQuo auf Facebook

      Viele Grüße

      Chris

      Antwort
  • 10. Mai 2020 um 17:28
    Permalink

    Hallo Chris,

    vielen Dank für die gute Vorlage und die entsprechenden Analysen, wirklich sehr spannend!

    Eine Frage zu dem Code: nachdem die keyValues ja doch recht umfangreich sind, wie würde man denn den Code dahingehend anpassen, dass nur einige der interessanteren features ausgelesen werden (e.g. “obj_yearConstructed”, “obj_totalRent”, …)?

    Viele Grüße,
    Simon

    Antwort
  • 27. Mai 2020 um 19:04
    Permalink

    Hallo,

    was eigentlich noch fehlt wäre das auslesen, auf welcher Seite man sich auf immobilienscout befindet. Bei mehr Treffer als 20 gibt es ja mehrere Seiten, auf denen die Ergebnisse angezeigt werden.

    Antwort
    • 29. Mai 2020 um 13:11
      Permalink

      Hi Patrick,

      man befindet sich immer auf Seite 1.

      Antwort
  • 10. August 2020 um 14:45
    Permalink

    Hallo Chris,

    danke erst mal für super spannenden Blogeinträge! Mir ist aufgefallen, dass über die “keyValues” leider keine Variable für das Hausgeld gefunden wird. Hast du eine Idee woran das liegen könnte und wie ich die Variable zu dem Scraper hinzufügen kann? Bei den meisten Postings auf Immobilienscout 24 scheint das Hausgeld auf jeden Fall angegeben zu sein und brauche diese Variable sehr dringend.

    Beste Grüße
    Jannis

    Antwort
  • 13. August 2020 um 16:46
    Permalink

    Hallo alle,
    ich scrape seit einigen Monaten regelmäßig die Immoscout seite. Dabei mache ich eine Umkreis-Suche. Die Seite mit den Suchergebnissen lässt sich seit etwa einer Woche nicht mehr scrapen. Habt ihr ähnliche Probleme und könnte es dafür eine Lösung geben?

    Danke
    Laura

    Antwort
    • 14. August 2020 um 08:08
      Permalink

      Hi Laura,

      Immoscout scheint Scraper jetzt zu blockieren, siehe die unteren Kommentare unter dem Beitrag zu den Häuserdaten.

      Die Alternative dazu ist entweder mit Selenium einen Browser zu simulieren oder die API zu nutzen. Hättest du Interesse an einem Tutorial für die API? Vorweg: Um die zu nutzen, braucht man einen Developer Account bei Immoscout.

      Viele Grüße
      Chris

      Antwort
  • 15. August 2020 um 12:02
    Permalink

    Auch falls jemand anderes eine Idee hat, wie ich das Hausgeld zu den “keyValues” hinzufügen kann, wäre ich sehr dankbar. 🙂

    Beste Grüße
    Jannis

    Antwort
  • 23. August 2020 um 14:55
    Permalink

    Hallo Chris,
    ich wollte mich auch gerade ans scrapen machen und musste das gleiche feststellen. Also habe ich mir mal die API Geschichte angesehen und auch einen Zugang bekommen. Für mich sieht es aber danach aus als könnte man nur grundlegende Infos Abfragen zu konkreten Exposés und keine generelle Suche starten. Oder geht das doch?
    Ansonsten gehe ich das Thema mit selenium an.

    Viele Grüße,
    Marius

    Antwort
    • 24. August 2020 um 07:59
      Permalink

      Hi Marius,

      zu Selenium: Hab ich letztens ausprobiert, man wird quasi direkt als Bot erkannt. Ich konnte einmal in der Suche ein paar Exposé IDs abgreifen, aber dann nicht weiter machen…

      Also kannst du die API auch als nicht-Content-Partner benutzen? Was sind denn so die Infos zu den Exposés? Weniger als beim Scraper?

      Echt schade, dass Immoscout uns das Leben so schwer macht.

      Viele Grüße
      Chris

      Antwort
  • 27. August 2020 um 10:34
    Permalink

    Das ist ja eine sehr geniale Darstellung. Danke dafür!
    Ich hätte aber irgendwie ein Problem am Anfang:
    Wenn ich den Loop ausführe, dann kommt eine für mich nicht klare EOF parcing – Fehlermeldung
    File “”, line 9
    soup = bs.BeautifulSoup(urllib.request.urlopen(‘https://www.immobilienscout24.de/Suche/S-2/Wohnung-Miete’).read(), ‘lxml’)
    ^
    SyntaxError: unexpected EOF while parsing

    Kannst Du bitte einen Tipp geben, woran das liegen kann?

    Antwort
    • 27. August 2020 um 10:49
      Permalink

      Hi Roman,

      den Fehler kann ich leider nicht reproduzieren. Bist du sicher, dass du den Code 1:1 kopiert hast? Ist eigentlich ein einfacher Syntaxfehler. Könnte sein, dass eine Zeile fehlt.

      Aber da Immobilienscout jetzt Scraper blockt, dürfte der Code eh nicht mehr funktionieren leider, siehe Kommentaren unter dem anderen Beitrag

      Viele Grüße
      Chris

      Antwort
    • 3. September 2020 um 16:19
      Permalink

      Hallo Chris,

      ich habe deinen Code bei immowelt.de verwendet. Dazu musste ich ihn bei links etc. anpassen.

      Dabei habe ich festgestellt, dass ich immer nur den Inhalt der ersten Seite bekomme.

      Wenn ich dem Link aus der Abfrage folge, dann wird auch immer nur die erste Seite angezeigt.

      Kannst Du mir eine Empfehlung geben, wie ich das Problem behebe?

      Unten der Codeteil, an dem ich jetzt arbeite.

      import bs4 as bs
      import urllib.request
      import time
      from datetime import datetime
      import pandas as pd
      import json

      for seite in range(1,5):
      print(“Loop ” + str(seite) + ” startet.”)
      df = pd.DataFrame()
      l=[]

      soup = bs.BeautifulSoup(urllib.request.urlopen(“https://www.immowelt.de/gewerbeliste/bl-bayern/renditeobjekte/kaufen?sd=DESC&sf=RELEVANCE&sp”+str(seite)).read(),’lxml’)
      print(“Aktuelle Seite: “+”https://www.immowelt.de/gewerbeliste/bl-bayern/renditeobjekte/kaufen?sd=DESC&sf=RELEVANCE&sp”+str(seite))
      for paragraph in soup.find_all(“a”):
      if r”/expose/” in str(paragraph.get(“href”)):
      l.append(paragraph.get(“href”).split(“#”)[0])
      #l = list(set(l))

      Antwort
      • 4. September 2020 um 00:13
        Permalink

        Ich ziehe meine Frage zurück. Es funktioniert. Es war nur etwas tricky, weil die das letzte Zeichen in dem Link sich änderte. 🙂
        woran ich aber jetzt tatsächlich gescheitert bin, ist der Fehler unten:

        ID https://www.immowelt.de/expose/2w7m84g entfernt.
        2020-09-04 00:10:31.919064: could not broadcast input array from shape (22) into shape (1)

        es liegt wohl an der Beschreibung der Merkmale, die in Form einer Liste einzeln gespeichert werden.

        Wenn das Programm versucht, diese zu parsen, schafft es das nicht, weil die Länge anders ist.

        Was könnte man hier machen? Kann mir jemand einen Tipp geben?

        Antwort
  • 28. August 2020 um 18:17
    Permalink

    Hallo Chris,

    verstehe ich das nun richtig, dass es damit gerade keine Lösung gibt?
    API kriegt ich keinen Zugriff. Selenium und BS wird beides blockiert.
    Weist du noch eine Alternative oder hab ich etwas übersehen?

    Viele Grüße
    Dominik

    Antwort

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

*

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.