Datenbeschaffung - MrJaimba/Projektseminar Wiki

Ansprechpartner
Lennart Müller

Um ein erfolgreiches Training der Machine Learning Modelle zu gewährleisten musste die Beschaffung einer soliden Datenbasis erfolgen. Wie bereits zum Anfang des Wikis erwähnt war das Sample, welches durch das Partnerunternehmen zur Verfügung gestellt wurde ungeeignet. Daher musste das Team selbst für eine Datengrundlage sorgen. Eine verfügbare Quelle von Immobiliendaten mit zugehörigem Angebotspreis waren Immobilienportale. Somit entschied das Projektteam sich über Web-Scraping der renommierten deutschen Immobilienportale "immonet.de" und "immobilienscout24.de" die Inputdaten zu beschaffen. Die ursprünglich geplante Eingrenzung auf den Großraum Würzburg wurde aufgrund der wenigen Treffer nach den ersten Durchläufen schließlich auf ganz Bayern ausgeweitet!

Immonet-Scraper

Der größere Teil der Datenbasis wurde durch einen Scraper generiert, welchen das Team für das Portal "immonet.de" geschrieben hat. Ziel ist es hier Informationen aller zum Verkauf stehender bayrischer Immobilien zu scrapen. Wie im gesamten Projekt erfolgte die Umsetzung in Python. Das Programm baut auf den Libraries requests und BeautifulSoup auf. Im folgenden Teil wird die Funktionsweise erklärt. Zum besseren Verständnis wird dabei zwischendurch immer wieder auf den Code Bezug genommen. Der Gesamtcode kann in der Datei webscraper.py eingesehen werden.

Objekte erstellen

Ein Teil des Scrapers ist die Klasse ScrapedRealEstate. Diese bündelt alle Attribute einer Immobilie, die der Scraper erfassen soll. Innerhalb der Klasse wird daher ein Konstruktor definiert, dem alle Attribute übergeben werden. Die Gesamtheit der Variablen eines Immobilienobjektes wird somit in der Klasse abgespeichert. Dies erlaubt später im Scraper Objekte zu erstellen, in welchen die einzelnen Attribute gebündelt vorliegen.

Daten extrahieren

Das eigentliche Scraping findet in einer weiteren Klasse ImmoFetcher statt. Diese beinhaltet die fetch Funktion, welche den Prozess der Datenextraktion definiert.

Innerhalb der Funktion wird zunächst eine Variable url erzeugt. Diese wird gleich der URL der ersten Ergebnisseite von Immonet gesetzt, nachdem man die Suche im Portal mit den o. g. Parametern (Alle Objekte, welche in Bayern zum Verkauf stehen) durchgeführt hat. Es wird zudem eine leere Liste immo_list erzeugt, in die während des Durchlaufes alle Ergebnisse eingetragen werden sollen.

Das Scraping jeder einzelnen Ergebnisseite findet in einer while-Schleife statt. Diese wird ausgeführt, solange der Parameter url nicht leer ist, d.h. solange noch nicht alle Seiten abgearbeitet sind. In dieser Schleife fragt man zunächst über eine requests-Abfrage den Quellcode der festgelegten URL an. Der html-Code, der als Antwort zurückgegeben wird soll anschließend in Textform mit BeautifulSoup und dem html.parser eingelesen werden.

Alle Immobilien einer Ergebnisseite sind in Kacheln angeordnet, deren Quellcode analog gestaltet ist. Somit wird im nächsten Schritt der html-Code aller dieser Kacheln in der Variable containers gespeichert. Die folgende Grafik zeigt die eigene Darstellung des Schemas einer solchen Immobilien-Kachel (s. Immonet.de).

Jede Immobilie besitzt eine eigene URL auf deren Webpage sich die spezifischen Informationen zum betreffenden Objekt befinden. Somit wird eine innere for-Schleife für alle extrahierten Immobilien-Kacheln festgelegt. Zunächst wird der Teil-Link zur betreffenden Immobilienseite aus dem Quellcode des Containers herausgezogen und anschließend mit einem urljoin zur vollwertigen Webadresse der Immobilienseite formiert. Um nun die gewünschten Daten erfassen zu können wird für jedes Objekt eine erneute Anfrage, analog zu jener der Ergebnisseite durchgeführt. Somit liegt an dieser Stelle nun der html-Code der Immobilienseite vor, welcher jene tiefgreifenden Informationen enthält, die das Projektteam beschaffen will.

An dieser Stelle gibt es nun diverse Möglichkeiten wie die verschiedenen Parameter in die Website und somit in den html-Code eingebettet sind.

