Zum Inhalt springen

Wir bauen einen Datenstaubsauger: Web Scraping mit ChatGPT

Daten aus öffentlich zugänglichen Datenbanken zu extrahieren und für eigene Zwecke zu nutzen, kann sehr aufwändig sein. Bis vor kurzem musste man dazu noch einen Riesenaufwand betreiben und die dafür nötigen Skripte selbst schreiben. Mit ChatGPT ist das alles wesentlich leichter geworden. In diesem Artikel zeige ich dir, wie du mithilfe von Google Tabellen und ChatGPT Daten aus öffentlichen Quellen extrahierst, aufbereitest und automatisiert täglich aktualisierst, um sie anschließend mit Datawrapper zu visualisieren. Dafür musst du weder programmieren können noch musst du Geld ausgeben. Das Ergebnis kannst du unten auf der Seite sehen.

Web-what? Web Scraping? Kennst du nicht? Erklär ich dir.

Web Scraping ist eine Methode, mit der du automatisch Informationen von Webseiten sammelst. Stell dir vor, du möchtest auf öffentlich zugänglichen Webseiten Daten beziehen, zum Beispiel aktuelle Pegelstände von Flüssen. Anstatt die Seite immer wieder selbst aufzusuchen und die dir wichtigen Daten rauszufiltern, kann Web Scraping diese Arbeit für dich übernehmen. Es ist wie ein fleißiger Assistent, der die Webseiten durchsucht, die relevanten Informationen herauszieht und sie für dich in eine übersichtliche Form bringt. So sparst du eine Menge Zeit und Mühe!

Beim Web Scraping bereinigst Du die Daten auf die dir wichtigen Werte

Es gibt da, grob gesagt, zwei mögliche Abfragen: REST-API-Abfragen beziehen ihre Daten häufig aus Datenbanken. Das ist relativ einfach umzusetzen, weshalb ich damit beginne.

Echtes Web-Scraping meint hingegen eine Technik, mit der Daten von Webseiten automatisch extrahiert werden. Dabei wird der HTML-Code der Webseiten analysiert, um spezifische Informationen zu sammeln und weiterzuverarbeiten. Auch dafür kannst du dir von ChatGPT ein Script schreiben lassen. Ein Muster dafür findest du am Ende dieses Artikels.

Ist das alles rechtens?

Beim Web Scraping musst du einige rechtliche Aspekte beachten. Nicht alle Webseiten erlauben das automatische Extrahieren von Daten. Überprüfe immer die Nutzungsbedingungen der Webseite, bevor du mit dem Scraping beginnst. In manchen Fällen benötigst du eine ausdrückliche Erlaubnis des Webseitenbetreibers.

Mir ist es wichtig, verantwortungsvoll mit den Daten umzugehen. Lies dir also immer die Nutzungsbedingungen der jeweiligen Seiten durch. Für das verwendete Beispiel der REST-API-Abfrage findest du sie auf dieser Seite. Für das Beispiel des echten Webscrapings habe ich selbst eine Seite erstellt, die du gerne als Musterseite verwenden darfst.

Von der Idee zur Umsetzung: Lassen wir ChatGPT ein Skript schreiben

Datenvisualisierung ist mein Hobby. Und auch mein Beruf. Die Idee für das hier genutzte Beispiel kam aus einem Seminar für die Akademie für Publizistik, in dem mich eine Teilnehmerin fragte, ob wir nicht ein Script schreiben könnten, dass die Pegelstände automatisch abfragt und diese für Datawrapper zur Verfügung stellt. Nun kann ich ein wenig programmieren. Aber bei weitem nicht so gut, dass ich mir das zugetraut hätte. Immerhin reichen meine Kenntnisse so weit, dass ich Maschinen Anweisungen geben kann und das Ergebnis halbwegs verstehe. Warum also nicht mit ChatGPT arbeiten. So kam ich recht schnell zum Ziel und das Ergebnis kann sich mMn sehen lassen. Doch fangen wir vorne an.

Schritt 1: ChatGPT ein Skript erstellen lassen, das die Daten filtert.

Ich brauche eine Ursprungsdatei. In meinem Fall ist das eine sich täglich selbst aktualisierede Datei der Wasserstraßen- und Schiffahrtsverwaltung des Bundes, die du hier findest.

