Erstellen einer Web-Scraping-Pipeline mit AWS-Diensten
Was ist Web Scraping und warum brauchen wir es?
Web Scraping ist eine Technik, mit der die zugrunde liegenden Daten einer Webseite extrahiert werden. Diese Daten bestehen in der Regel aus HTML-, CSS- und JavaScript-Dateien sowie weiteren Ressourcen wie den referenzierten Bildern, Videos und Schriftarten, die ein Browser zum Darstellen der jeweiligen Webseite verwendet. Die gesammelten Daten werden anschließend zur weiteren Verarbeitung in Dateien oder einer Datenbank gespeichert.
Bei TeleportHQ erforschen wir kontinuierlich Möglichkeiten, unsere Fähigkeiten zur Codegenerierung aus Wireframes oder hochauflösenden Designs zu verbessern. Da dabei viel maschinelles Lernen zum Einsatz kommt, benötigen wir große Mengen sorgfältig zusammengestellter Daten. Der RICO-Datensatz war zwar ein guter Ausgangspunkt für native mobile Seiten, doch aus mehreren Gründen hielten wir es für sinnvoll, eigene Webseitendaten zu erstellen:
- Es gibt kaum öffentliche Datensätze, die unseren Qualitätsanforderungen entsprechen.
- Kontrolle über die Daten – wir können genau festlegen, welche Informationen wir von den Websites abrufen möchten.
- Skalierbarkeit – mit fortschreitender Forschung benötigen wir immer mehr Daten.
- Organisation und Zugänglichkeit – wir schaffen einen schnellen und unkomplizierten Zugriff auf die Daten.
Wie funktioniert es?
Das Web Scraping einer Webseite umfasst zwei Schritte: das Abrufen und das Extrahieren der Daten. Beim Abrufen wird eine Webseite heruntergeladen, also der ursprüngliche HTML-Code und alle referenzierten Ressourcen – genau das, was ein Browser beim Aufrufen der Seite tut. Daher ist Web-Crawling ein zentraler Bestandteil des Web Scrapings: Wir rufen Seiten ab, um sie später zu verarbeiten. In unserem Fall verwenden wir dafür Puppeteer, eine Node.js-Bibliothek mit einer High-Level-API zur Steuerung von Chrome oder Chromium. Durch das Starten eines Headless-Chromium-Browsers können wir Webseiten abrufen und die darin enthaltenen Daten auslesen.
Es gibt viele Möglichkeiten, Daten von einer Website zu extrahieren. In unserem Fall verwenden wir eine Technik namens DOM-Parsing. Beim Laden einer Webseite erstellt der Browser ein Document Object Model (DOM) der Seite, das anschließend für die Darstellung auf dem Bildschirm verwendet wird. Das HTML-DOM-Modell wird als Baum aus Objekten aufgebaut, der geparst werden kann, um die erforderlichen Informationen abzurufen.
Für jedes Element im DOM rufen wir eine Liste von Attributen ab, die Informationen zu Größe, Position, Farbe und vielem mehr enthalten.
Erste Probleme
Bei der Arbeit mit dem Websites-Datensatz haben wir festgestellt, dass viele darin enthaltene Websites Probleme verursachten, etwa überlappende Boxen oder 404-Seiten.
Die überlappenden Boxen wurden durch unsichtbare Elemente oder Elemente außerhalb des sichtbaren Bereichs verursacht, die zwar ins DOM geladen, aber erst nach einem bestimmten Ereignis angezeigt werden. Damit wollen wir nicht sagen, dass diese Websites schlecht gestaltet sind. Sie würden jedoch beim Training eines ML-Modells zu Inkonsistenzen führen. Die 404-Seite erschien, weil der Browser zwar mit dem Server kommunizieren konnte, der Server die angeforderte Ressource jedoch nicht finden konnte. Das DOM der 404-Seite wird dennoch geladen und die Seite geparst, aber daraus lassen sich keine nützlichen Informationen extrahieren.
Ein ML-Klassifikator zur Rettung
Die Lösung für diese Probleme war ein ML-Klassifikator, der die Wahrscheinlichkeit angibt, dass eine Website für unsere Zwecke geeignet ist. Zunächst ordneten wir Websites manuell verschiedenen Kategorien zu und beurteilten sie anhand objektiver Kriterien wie: „Überlappen sich die Boxen?“ oder „Enthält die Seite genügend Informationen?“. Um den Prozess zu vereinfachen, entwickelten wir mit R Shiny eine eigene Webanwendung mit einer speziellen Visualisierung, mit der sich die Datenpunkte einzeln annotieren ließen.
Die Annotationen dienten anschließend als Trainingsdaten für unser XGBoost-Modell. Nach dem Testen erzielten wir eine Genauigkeit von 85 %. Für die Bereitstellung nutzten wir SageMaker, hauptsächlich weil die XGBoost-Bibliothek zu groß war, um in einen Lambda-Container aufgenommen zu werden.
Durchschnittliche Wahrscheinlichkeit, dass Websites geeignet sind, in Abhängigkeit von der Anzahl der Elemente im DOM
Wahrscheinlichkeiten für 200.000 Websites
Skalierung
Die erste Version des Web-Scrapers war eine Node.js-Anwendung, die asynchrone Aufrufe nutzte, um den Parsing-Prozess zu parallelisieren. Das war ein guter Anfang und ermöglichte es uns, schnell unsere ersten Websites zu parsen. Als wir jedoch versuchten, die Arbeit zu parallelisieren, stießen wir schnell an die Hardwaregrenzen unseres lokalen Computers. Der Arbeitsspeicher war rasch erschöpft und die CPU konnte die Last nicht bewältigen. Um die Rechenleistung zu erhöhen, entschieden wir uns, den Parser auf eine m4.4xlarge-EC2-Instanz bei AWS zu verlagern, die über 16 vCPUs und 64 GB RAM verfügte. Dies geschah ausschließlich, um die Parsing-Geschwindigkeit zu erhöhen.
Der größte Nachteil dieses Ansatzes war, dass alles manuell erledigt werden musste: die Eingabe der Websites, das Feature Engineering, die ML-Inferenz, der Upload zu S3 nach Abschluss all dieser Schritte und vieles mehr. Eine Lösung für dieses Problem bestand darin, eine Pipeline zu erstellen, die all diese Aufgaben automatisch erledigt und sie so organisiert, dass sie leichter zugänglich sind. Außerdem unterstützen AWS Lambda-Funktionen eine große Anzahl gleichzeitiger Ausführungen, sodass wir mehr Websites pro Minute parsen können.
Pipeline-Struktur
Die Pipeline besteht aus zwei Arten von Elementen: Prozessoren und Speicher. Bei den Prozessoren handelt es sich um Lambda-Funktionen, die durch bestimmte Ereignisse ausgelöst werden. Als Speicher dienen uns die NoSQL-Datenbank DynamoDB und ein S3-Bucket. DynamoDB enthält allgemeine Informationen zu den Websites, etwa die Domain, die Seite oder den Zeitpunkt, zu dem die Website geparst wurde. Der S3-Bucket ist in drei Ordner unterteilt:
- Multi-site-CSV – enthält CSV-Dateien mit mehreren zu parsenden Websites
- Meta – enthält Informationen zu einer Website, die für das Parsing benötigt werden
- Data – enthält die Ausgabe des Parsers: einen Screenshot und eine JSON-Datei mit allen aus dem DOM extrahierten Informationen
Ausgangspunkt
Um den Prozess zu starten, müssen wir eine oder mehrere Websites eingeben. Dafür gibt es zwei Möglichkeiten. Zum einen können wir einen Endpunkt mit der URL als Anfrageparameter aufrufen. Dadurch wird nur die angegebene Website geparst, und als Antwort erhalten wir ihren Namen in S3. Zum anderen können wir eine CSV-Datei mit allen zu parsenden Websites in den Ordner „multi-site-CSV“ hochladen.
Lambda-Trigger
In der Pipeline sorgen drei Lambda-Funktionen für den nötigen Antrieb.
Die erste Lambda-Funktion ist „CSV-split“. Sie wird jedes Mal ausgelöst, wenn eine CSV-Datei in den Ordner „multi-site-CSV“ hochgeladen wird. Sie teilt die große CSV-Datei in kleinere CSV-Dateien auf, die jeweils Informationen zu einer Website enthalten, und lädt diese in den Ordner „meta“ in S3 hoch.
Die zweite Lambda-Funktion, „parse-added“, ist das Herzstück der Pipeline. Sie enthält den Parser und beansprucht die meisten Ressourcen. Sie wird bei jedem Upload einer neuen CSV-Datei in den Ordner „meta“ ausgelöst und analysiert die entsprechende Website. Bei erfolgreicher Analyse liefert sie einen Screenshot, eine JSON-Datei und eine Liste interner Links zurück, die später in der Pipeline für die rekursive Analyse verwendet werden. Anschließend aktualisiert sie den Datenbankeintrag für die entsprechende Website und lädt die beiden Dateien in den Ordner „data“ im S3-Bucket hoch. Schlägt die Analyse fehl, werden die S3- und Datenbankeinträge gelöscht, um Inkonsistenzen zu vermeiden.
Die dritte und letzte Lambda-Funktion übernimmt den ML-Teil der Pipeline. Sie wird bei jedem Upload einer JSON-Datei in den Ordner „data“ ausgelöst und nutzt die darin enthaltenen Daten für das Feature Engineering. Anschließend sendet sie eine Anfrage mit den Merkmalen an den SageMaker-Endpunkt, der die Wahrscheinlichkeit zurückgibt, dass die Website gut ist. Ist diese Wahrscheinlichkeit hoch genug, lädt die Funktion eine CSV-Datei mit allen internen Links der entsprechenden Website in den Ordner „multi-site-CSV“ hoch. Dadurch wird die erste Lambda-Funktion ausgelöst und eine Schleife entsteht.
Ergebnisse
Leistung
Die Leistung hat sich im Laufe der Entwicklung erheblich verbessert. Die Node.js-Anwendung erreichte eine durchschnittliche Analysegeschwindigkeit von 20 Websites pro Minute. Nach dem Wechsel zu EC2 und weiteren Optimierungen konnten wir die Geschwindigkeit auf 240 Websites pro Minute steigern. Das ist jedoch nichts im Vergleich zu den 4.500 Websites pro Minute, die wir mit AWS Lambda erreicht haben.
Was können wir mit den Daten anfangen?
Einer der Ansätze, die wir verfolgen, ist die Objekterkennung auf Website-Screenshots. Die Informationen, die wir aus den Websites extrahiert haben, lieferten uns alles, was wir für den Einstieg benötigten.
Links – Vorhersage / Rechts – Ground Truth
Unser Ziel ist es, die Elemente einer Webseite möglichst präzise zu erkennen. Anhand der Koordinaten jedes Elements (oben, links, Breite und Höhe) berechnen wir die entsprechenden Begrenzungsrahmen und trainieren damit anschließend das ML-Modell. Die aus dem DOM extrahierten Daten waren im obigen Beispiel inkonsistent. Dadurch wurden unsichtbare Elemente angezeigt oder Elemente nicht erkannt. Da wir für das Training hochwertige Webseiten verwendet haben, konnte das Modell sogar die Position dieser Elemente erschließen (des Absatzes mit dem Hintergrundbild im oberen Seitenbereich) und die unsichtbaren Elemente ignorieren (die Elemente auf der linken Seite).
Zunächst haben wir jedes Element entweder als Text oder als Bild kategorisiert. Mit fortschreitender Entwicklung werden wir jedoch weitere HTML-Tags wie Tabellen, Listen und Eingabefelder berücksichtigen.
Fazit
Es gibt nur sehr wenige öffentlich verfügbare und sorgfältig zusammengestellte Web-Datensätze, und die wenigen verfügbaren enthalten nur eine begrenzte Anzahl von Datenpunkten. Diese Vorarbeit hat uns unabhängig gemacht und ermöglicht es uns, Qualität und Umfang unserer Daten präzise zu kontrollieren. Ein weiterer wichtiger Vorteil ist, dass wir damit innerhalb weniger Stunden dynamisch neue, aktualisierte und verbesserte Datensätze erstellen können. Wenn Sie als Forschende oder Forschender Zugang zu unseren Daten erhalten möchten, schreiben Sie uns gerne.
Beim Aufbau haben wir auch viel über unsere Branche und die zugrunde liegenden Technologien gelernt. Dieses Wissen hat uns ein besseres Verständnis dafür vermittelt, worauf wir unsere Forschung zur Automatisierung der Erstellung von Benutzeroberflächen ausrichten sollten.
Wie immer sind wir sehr daran interessiert, uns mit anderen Interessierten über dieses Thema auszutauschen. Wenn Sie sich für unsere Arbeit interessieren, kontaktieren Sie uns gerne über einen unserer Social-Media-Kanäle, die Sie in der Fußzeile dieser Website finden.
Kommentare
Noch keine Kommentare. Teilen Sie als Erste Ihre Gedanken mit.