Die einfachste Variante liegt vor wenn für ein Attribut eine charakteristische ID vorliegt. Ein Beispiel hierfür ist der Angebotspreis. Hierbei wird aus dem Quellcode der Immobilienseite das div-Element mit der ID priceid_1 angesteuert. In der folgenden if-Schleife werden überschüssiger Code entfernt, diverse Anpassungen vorgenommen und die Ausgabe bei einem Default-Wert, mit entsprechendem Datentyp festgelegt.

Schwieriger gestaltet sich dies beispielweise bei der Beschaffung der Postleitzahl. Da keine ID vorliegt muss das p-Element mit der gesamten zugehörigen Klasse angesteuert werden. Da sich in dieser diverse Informationen befinden wird in diesem Fall die Postleitzahl über einen regular expression, welcher nach einer zusammenhängenden 5-stelligen Zahl sucht identifiziert.

In einigen Fällen befinden sich Informationen auch in den Beschreibungstexten auf den einzelnen Immobilienseiten. Im Bespiel der Variable Aufzug wurden die Beschreibungen mit Text Mining nach Permutationen des Wortes "Aufzug" untersucht, sodass die Verfügbarkeit eines Fahrstuhls bestimmt werden konnte.

Nachdem alle Parameter extrahiert wurden wird in der Variable scraped ein neues Immobilienobjekt erzeugt welches dann zu immo_list hinzugefügt wird. Das beschriebe Prozedere erfolgt nun für alle Immobilien auf der ersten Übersichtsseite.

Da in den meisten Fällen mehrere Ergebnisseiten auf diese Weise durchsucht werden wird im letzten Schritt der Funktion der Teil-Link zur nächsten Seite aus dem html-Code des zugehörigen Buttons extrahiert. Mit urljoin wird die Webadresse der nächsten Übersichtsseite bestimmt und gleich der Variable url gesetzt. Die while-Schleife beginnt von neuem und durchsucht so systematisch alle Seiten. Ist die letzte Ergebnisseite erreicht wird url gleich "leer" gesetzt und der Durchlauf ist beendet, da das Kriterium zum stoppen der while-Schleife erreicht ist.

Daten speichern

Da es das Primärziel war ein funktionstüchtiges Tool zu erstellen, einigte sich das Projektteam darauf zunächst eine Datenbasis für spätere Machine-Learning Tests anzulegen. Hierzu wurde bestimmt, dass die gescrapten Daten zunächst in einer CSV-Datei gespeichert werden. Dafür wurde bereits zum Anfang das CSV-Modul importiert.

Als Ausgangspunkt wird dabei zunächst in der Variable fetcher ein neuer ImmoFetcher erzeugt. Anschließend wird eine CSV-Datei benannt, zum Schreiben geöffnet und die Festlegung gewisser Einstellungen erfolgt. Es folgt die Bestimmung der ersten Zeile indem die Überschriften der einzelnen Spalten definiert werden. In der darauf folgenden for-Schleife wird festgelegt, dass nach Aufruf der fetch-Methode für jedes Objekt eine Zeile erzeugt wird. Sobald die Methode abgeschlossen ist wird auch die CSV-Datei geschlossen.

Über die Zeitspanne der Datenbeschaffung wurde der Immonet-Scraper immer wieder ausgeführt. Duplikate wurden entfernt und die neuen Zeilen zur Datei hinzugefügt. Der vollständige Immonet-Datensatz umfasste schließlich rund 13.700 Beobachtungen und kann hier eingesehen werden.

Immoscout Scraper

Ansprechpartnerin
Yanina Budnik

Immoscout schützt seine Daten vor Bots und Web Scraping indem Captcha eingesetzt wird, der Einsatz führt zum Abbruch des Scraping-Vorgangs, so dass keine Immobiliendaten extrahiert werden können:

Mehrere Versuche unsererseits diesen Schutz zu umgehen waren nicht erfolgreich, so dass das Projektteam gezwungen war auf eine Fertiglösung auszuweichen.

webscraper.io

Web Scraper ist ein Add-On für den Webbrowser Chrome, damit lassen sich öffentlich zugängliche Daten extrahieren und in eine CSV Datei speichern. Dafür muss im ersten Schritt eine Sitemap angelegt werden, in dieser wird die Start-URL festgelegt. Für den Immobiliendatensatz im Rahmen des Projekts sind es:

Startet man die Immobiliensuche direkt über die Immoscout24 Seite, so fehlt der Linkteil &pagenumber=[1-200]. Dieser wird zum Scrapen benötigt, da sonst lediglich der Inhalt der ersten Seite des Suchergebnisses auf Immoscout24 gelesen wird. Im zweiten Schritt werden die Selektoren festgelegt. Um auf die einzelnen Wohnungen bzw. Häuser zugreifen zu können wird zuerst der Linkselektor festgelegt:

Anschließend werden die jeweiligen Eigenschaften der einzelnen Immobilien durch Textselektoren abgefragt:

Der obige Screenshot zeigt einen Ausschnitt der extrahierten Immobilienattribute, der vollständige Immobilienscout24-Datensatz in roher Form kann hier für Häuser und hier für Wohnungen eingesehen werden.

webscraper.io und CAPTCHA Abfrage

Auch durch die Verwendung dieser Lösung konnte die CAPTCHA Abfrage durch Immobilienscout24 nicht umgangen werden, diese erschien in regelmäßigen Abständen von etwa 10-20 Seiten. Wurde die Abfrage nicht in einer angemessenen Zeit gelöst, führte dies zu Abbruch des Scraping-Vorgangs. Dieses Problem ließ sich durch zwei Ansätze lösen, die jedoch mit manuellen Eingriffen und damit einem zeitlichen Mehraufwand bei der Datenbeschaffung von Immobilienscout24 verbunden waren.

Der erste Ansatz bestand in der Vergrößerung des Anfrageintervalls des Scrapers. Da das Add-On über eine graphische Fläche verfügt und damit jederzeit ersichtlich ist auf welcher Seite der Scraper sich befindet, konnte die CAPTCHA Anfrage bei einer entsprechend hohen Einstellung des Anfrageintervalls manuell gelöst werden. Dies würde jedoch bedeuten, dass der gesamte Scraping-Vorgang für einen kompletten Durchlauf einer permanenten Überwachung bedarf. Der zweite Ansatz bestand darin den Scraper bis zum Abbruch durchlaufen zu lassen, dabei konnte festgestellt werden auf welcher Seite sich der Scraper als Letztes vor dem Abbruch befand. Danach musste ein neuer Scraping-Vorgang gestartet werden, der auf der Seite begonnen hat, auf der der vorherige Durchgang abgebrochen wurde. Dies wurde so lang wiederholt bis der Scraper am Ende der Ergebnisliste angelangt ist. Anschließend wurden alle Teillisten in einer Gesamtliste zusammengeführt, eventuelle Duplikate ließen sich durch die eindeutige ScoutID gut identifizieren und entfernen.

Limitationen und Probleme bei der Datenbeschaffung

Auch wenn durch das Scrapen von den beiden bekanntesten Immobilienportalen eine ausreichende Datenbasis geschaffen werden konnte, konnten folgende Probleme und Limitationen identifiziert werden:

Datensatz der VR-Immo

Seitens VR-Immo wird dem Projektteam ein Datensatz zur Verfügung gestellt, dieser enthält 322 Einträge. Bei 23 Immobilieneinträgen fehlt der Kaufpreis. Ebenso fehlen bei einigen Dateneinträgen essentielle Angaben wie Wohnfläche oder Zimmeranzahl, 164 Einträge sind ohne Angabe des Baujahres. Zudem wiederholen sich viele Einträge, da sich die Wohneinheiten im gleichen Haus befinden. So finden sich im Datensatz 118 Immobilien aus Würzburg, von diesen befinden sich 63 im Unteren Katzenbergweg. Aufgrund der Anzahl der verwendbaren Einträge hat sich das Projektteam für den Aufbau einer eigenen Datenbasis entschieden.

Angebotspreise vs. Verkaufspreise

Preisdaten, die sich aus den öffentlichen Immobilienportalen entnehmen lassen und die Basis für unsere Bewertung bilden, entsprechen Angebotspreisen, also den Preisen die die Anbieter gerne erzielen würden, unabhängig von deren Durchsetzbarkeit. Angebotspreise sind jedoch von den finalen Verkaufspreisen zu unterscheiden. Sicherlich werden die Angebotspreise nicht bei jedem Verkaufsvorgang vollständig erreicht, auch sind die Verkaufspreise u.a. von der individuellen Verhandlungsmacht des Käufers abhängig. So ließen sich z. B. auch in unseren Datensätzen vereinzelte Einträge finden, die identische Immobilien zu unterschiedlichen Angebotspreisen enthielten, da die Verkäufer den Preis korrigieren mussten (diese wurden in den weiteren Schritten der Datenbereinigung entfernt).

Dem Projektteam ist jedoch keine Quelle bekannt, die öffentlich zugänglich und bayernweit, sowohl die Verkaufspreise als auch die Immobilieneigenschaften im gleichen Umfang dokumentiert wie die erwähnten Immobilienportale. Zudem können keine Annahmen über die Verkaufspreise getroffen werden.