Ein Koch am Herd, der aus einem Topf (dem Computer) Daten in Form von Nullen und Einsen schöpft und sie durch ein Sieb filtert, wobei die nützlichen Daten als schöne, glänzende Perlen herauskommen und die unbrauchbaren als Schmutz zurückbleiben.
Aus vielen kruden Zutaten kannst du dir ein tolles Rezept erstellen

Die Tabelle sieht erstmal ziemlich krude aus. Sie ist maschinell erstellt und man muss sich etwas einarbeiten, um zu verstehen, was für das eigene Projekt von Relevanz ist. Ich brauche daraus die Werte für Pegelname („0:longname“), Längengrad („0:longitude“, Breitengrad („0:latitude“), Gewässer („water:longname“)Wasserstand („currentMeasurement:stateMnwMhw“) und Datum der Messung („currentMeasurement:timestamp“) (aktueller Wert („0:CurrentMeasurement“). Also habe ich Chatgpt mit Verweis auf den Link zur oben verlinkten Datei gebeten, mir ein Script für Google Tabellen zu erstellen. Das Ergebnis sieht so aus:

function fetchAndWriteData() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var url = 'https://www.pegelonline.wsv.de/webservices/rest-api/v2/stations.json?includeTimeseries=true&includeCurrentMeasurement=true';
  var response = UrlFetchApp.fetch(url);
  var data = JSON.parse(response.getContentText());
  
  // Clear existing content
  sheet.clear();

  // Write headers
  var headers = ["Pegelname", "Längengrad", "Breitengrad", "Gewässer", "Wasserstand", "Datum der Messung"];
  sheet.appendRow(headers);
  
  // Extract and write data
  data.forEach(function(station) {
    if (station.timeseries && station.timeseries.length > 0) {
      var currentMeasurement = station.timeseries[0].currentMeasurement;
      if (currentMeasurement) {
        var row = [
          toProperCase(station.longname || ''),
          station.longitude || '',
          station.latitude || '',
          toProperCase(station.water.longname || ''),
          formatWaterLevel(currentMeasurement.stateMnwMhw || ''),
          formatGermanDate(currentMeasurement.timestamp) || ''
        ];
        sheet.appendRow(row);
      }
    }
  });
}

function formatGermanDate(dateString) {
  var date = new Date(dateString);
  var day = ('0' + date.getDate()).slice(-2);
  var month = ('0' + (date.getMonth() + 1)).slice(-2);
  var year = date.getFullYear();
  return day + '.' + month + '.' + year;
}

function toProperCase(text) {
  return text.toLowerCase().replace(/(^|\s)\S/g, function(t) { return t.toUpperCase() });
}

function formatWaterLevel(state) {
  if (!state || state === 'unknown' || state === 'commented' || state === 'out-dated') {
    return 'veraltet oder unbekannt';
  }
  return state;
}

function createTimeDrivenTrigger() {
  // Delete all existing triggers to avoid duplicates
  ScriptApp.getProjectTriggers().forEach(function(trigger) {
    ScriptApp.deleteTrigger(trigger);
  });
  
  // Create a new time-driven trigger to run daily
  ScriptApp.newTrigger('fetchAndWriteData')
    .timeBased()
    .everyDays(1)
    .atHour(1) // Change the hour as needed
    .create();
}

function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Custom Scripts')
      .addItem('Fetch and Write Data', 'fetchAndWriteData')
      .addItem('Create Daily Trigger', 'createTimeDrivenTrigger')
      .addToUi();
}

Das hätte ich, ehrlich gesagt, nicht so schnell hinbekommen.

Schritt 2: Einrichtung der Google Tabelle

Nun erstellst du eine neue Google Tabelle, in der die Daten gespeichert werden sollen. Öffne Google Sheets und erstelle ein neues Dokument. Gib der Tabelle einen aussagekräftigen Namen, z.B. „Pegelstände“. Ändere die Freigabe in „Jeder, der über den Link verfügt“

Schritt 3: Einbindung des von ChatGPT erstellten Skripts zur Datenbereinigung

Um nun die Daten aus einer öffentlichen Datenbank zu extrahieren, nutzen wir das von Datawrapper erstellte Skript. Es holt sich in meinem Beispiel die Daten aus der Pegel-Online-Datei und schreibt sie in die Google Tabelle. Um es einzurichten, gehst du wie folgt vor:

  1. Öffne das Skript-Editor-Fenster über Erweiterungen > Apps Script.
  2. Ersetze den vorhandenen Code durch das Skript oben.
  3. Speichere das Skript (über das Disketten-Symbol oben
  4. Starte das Skript anschließend per Klick auf „Ausführen“ (oben neben dem Disketten-Symbol)

Schritt 4: Automatisierung der täglichen Aktualisierung

Damit die Tabelle sich täglich automatisch aktualisiert, richten wir eine tägliche Abfrageroutine ein. Dazu klickst du im Apps-Script Fenster in der linken Spalte auf das Uhrensymbol und im sich dann öffnenden Fenster auf Trigger hinzufügen. Es öffnet sich ein weiteres Fenster, bei dem du unter dem Text „Terminquelle auswählen“ den Wert in „Zeigesteuert“ änderst un die häufigkeit der Abfrage festlegst.

Schritt 5: Visualisierung der Daten mit Datawrapper

Nachdem die Daten erfolgreich in die Google Tabelle extrahiert und aktualisiert wurden, ist der nächste Schritt die Visualisierung dieser Daten mit Datawrapper. Dazu gehst du wie folgt vor

  1. Gehe zum Datawrapper
  2. Erstelle eine neue Symbolkarte
  3. Wähle eine Hintergrundkarte (in meinem Fall Deutschland Landkreise 2016)
  4. Nun folgt unter „Füge Daten hinzu“ der spannendste Punkt. Wähle hier nicht „mit Google-Sheet verbinden“, sondern „Externe Daten verlinken“ und setzte den Link zu deiner Google-Tabelle in das Feld unter „Gib den Link zu einer CSV-Datei ein:“. Klicke anschließend auf verbinden und passe deine Visualisierung im Datawrapper weiter an. Anschließend kannst du dir das Ergebnis als png-Datei herunterladen oder als sich täglich aktualisierende Grafik in deine Webseite einbetten.
Auch wenn es nahe liegt: Nutze nicht die Funktion „Mit Google-Sheet verbinden, sondern „Externe Daten verlinken“, um deine Tabelle an den Datawrapper zu übertragen

Schritt 6: Das Ergebnis einbetten

Nachdem du die Visualisierung veröffentlicht hast, erstellt dir Datawrapper einen Einbettungscode. Diesen fügst Du in einen HTML-Block Deiner Seite ein. Das Ergebnis sieht dann so aus:

Von der Datenbankabfrage zum Webscraping mit ChatGPT

Das ist jedoch nur der erste Schritt. Genau gesagt, ist das, was ich bis jetzt gemacht habe, nur eine REST-API-Abfrage, worauf ja auch diverse Kommentatoren hingewiesen haben. Echtes Webscraping bezeichnet dagegen das automatisierte Extrahieren von Daten aus Webseiten durch Analyse des HTML-Codes. Aber auch das sollte möglich sein. Da sich das ganze rechtlich in einer Grauzone befindet, werde ich mit Daten auf meiner eigenen Seite arbeiten. Nehmen wir an, ich betriebe ein Immobilienprotal, auf dem Häuser zum Kauf angeboten werden. Dazu habe ich eine Mustertabelle erstellt, die du auf dieser Seite findest. Diesen habe ich bewusst einfach gehalten, denn es ist etwas Handarbeit nötig. Zunächst solltest Du dir den HTML-Quellcode der Seite anschauen. Du wirst feststellen, dass jeder Eintrag glich aufgebaut ist:

<div class="house-title">
            Haus am See
        </div>
        <div class="house-description">
            <span class="house-location">Berlin</span>
            <span class="house-size">150 m²</span>
            <span class="house-build">1990</span>
        </div>
        <div class="sales-price">
            € <span class="house-price">450.000,—</span>
        </div>

Diese Daten kann ich nun automatisiert auslesen und in eine Google Tabelle schreiben lassen. Dafür habe ich CHatGPT gebeten, mir ein Script für Google Tabellen zu schreiben. Prombt dafür war:

Schreibe mir ein Script für Google Tabellen, dass aus dem Quellcode der Seite https://matthias-suessen.de/2024/06/html-mustercode/ aus der Tabelle die Werte für house-title, house-description, house-location, house-size, house-build und house-price herausfiltert und in eine Google-Tabelle schreibt.

Kurz darauf spuckte mir ChatGPT diesen Code aus:

function extractHouseDataWithoutCheerio() {
  const url = 'https://matthias-suessen.de/2024/06/html-mustercode/';
  const response = UrlFetchApp.fetch(url);
  const html = response.getContentText();
  
  // Use regular expressions to find all house entries
  const houseEntries = html.match(/<div class="house-entry">([\s\S]*?)<\/div>/g);
  
  if (!houseEntries) {
    Logger.log('No house entries found.');
    return;
  }
  
  const data = [['Title', 'Location', 'Size', 'Build Year', 'Price']];
  
  houseEntries.forEach(entry => {
    const houseTitle = extractValue(entry, /<div class="house-title">\s*([\s\S]*?)\s*<\/div>/);
    const houseLocation = extractValue(entry, /<span class="house-location">\s*([\s\S]*?)\s*<\/span>/);
    const houseSize = extractValue(entry, /<span class="house-size">\s*([\s\S]*?)\s*<\/span>/);
    const houseBuild = extractValue(entry, /<span class="house-build">\s*([\s\S]*?)\s*<\/span>/);
    const housePrice = extractValue(entry, /<span class="house-price">\s*([\s\S]*?)\s*<\/span>/);
    
    data.push([houseTitle, houseLocation, houseSize, houseBuild, housePrice]);
  });
  
  // Output data to Google Sheets
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  sheet.clear();
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}

function extractValue(html, regex) {
  const match = html.match(regex);
  return match ? match[1].trim() : 'N/A';
}

Diesen habe ich dann in Google Tabellen (->Erweiterungen ->Apps-Script) eingefügt und ausführen lassen. Das Ergebnis ist diese Tabelle:

Fazit

Mit Hilfe von ChatGPT und Google Tabellen kannst du recht einfach und automatisiert Daten aus öffentlich zugänglichen Datenbanken extrahieren und diese für deine eigenen Zwecke aufbereiten. Die automatische Aktualisierung stellt sicher, dass deine Daten immer auf dem neuesten Stand sind. Die abschließende Visualisierung mit Datawrapper macht deine Daten anschaulich und leicht verständlich. Probier es aus und entdecke die Möglichkeiten des Web Scraping mit ChatGPT!

Natürlich lässt sich das Script weiter verfeinern. Ich könnte ChatGPT beispielsweise bitten, nur die Daten bestimmmter Flüsse anzuzeigen oder zusätzlich noch den aktuellen Wassserstand. Aber das kannst du natürlich auch ganz nach deinen Bedürfnissen machen.

Viel Spaß beim Ausprobieren und bis zum nächsten Mal!

Teile diesen Beitrag

7 Kommentare

  1. Martin

    Das Ansprechen einer öffentlichen API ähnelt dem WebScraping so wenig wie das Einkaufen im Supermarkt dem Pflücken von Wildkräutern im Wald. Meiner Meinung nach ist der Titel irreführend gewählt. Ansonsten ist der Blogartikel informativ und der Rest gut, danke dafür.

    • Matthias Süßen

      Moin Martin. Vielen Dank auch für Deinen Kommentar. Über Begrifflichkeiten mag ich nicht streiten.

      • DetailsMatters

        Mit Verlaub, das hat nichts mit Begrifflichkeiten zu tun sondern das eine meint eben eine Technik und die andere eben die andere. Ein anderes Beispiel dazu wäre, wenn du sagen würdest ich fliege mit dem Fahrrad von A nach B und jemand würde dich korrigieren, dass du mit dem Fahrrad fährst und nicht fliegst und du wiederum antworten würdest, ach sei doch nicht so kleinilich…

        • Matthias Süßen

          Moin Martin. Bitte entschuldige. War ein paar Tage anderweitig beschäftigt und bin nicht dazu gekommen, Kommentare freizugeben. Danke nochmals für Deinen Hinweis. Ich habe den Artikel ergänzt. Jetzt ist die REST-API-Abfrage „nur“ der erste Schritt. Gruß M

  2. Kathrin Haarstick

    I am very impressed!

    • Matthias Süßen

      Ich danke Dir. Ich bin ich ja ehrlich gesagt, auch immer wieder erstaunt, was so alles geht.

  3. […] Hier steht nur der Mustercode, den ich durch ein Webscraping-Tool auslesen lasse. Weitere Informationen dazu findest du in dem Artikel Wir bauen einen Datenstaubsauger: Web Scraping mit ChatGPT. […]

Schreibe einen Kommentar

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

Consent Management Platform von Real Cookie Banner