PLZ als kleinste geografische Ebene

Im Rahmen dieses Projekts wird die PLZ als eines der Features verwendet. Dies ist, zusammen mit den Koordinaten, das einzige Feature was die geographische Lage einer Immobilie in unserem Datensatz beschreibt. Bei diesem Ansatz tritt das Problem auf, dass die Genauigkeit der Preisschätzung leidet, da einige PLZ-Gebiete über eine große Fläche verfügen. Diese Weiträumigkeit führt dazu, dass manche Unterschiede in der Lage der Immobilien, die sich auf den Preis auswirken, nicht immer erfasst werden können, wie beispielsweise die Entfernung zu einer vielbefahrenen Straße oder zu den Bahngleisen. Auf die sich in unmittelbarer Nähe befindenden Immobilien würde eine laute Straße einen höheren negativen Einfluss haben, als auf weiter entfernte Immobilien im gleichen PLZ Gebiet. Ebenso lassen sich solche Faktoren wie Unterschiede in den Baulandkosten nicht genau abbilden.

Da die Daten, die über Immobilienportale veröffentlicht werden für Jedermann einsehbar sind, verzichten viele Immobilienanbieter aus Diskretionsgründen auf die vollständige Angabe der Adressdaten. Zwar sind der Straßenname und die Hausnummer sowohl bei Immobilienscout24, als auch bei Immonet, Pflichtangaben, jedoch müssen sie in der endgültigen Anzeige nicht sichtbar sein. So enthalten weniger als 20% der Einträge, die von Immobilienscout24 stammen, die Adressinformationen, unter diesen finden sich zahlreiche Einträge, die keine Hausnummer enthalten. Da die Straßenangaben zudem nicht verifiziert werden, lassen sich in den Anzeigen Adressenangaben wie "A3" oder "in der Nähe von ..." finden, die für eine geografische Zuordnung auf dieser Ebene unbrauchbar sind. Anders verhält es sich mit der Angabe der Postleitzahl, diese wird auf ihre Gültigkeit geprüft, so dass die Angabe einer unbekannten PLZ nicht funktioniert. Im Zeitrahmen des Projekts sah das Projektteam aus diesen Gründen keine Möglichkeit eine solide, straßenbezogene Datenbasis aufzubauen, weder auf lokaler, noch auf bayernweiter Ebene.

Datenqualität

Wie bei der Adresseingabe, gilt das Problem der fehlenden Validierung auch für die anderen Immobilieneigenschaften. Solche Eigenschaften wie Immobilien- oder Heizungsart, Vorhandensein eines Balkons oder Terrasse etc. müssen über Dropdown Menüs angewählt werden, von diesen Menüs gibt es einige. Makler inserieren meistens jedoch nicht nur auf einem Immobilienportal, sondern auf mehreren, zudem wird je nach Beliebtheit eines Maklers nicht nur eine Immobilie online gestellt. Unterschiedliche Immobilienportale haben unterschiedliche Formate, auf allen ist jedoch ein Freitextfeld für die Objektbeschreibung vorhanden. Es kann nicht ausgeschlossen werden, dass die Makler um Zeit zu sparen eher dieses Freifeldtext nutzen, statt jede Kategorie einzeln anzuklicken. Werden diese Kategorien aber nicht ausgefüllt, so werden die Eigenschaften auch nicht mitgescrapet. Füllt ein Makler z.B. das Feld für Terrasse nicht aus, sondern schreibt lediglich im Freitext, dass es eine gibt, so bleibt dieses Feld beim Scrapen leer und ergibt einen NaN Wert. Für NaN Werte bei Balkon oder Terrasse wird in unserem Datenbestand davon ausgegangen, dass es keine Terrasse oder Balkon gibt, was dann nicht der Realität entspricht und damit letztendlich auch den Angebotspreis verzerrt. Auch Angaben wie Wohn- oder Grundstücksfläche sind schwierig zu validieren. So war in unserem Datenbestand eine Immobilie zu finden deren Wohnfläche mit 51.000 Quadratmetern angegeben war, es ist zweifelhaft ob sie tatsächlich so stimmt. Ein Eintrag dieser Art hat jedoch ausgereicht, um den Korrelationswert zwischen dem Angebotspreis und der Wohnfläche gegen 0 gehen zu lassen, wurde der Eintrag entfernt betrug der Wert etwa 0,5. Die Angaben auf ihre Wahrheitstreue zu überprüfen ist schwierig, dafür müsste den Freitext von jeder Immobilie durchgegangen werden oder auch die Bilder mit den Dateneinträgen verglichen werden. Dies ist jedoch für mehrere 1.000 Einträge nicht durchführbar.