Schlüsselwörter

figure a

Automatisierte Verfahren der Datenerhebung spielen vor allem dort eine Rolle, wo sich das Handeln von Akteuren in Daten niederschlägt.Footnote 1 Das betrifft insbesondere die internetvermittelte Kommunikation, etwa wenn Anbieter Webseiten erstellen und die Zugriffe protokollieren, wenn Nutzer:innen auf diesen Webseiten Inhalte veröffentlichen, kommentieren und bewerten oder wenn Forscher:innen ihre Ergebnisse auf Webseiten publizieren. Steht man als Wissenschaftler:in einem Webangebot gegenüber, so lassen sich drei Ebenen unterscheiden, auf denen sich das Ergebnis von Handeln wiederfindet (siehe auch Kap. 2). In seltenen Fällen bekommt man Zugriff auf die Ebene der Datenbanken, aus denen Webseiten erzeugt und in denen Zugriffe protokolliert werden. Dahingegen stellen jedoch einige Anbieter Programmierschnittstellen bereit, über die ein automatisierter Zugang zu Funktionen und vorstrukturierten Daten möglich ist. Auch ohne spezielle Schnittstellen können Daten direkt aus Webseiten ausgelesen werden, denn auf Ebene der Browser sind Texte und Nutzungsindikatoren für Wissenschaftler:innen genauso sichtbar wie für andere Nutzer:innen. In den folgenden Kapiteln geht es darum, wie solche Daten mit eigenen Skripten erhoben werden.

Die Ausführungen setzen erste Erfahrungen mit Python und R voraus (siehe Kap. 5). Hilfreich sind auch grundlegende Kenntnisse über HTML und URLs (siehe Kap. 2 und 3). Es geht hier einerseits darum, die grundsätzliche Vorgehensweise zu vermitteln und ein Grundgerüst zur Verfügung zu stellen. Andererseits werden Hinweise auf typische Hürden gegeben. Aus diesen Zutaten können Sie anschließend mit etwas Geduld und Kreativität eigene Lösungen entwickeln.

1 Webscraping

Webscraping bezeichnet das automatisierte Extrahieren von Daten aus Webseiten. In einem allgemeinen Sinn kann man darunter alle Verfahren verstehen, bei denen Daten über das HTTP-Protokoll übertragen und anschließend aufbereitet werden. Das HTTP-Protokoll ist eine wesentliche Grundlage des Web und dient vor allem dazu, dass Webseiten in Webbrowsern angezeigt werden können. Es ist in der Adresszeile von Browsern erkennbar: Das Protokoll wird in der Regel bei unverschlüsselten Verbindungen in der Form „http://“ oder bei verschlüsselten Verbindungen als „https://“ direkt vor der URL angezeigt.Footnote 2

In einem engeren Sinn versteht man unter Webscraping dagegen nur diejenigen Verfahren, bei denen Webseiten im HTML-Format verarbeitet werden (siehe Abschn. 3.4). Auch APIs bauen teilweise auf dem Web auf, geben Daten aber in strukturierter Form zurück, etwa im JSON-Format. Eine Spezialform von Webscraping ist das Webcrawling. Hierbei werden die Links einer Webseite ausgelesen und verfolgt, das heißt, es werden immer weitere Webseiten gesammelt. Webcrawler, auch als Webspider bezeichnet, arbeiten sich auf diese Weise durch das Netz. Insbesondere Suchmaschinen verwenden dieses Verfahren, um so nach und nach alle Webseiten zu erfassen.

Für Webscraping als Methode zur automatisierten Datenerhebung gibt es typischerweise drei Möglichkeiten:

  1. 1.

    Beim klassischen Webscraping erhält ein Skript eine Liste von URLs und lädt die entsprechenden Seiten herunter. Aus dem so abgespeicherten Quelltext werden die Daten extrahiert.

    Ein Vorteil dieser Methode besteht darin, dass sie vergleichsweise einfach umzusetzen ist und auch gut skaliert, das heißt für eine hohe Anzahl von Webseiten eingesetzt werden kann. Aufwendig sind allerdings Authentifizierungsverfahren über Cookies (wenn man sich bei einer Webseite anmelden muss), eingeblendete Popups oder der Umgang mit dynamischen Inhalten (wenn Webseiten Daten im Hintergrund nachladen).

  2. 2.

    Bei der Automatisierung des Webbrowsers startet ein Skript einen Browser, der dann ferngesteuert wird. Einerseits kann dann wie beim klassischen Webscraping der Quelltext der Seiten abgespeichert und weiterverarbeitet werden. Andererseits sind die Inhalte der Seiten im Browser in einem sogenannten Document Object Model (DOM) verfügbar, auf das ein Skript zugreifen kann.

    Ein Vorteil dieser Vorgehensweise ist, dass sie dem manuellen Surfen im Web sehr nahekommt. Auch Webseitenbetreiber können hier kaum unterscheiden, ob ein Skript bzw. Bot oder ein Mensch auf die Webseite zugreift. Zudem kann man sich bei einer Webseite anmelden, indem Benutzername und Passwort ferngesteuert in die entsprechenden Anmeldefelder geschrieben werden oder indem man zwischen automatisierten Eingaben und manuellem Eingreifen hin und her wechselt. Auch dynamische Inhalte, die vom Browser automatisch nachgeladen werden, sind zugänglich, wenn man den Ladevorgang abwartet. Diese Vorgehensweise ist sehr langsam, hat aber den Charme, dass man dem Computer beim Surfen zuschauen kann.

  3. 3.

    Spezialprogramme wie RapidMiner, ScrapeBox oder Facepager bieten dagegen grafische Benutzeroberflächen an, um Seiten herunterzuladen und zu verarbeiten.Footnote 3

    Als Vorteil mag hierbei erscheinen, dass man nicht programmieren muss. Wer keine Programmiererfahrung hat, bekommt hiermit den schnellsten Einstieg. Dieser Vorteil ist aber trügerisch, denn gleichzeitig gibt man die Hoheit über den Prozess der Datenerhebung auf. Nicht nur die Funktionsweise einer Plattform wie Facebook ist dann eine Black Box, sondern zusätzlich auch die zur Datenerhebung eingesetzte Software.

Alle drei Möglichkeiten werden im Folgenden kurz vorgestellt.

1.1 Klassisches Webscraping

Klassisches Webscraping kann in drei Schritte unterteilt werden. Zunächst werden die benötigten Webseiten heruntergeladen, das heißt, die HTML-Dateien werden abgespeichert. Im zweiten Schritt werden aus diesen Dateien die gewünschten Daten extrahiert. Dazu werden die Dateien in der Regel so eingelesen, dass die Struktur der Daten in Strukturen der Programmiersprache überführt wird. Ein solcher Prozess wird parsen genannt und das dazu eingesetzte Programm ist ein Parser. Schließlich werden diese extrahierten Daten in einem Format abgespeichert, das für die weitere Verarbeitung geeignet ist, etwa in Tabellen im CSV-Format. Webscraping lässt sich mit vielen verschiedenen Programmiersprachen umsetzen.Footnote 4 Mit Python (siehe Abschn. 5.2) läuft dieser Prozess typischerweise wie folgt ab (unten finden Sie ein Beispiel mit R):

  1. 1.

    Mit Funktionen aus der Bibliothek requests werden Webseiten heruntergeladen und auf dem Computer abgespeichert (Reitz 2020). Zusätzlich kommen in der Regel noch Funktionen aus der Bibliothek os zum Einsatz, um mit Dateien und Verzeichnissen umzugehen. Hierbei ist zu beachten, dass die reinen HTML-Dateien heruntergeladen werden und deshalb zum Beispiel kein JavaScript ausgeführt wird. Einige Seiten enthalten nur ein Grundgerüst und laden die Inhalte erst mit JavaScript und sogenannten XMLHttpRequests (XHR) nach. Diese Seiten können mit klassischem Webscraping nicht ohne Weiteres ausgelesen werden.

    Häufig sind die Betreiber allerdings darauf eingestellt, zumindest die wesentlichen Inhalte auch ohne JavaScript auszuliefern. Mitunter werden auch spezielle Mobilseiten angeboten, die ohne JavaScript auskommen. Um zu erkunden, wie eine Seite ohne JavaScript aussieht, kann man dieses im Browser über die Einstellungen übergangsweise deaktivieren. Einige Anbieter stellen ihre Inhalte zusätzlich als RSS-Dateien zur Verfügung. Das hat den Vorteil, dass die Daten ähnlich wie bei der Verwendung von APIs schon vorstrukturiert sind. Diese Dateien enthalten XML und können im Prinzip genauso verarbeitet werden wie HTML-Seiten.

  2. 2.

    Die Dokumente werden anschließend mit Funktionen aus der Bibliothek Beautiful Soup geparst (Richardson 2022). Beautiful Soup kann sowohl HTML als auch XML verarbeiten und ist je nach Modus mehr oder weniger fehlertolerant. Das ist wichtig, weil Webseiten nicht immer standardkonform sind. Genauso wie dieses Dokument ganz sicher Rechtschreib-, Formulierungs- und Formatierungsfehler enthält, wird man auch im Web regelmäßig auf Fehler oder zumindest Sonderfälle stoßen. Nach dem Einlesen liegen die Daten in einem sogenannten Document Object Model (DOM) vor, das heißt die Teile des Dokuments sind in einer hierarchischen Baumstruktur abgelegt, wobei die Elemente Knoten genannt werden, die Verbindungen zwischen den Knoten heißen Achsen. Für den Zugriff auf die Elemente stellt Beautiful Soup mehrere Möglichkeiten bereit:

    • Navigieren: Man kann sich im baumartig aufgebauten DOM von Ast zu Ast hangeln, wobei sich die Stammbaumterminologie eingebürgert hat. Ausgehend von einem Element kann man die Kindelemente (engl. children), Geschwisterelemente (engl. siblings) oder das Elternelement (engl. parent) erreichen.

    • Suchen: Elemente können mittels ihres Namens oder ihrer Attribute gesucht werden (siehe Abschn. 3.4). Dabei kann man auch reguläre Ausdrücke verwenden (siehe Abschn. 4.1.1).

    • CSS-Selektoren: Cascading Stylesheets (CSS) sind eigentlich eine Sprache zur Formatierung von Webseiten, zum Beispiel um Schriftfarben oder die Breite einer Spalte festzulegen. Mit Selektoren wird bestimmt, welche Elemente formatiert werden sollen. Die einfachsten Selektoren bestehen nur aus dem Namen eines Elements. Man kann Elemente zudem durch ihre Klassenattribute und IDs auswählen sowie in hierarchisch tieferliegende Ebenen des DOM eintauchen (siehe Abschn. 4.1.2).

  3. 3.

    Die Inhalte der so ausgewählten Elemente werden schließlich in einer passenden Datenstruktur abgelegt. Wenn mehrere Seiten ausgelesen werden, kann zum Beispiel eine Liste von Dictionaries verwendet werden. In jedem Dictionary sind dann die einzelnen Datenwerte einer Seite als Name-Wert-Paare abgelegt. Eine solche Datenstruktur lässt sich im JSON-Format abspeichern, sie lässt sich aber auch in eine Tabelle umformen. Jedes Element der Liste entspricht dabei einer Zeile, die Namen innerhalb der Dictionaries geben die Spalten an und die Werte in den Dictionaries entsprechen den Zellen der Tabelle. Die Bibliothek pandas (Pandas development team 2022a) stellt Funktionen bereit, mit denen Listen von Dictionaries in tabellenartige Strukturen umgeformt werden können. Das Ergebnis lässt sich dann zum Beispiel als CSV- oder Excel-Datei abspeichern.

Das folgende Beispiel setzt diese Schritte um und extrahiert eine Wikipedia-Tabelle deutscher Zeitschriften – sortiert nach Auflagenstärke im vierten Quartal 2014 (Abb. 7.1). Möglicherweise müssen Sie die Skripte etwas anpassen, denn das Web entwickelt sich beständig weiter und die Anbieter ändern immer wieder die Struktur von Webseiten. Die grundsätzliche Vorgehensweise bleibt aber gleich.

Abb. 7.1
figure 1

Webseite und Quelltext einer Seite im Vergleich. (Quelle: Ausschnitt aus Wikipedia (2021, https://de.wikipedia.org/wiki/Liste_auflagenstärkster_Zeitschriften#Deutschland), CC-BY-SA. Den vollständigen Quelltext können Sie im Browser mit der Entwicklerkonsole betrachten (siehe Abschn. 3.4))

Erstellen Sie zunächst ein neues Jupyter-Notebook (siehe Abschn. 5.2) und gehen Sie dann Stück für Stück vor, indem Sie einzelne Zellen einfügen und ausführen (☛ Repositorium). Versuchen Sie dabei zu verstehen, was der Code bewirkt. Zur Erinnerung: Die Zeilen mit einem Hash # am Anfang sind Kommentare, die nur der Erläuterung und Dokumentation dienen. Zur Überprüfung der Schritte können Sie den Inhalt der Objekte mit dem print()-Befehl ausgeben. Grundsätzlich wird in Jupyter-Notebooks das zuletzt angegebene Objekt in einer Zelle automatisch ausgegeben, sodass der print()-Befehl nicht immer nötig ist.

Schritt 1: Dokumente herunterladen

Im ersten Schritt werden die Dokumente heruntergeladen und in einer Datei im Arbeitsverzeichnis abgespeichert. Wesentlich ist der Befehl requests.get(), mit dem eine Anfrage an den Webserver gesendet wird, um eine Seite herunterzuladen. Welche Seite genau heruntergeladen werden soll, wird über eine URL angegeben. Der Server antwortet auf die Anfrage zunächst mit einem Statuscode. Mit dem Statuscode 200 signalisiert der Server, dass die Seite vorhanden ist und heruntergeladen werden kann. Weitere häufig anzutreffende Statuscodes sind 404, wenn eine Seite nicht vorhanden ist, oder 500, wenn auf dem Server ein Fehler auftritt.Footnote 5

# Bibliotheken einbinden import os import requests # Unterverzeichnis zum Herunterladen festlegen und # anlegen, wenn es noch nicht existiert directory = "html" if not os.path.exists(directory): os.makedirs(directory) # URL und Dateiname festlegen url = "https://de.wikipedia.org/wiki/" + \ "Liste_auflagenst%C3%A4rkster_Zeitschriften" dateiname = directory + "/zeitschriften.html" # Herunterladen response = requests.get(url) if response.status_code == 200: with open(dateiname, 'wb') as datei: datei.write(response.content)

Nach dem Ausführen dieses Abschnitts sollte im Unterverzeichnis html eine HTML-Datei der Webseite liegen. Öffnen Sie die Datei mit dem Browser oder mit einem Texteditor wie Atom, um sich den Inhalt anzuschauen. In der Browseranzeige der HTML-Datei kann es Ihnen so vorkommen, als wäre die Datei kaputt, da sie nicht ordentlich formatiert ist. Dies liegt daran, dass nur der HTML-Inhalt ohne die grafische Gestaltung (CSS-Dateien) heruntergeladen wurde – für die Datenerhebung ist das in der Regel genau richtig.

Bei der Anfrage lassen sich noch weitere Informationen an den Webserver schicken, um mit einem Skript das menschliche Surfen nachzuahmen. Zum Beispiel können Cookies mitgeschickt werden, um sich bei einer Seite anzumelden. Hilfreich ist auch das Übermitteln eines User-Agent. Der User-Agent gibt an, mit welchem Programm auf die Webseite zugegriffen wird – damit kann sich ein Skript als Webbrowser wie Chrome oder Firefox ausgeben. Beim Webscraping wird das hin und wieder nötig, da einige Webserver nur Anfragen von Browsern, nicht aber Skripten, akzeptieren. Um herauszufinden, welche Cookies oder welchen User-Agent ein Browser normalerweise versendet, können Sie im Browser die Entwicklerkonsole verwenden.Footnote 6 Wie diese Angaben mitgeschickt werden können, lässt sich in der Dokumentation der requests-Bibliothek nachlesen.Footnote 7

Schritt 2: Dokument parsen

Im zweiten Schritt wird mit BeautifulSoup() die Datei eingelesen und im Objekt soup abgelegt. Sie können dieses Objekt beliebig benennen, es repräsentiert das Wurzelelement der Seite. Von dort kann auf das Document Object Model und damit auf die Kindelemente zugegriffen werden. Schauen Sie sich den Quelltext genau an, um die gewünschten Elemente zu identifizieren – dafür müssen Sie zunächst den Aufbau von HTML-Dateien verstehen (siehe Abschn. 3.4)! Die Namen der Elemente können Sie am einfachsten mit der Entwicklerkonsole des Browsers herausfinden. Im Beispiel soll eine Tabelle aus dem Quellcode extrahiert werden. Tabellen sind in <table>-Elementen enthalten. Darin ist jede Zeile in einem <tr>-Tag gekapselt, worin sich wiederum die einzelnen Spalten in <td>-Tags finden (Abb. 7.1).

Die Beautiful Soup-Funktion select() erlaubt es, mittels CSS-Selektoren Elemente zu finden. Im Output erhält man eine Liste mit allen Elementen, auf die der CSS-Selektor zutrifft.Footnote 8 Im Beispiel werden zunächst ausgehend vom Wurzelelement mit select('table') alle untergeordneten Tabellen, also alle <table>-Elemente, aus dem DOM ausgelesen. Aus der Liste tables kann dann mit [3] auf die vierte Tabelle,Footnote 9 diejenige mit den deutschen Zeitschriften, zugegriffen werden. Innerhalb der Tabelle können nach dem gleichen Schema alle Zeilen gewonnen werden. Die erste Zeile enthält keine Inhalte, sie wird mit table_rows[1:] aussortiert, indem nur Zeilen ab Index 1 behalten werden. Es lohnt sich, die Dokumentation von Beautiful Soup zu lesen, um einen Überblick über weitere Möglichkeiten zu erhalten.Footnote 10

# Bibliotheken einbinden from bs4 import BeautifulSoup # Datei öffnen und HTML parsen soup = BeautifulSoup( open(dateiname, encoding="utf-8"), 'lxml' ) # Alle Tabellen finden, vierte Tabelle rausziehen tables = soup.select('table') table_de = tables[3] # Alle Zeilen in Tabelle finden # Die erste Zeile (ohne Inhalte) entfernen rows = table_de.select('tr') rows = rows[1:]

Aus allen gefundenen Zeilen, die als Liste im neu erstellten Objekt rows abgelegt sind, werden anschließend die Inhalte ausgelesen. In jedem Durchlauf der For-in-Schleife werden zunächst über select('td') alle Spalten innerhalb einer Zeile gefunden und in der Liste cols abgelegt. Auf eine einzelne Spalte wird wie schon bei den Tabellen über Indizes zugegriffen. Der Text des Elements lässt sich über .text extrahieren und mit .strip() so bereinigen, dass Leerzeichen oder Markierungen von Umbrüchen am Anfang und am Ende entfernt werden.

Um die extrahierten Daten einzusammeln, wird zunächst ein leeres Dictionary item angelegt. Innerhalb eines Durchlaufs der For-Schleife wird das Dictionary mit Einträgen gefüllt und der Liste results hinzugefügt.

# Liste, um die Ergebnisse abzulegen results = [] # Alle Zeilen abarbeiten... for row in rows: # Alle Spalten innerhalb einer Zeile finden cols = row.select('td') # Text aus Spalten auslesen item = {} item['rang'] = cols[0].text.strip() item['titel'] = cols[1].text.strip() item['auflage'] = cols[2].text.strip() item['gruppe'] = cols[3].text.strip() # Das dict zur results-Liste hinzufügen results.append(item)

Nach dem Ausführen dieses Abschnitts liegen die extrahierten Inhalte in der Liste results vor. Im Beispiel werden die ersten vier Spalten der Tabelle ausgelesen. Versuchen Sie, weitere Daten auszulesen oder aufzubereiten und in der results-Liste abzulegen!

Hilfreich könnte es beispielsweise sein, die Links auszulesen, durch die man bei einem Klick auf den Titel zum entsprechenden Wikipedia-Artikel gelangt. Diese Links sind innerhalb der zweiten Spalte in den <a>-Elementen enthalten, genauer in den href-Attributen. Da aus jeder Spalte nur ein einzelnes Element ausgelesen werden soll, nicht eine ganze Liste, wird die select_one()-Funktion verwendet. So spart man sich den Zugriff über die Indizes. Aus diesem Element kann man mit get('href') dann die URL auslesen:

link = cols[1].select_one('a') if link: item['link'] = "www.wikipedia.org" + \ link.get('href') else: item['link'] = None

Grundsätzlich muss man sich darauf einstellen, dass innerhalb einer Website häufig nicht alle Tabellen, Listen oder Unterseiten gleich aufgebaut sind und dass sich Webseiten immer wieder ändern. Damit ein Skript nicht jedes Mal abbricht, wenn man auf solch eine Hürde stößt, baut man Fehlerbehandlungen ein. Im vorangegangenen Beispiel ist eine einfache Variante umgesetzt: Nicht alle Artikel enthalten einen Link, der Zugriff über link.get() würde dann zu einem Fehler führen. Deshalb wird mit einer If-else-Verzweigung geprüft, ob das Element erfolgreich ausgelesen werden konnte.

Eine universelle Möglichkeit der Fehlerbehandlung bieten Try-except-Blöcke. Innerhalb des Try-Blocks wird zunächst der Code formuliert, der ausgeführt werden soll. Wirft dieser einen Fehler aus, wird zum Except-Block gesprungen. In diesem ist festgelegt, wie alternativ verfahren wird – etwa ob die entsprechende Funktion übersprungen wird oder ein leerer Wert zurückgegeben werden soll. Bauen Sie das Beispiel einmal entsprechend um!

Schritt 3: Daten abspeichern

Im letzten Schritt geht es darum, die Daten für die weitere Analyse abzuspeichern. Mit der pandas-Bibliothek wandeln Sie die Liste in eine Tabelle um und können diese dann als CSV-Datei abspeichern. Damit die Datei leichter mit Excel geöffnet werden kann, geben Sie das Semikolon als Trennzeichen an:

# Bibliotheken einbinden import pandas as pd # Liste mit Dictionaries in Dataframe umwandeln results = pd.DataFrame(results) # Vorschau des Dataframe ausgeben display(results) # Dataframe als CSV-Datei abspeichern results.to_csv( "results.csv", sep=";", index=False )

Wenn dieser Schritt funktioniert hat, dann sehen Sie dank der Funktion display() im Notebook einen Auszug aus der Tabelle mit den extrahierten Daten. Außerdem sollte im Verzeichnis von JupyterLab eine CSV-Datei liegen. Öffnen Sie die Datei mit einem Texteditor und mit einem Programm wie Excel, um den Aufbau zu verstehen.

Wenn Sie das Beispiel an andere Zwecke anpassen und weiter ausbauen, etwa um in einer Schleife mehrere Seiten nacheinander automatisch herunterzuladen, wird es schnell unübersichtlich. Sie können die Übersichtlichkeit verbessern, indem Sie Teile des Codes in eigene Funktionen verpacken (☛ Repositorium). Für umfangreichere Projekte lohnt sich darüber hinaus die Arbeit mit speziell dafür entwickelten Bibliotheken. Empfehlenswert ist hierfür das Framework Scrapy.Footnote 11

Alternative: Webscraping mit R

Die gleiche Vorgehensweise lässt sich auch mit R (siehe Abschn. 5.1) umsetzen. Die benötigten Bibliotheken sind tidyverse (Wickham 2019b) und writexl (Ooms und McNamara 2021) für die Verarbeitung und das Abspeichern der Ergebnisse. Über die Bibliothek rvest (Wickham 2022b) kann eine Seite heruntergeladen und geparst werden:Footnote 12

# Packages library(tidyverse) library(writexl) library(rvest) # Seite herunterladen und parsen url <- "https://de.wikipedia.org/wiki/ Liste_auflagenst%C3%A4rkster_Zeitschriften" html <- read_html(url) html

Das erzeugte html-Objekt ist vergleichbar mit dem soup-Objekt von Beautiful Soup. Es kann nun mit ähnlichen Funktionen auf die Elemente im Document Object Model (DOM) zugegriffen werden. Besonders einfach ist der Zugriff mit der Funktion html_nodes(). Diese Funktion erwartet als ersten Parameter das html-Objekt und als zweiten Parameter einen CSS-Selektor.Footnote 13 Um auf alle <table>-Elemente zuzugreifen, kann man den CSS-Selektor table verwenden:Footnote 14

el_tables <- html_nodes(html, "table")

Im Sinne der Tidyverse-Logik ist besonders bei mehreren Verarbeitungsschritten der Pipe-Operator %>% hilfreich – etwa wenn zunächst die Elemente und im nächsten Schritt dann deren Attribute oder Inhalte extrahiert werden. Die Pipe schiebt im folgenden Beispiel das Ausgangsobjekt html als ersten Parameter in die Funktion html_nodes(). Diese Formulierung ist äquivalent zur Variante ohne Pipe, mit dem Vorteil, dass das Resultat bei Bedarf über das Anhängen weiterer Pipes in weitere Funktionen geschoben werden kann.

el_tables <- html %>% html_nodes("table")

Im Objekt el_tables liegt nun eine Liste mit allen <table>-Elementen vor – der Name „el_tables“ ist selbst gewählt. Interessieren nicht alle Tabellen, kann man den entsprechenden Listeneintrag über eckige Klammern auswählen, die vierte Tabelle enthält die Angaben zu deutschen Zeitschriften. Im nächsten Schritt gelangt man wieder über html_nodes() an die Zeilen der Tabelle:

el_rows <- el_tables[4] %>% html_nodes("tr")

Aus den einzelnen Zeilen können nun in einem Loop die Werte ausgelesen werden. Die Funktion html_text() erlaubt dabei Zugriff auf den Textinhalt der Elemente, während mit html_attr() einzelne Attribute extrahiert werden. So lässt sich neben dem Link auch der Text aus dem Element <a href="/wiki/ADAC_Motorwelt" title="ADAC Motorwelt">‌ADAC Motorwelt</a> auslesen.

Um alle Werte der einzelnen Zeilen einzusammeln, wird zunächst ein leeres Tibble results angelegt. Innerhalb eines jeden Durchlaufs wird dann ein Tibble magazine mit nur einer einzigen Zeile erstellt, welches mit bind_rows() fortlaufend an results angehängt wird:

# Leeres Tibble zum Sammeln der Ergebnisse results <- tibble() # Alle Zeilen abarbeiten for (el_row in el_rows) { # Alle Spalten innerhalb einer Zeile finden el_cols <- el_row %>% html_nodes("td") # Text aus der zweiten Spalte auslesen titel = el_cols[2] %>% html_text() # URL aus dem Attribut 'href' auslesen link = el_cols[2] %>% html_nodes("a") %>% html_attr('href') # In einem neuen Tibble ablegen... magazine <- tibble( 'titel' = titel, 'link' = link ) # ... und zu den Ergebnissen hinzufügen results <- bind_rows(results, magazine) }

Versuchen Sie, noch weitere Spalten auszulesen und in der results-Liste abzulegen!

1.2 Automatisierung des Webbrowsers

Eine weitere Möglichkeit zur Datenerhebung im Web besteht darin, den Browser zu automatisieren. Der Browser wird dabei wie eine Marionette durch Code ferngesteuert. Das folgende Beispiel verwendet Python, um den Browser Firefox zu automatisieren. Zwischen dem Skript und dem Browser sitzen drei weitere Komponenten (Abb. 7.2). Der Browser wird durch den GeckoDriver um eine Programmierschnittstelle erweitert, auf die dann die Automatisierungssoftware Selenium (ThoughtWorks 2022) zugreift. Die Entwicklung des Skripts, über welches Selenium angesteuert wird, findet in der Entwicklungsumgebung Jupyter-Notebook statt. Diese Pipeline ist nur ein Beispiel. Es können auch andere Browser wie Chrome oder andere Programmiersprachen und Entwicklungsumgebungen eingesetzt werden.

Abb. 7.2
figure 2

Komponenten bei der Automatisierung eines Browsers am Beispiel von Firefox. (Quelle: eigene Darstellung)

Die wesentliche Komponente zur Automatisierung des Browsers ist Selenium. Diese Software wird unter anderem zur Entwicklung von Webseiten eingesetzt, um automatisiert neu entwickelte Funktionen zu testen. Es lässt sich damit aber auch sehr gut Webscraping betreiben. Die Installation für Python nimmt man am besten auf der Kommandozeile über den Paketmanager pip vor. Wenn Sie mit JupyterLab arbeiten, können Sie direkt von dort ein Terminal öffnen (File > New Launcher):

pip install selenium

Natürlich benötigen Sie auch einen Browser, der ferngesteuert werden kann. Falls noch nicht vorhanden, installieren Sie Firefox.Footnote 15 Alternativ können Sie auch Google Chrome verwenden, müssen dann aber in den nächsten Schritten statt des GeckoDriverManager den ChromeDriverManager einbinden. Diese Driver stellen die Schnittstelle zwischen Selenium und dem Browser dar, bei der Installation hilft der Webdriver Manager:Footnote 16

pip install webdriver_manager

Starten Sie anschließend JupyterLab und legen Sie ein neues Python-3-Notebook an. Der passende Driver kann nun installiert und eingebunden werden:

from selenium.webdriver.firefox.service \ import Service from webdriver_manager.firefox \ import GeckoDriverManager driver = Service(GeckoDriverManager().install())

Sobald die Software installiert ist, sind die Schritte im Prinzip die gleichen wie beim klassischen Webscraping. Zunächst werden Seiten aufgerufen, dann Daten extrahiert und diese Daten werden dann abgespeichert.

Schritt 1: Browser fernsteuern

Im ersten Schritt werden der Webbrowser gestartet und eine Seite geöffnet:

# Programmbibliotheken laden from selenium.webdriver.firefox.service \ import Service from webdriver_manager.firefox \ import GeckoDriverManager # Driver initialisieren driver = Service(GeckoDriverManager().install()) # Browser starten browser = webdriver.Firefox(service=driver) browser.get("https://www.google.de/")

Daraufhin sollte sich ein Firefox-Fenster geöffnet haben, in dem die Startseite von Google aufgerufen wird. Sie können nun manuell in diesem Browser surfen, das Surfen automatisieren oder zwischen diesen beiden Modi hin und her wechseln. So bietet es sich beispielsweise zu Beginn an, den Datenschutzbedingungen, die sich beim erstmaligen Aufrufen von Google öffnen, manuell zuzustimmen und erst dann die weitere Suche zu automatisieren.

Um automatisiert Suchbegriffe in den Suchschlitz einzugeben, muss der Suchschlitz eindeutig identifiziert werden. Wie beim klassischen Webscraping schauen Sie dazu in den Quelltext der Seite, zum Beispiel über die Entwicklerkonsole. Klicken Sie mit der rechten Maustaste auf den Suchschlitz und wählen Sie Element untersuchen. Es handelt sich bei diesem Eingabefeld um ein HTML-Element mit dem Namen input. Dieses Element kann auf verschiedene Weise identifiziert werden, beispielsweise durch die ID lst-ib oder den Namen q (Abb. 7.3).

Abb. 7.3
figure 3

Quelltext eines Eingabefelds. (Quelltext von https://www.google.de. Quelle: eigene Darstellung)

Selenium stellt mehrere Funktionen bereit, um mit den Elementen einer Seite zu arbeiten – Sie sollten sich dazu unbedingt die Dokumentation ansehen.Footnote 17 Das folgende Beispiel verwendet die Funktion find_element() in Kombination mit By.Name zur Identifizierung des Suchschlitzes. Zur Simulation der Tastatureingabe wird die Funktion send_keys() verwendet. Vorher wird festgelegt, dass Selenium einige Zeit warten soll, falls das gesuchte Element nicht verfügbar ist. Das ist notwendig, weil das Laden der Seite einen Moment dauert:

# By.Name und By.Id importieren from selenium.webdriver.common.by import By # Beim Zugriff auf Elemente der Seite bis zu # 10 Sekunden warten, sodass die Seite laden kann browser.implicitly_wait(10) # Suchschlitz finden suchschlitz = browser.find_element(By.NAME, "q") # In den Suchschlitz schreiben suchschlitz.send_keys("Wie macht ein ") # Abschicken suchschlitz.submit()

Eingabefelder und Buttons sind auf Webseiten in der Regel in sogenannte Formulare eingebettet. Indem man das Formular abschickt, werden alle eingegebenen Inhalte an den Server geschickt. Die letzte Zeile schickt das Formular ab, das mit dem ausgewählten Eingabefeld in der Google-Suche verbunden ist. Dafür verfügt das input-Element (das im Objekt suchschlitz abgelegt ist) über die Funktion submit(). Alternativ zum Abschicken über submit(), welches dem Drücken der Enter-Taste gleichkommt, könnte auch der Klick auf den Button simuliert werden. In diesem Fall müssten Sie analog zum Suchschlitz den Suchbutton identifizieren. Für das gefundene Element könnte anschließend die click()-Funktion anstelle der submit()-Funktion ausgeführt werden.

Webscraping kann übrigens auch so durchgeführt werden, dass der Browser unsichtbar bleibt, das heißt, die Befehle können ausgeführt werden, ohne ein Browserfenster zu öffnen. Ein solcher Modus wird headless genannt und beschleunigt den Prozess in der Regel. Weitere Informationen dazu finden Sie in der Dokumentation von Selenium.

Schritt 2: Inhalte der Seite verarbeiten

Auch um den Inhalt der Seite zu verarbeiten, müssen wieder die gewünschten Elemente über Namen oder IDs identifiziert werden. Dann kann auf den Inhalt der Elemente über die text-Eigenschaft zugegriffen werden. Im folgenden Beispiel wird außerdem gezeigt, wie aus diesem Text mit einem regulären Ausdruck (siehe Abschn. 4.1.1) die Zahl ausgelesen wird.

# Anzahl der Ergebnisse auslesen ergebnisse = browser.find_element( By.ID, 'result-stats' ) print(ergebnisse.text) # Bibliothek für reguläre Ausdrücke # zum Verarbeiten von Zeichenketten laden import re # Zahl mit regulärem Ausdruck extrahieren anzahl = re.search( '([0-9\.]+) Ergebnisse', ergebnisse.text ).group(1) # Punkt aus Zeichenkette entfernen anzahl = anzahl.replace('.', '') # In eine Ganzzahl (int) umwandeln anzahl = int(anzahl) print(anzahl)

Automatisierung wird dann sinnvoll, wenn mehrere Suchabfragen durchgeführt oder mehrere Seiten ausgelesen werden sollen. Die Ergebnisse können analog zur Vorgehensweise beim klassischen Webscraping in einer Liste bestehend aus Dictionaries abgelegt werden. Vorausgesetzt der Webbrowser wurde wie bislang beschrieben mit Selenium gestartet, lässt sich das gut über eine For-in-Schleife umsetzen:

# URL und Liste mit Keywords festlegen url = "https://www.google.de/" keywords = ["Computational", "Statistical", \ "Interpretive"] # Leere Liste für Suchergebnisse erstellen results = [] # Für jedes Keyword die Google-Suche durchführen, # Anzahl der Ergebnisse auslesen und # in der results-Liste ablegen for keyword in keywords: print(keyword) browser.get(url) suchschlitz = browser.find_element(By.NAME, "q") suchschlitz.send_keys(keyword) suchschlitz.submit() anzahl = browser.find_element( By.ID, 'result-stats' ).text result = {'keyword':keyword, 'count':anzahl} results.append(result) results

Eine der größeren Herausforderungen besteht darin, festzustellen, wann eine Seite fertig geladen ist, sodass die benötigten Elemente zur Verfügung stehen. Eine grundsätzliche Einschränkung besteht auch darin, dass mit Selenium (bislang) keine http-Statuscodes ausgelesen werden können. So weiß man nicht, ob eine Seite überhaupt geladen wurde oder ob eine Fehlermeldung vorliegt. Deshalb sollte man Vorsichtsmaßnahmen einbauen.

Beim Zugriff auf einzelne Elemente wird dank der bislang verwendeten Anweisung browser.implicitly_wait(10) so lange gewartet, bis das Element geladen wurde. Das gilt zum Beispiel für die Funktion find_element(). Wenn das Element nach dem angegebenen Timeout von 10 Sekunden nicht gefunden wurde, wird das Skript abgebrochen. Schwierig wird diese Lösung allerdings immer dann, wenn das gesuchte Element auch schon auf der zuletzt aufgerufenen Seite vorhanden war. Denn in diesem Fall wird möglicherweise gar nicht der neue, sondern der alte Inhalt gefunden. Zur Lösung dieses Problem gibt es sehr verschiedene Ansätze. Die folgende Funktion fragt beispielsweise wiederholt den Status der Seite über JavaScript ab:

# Funktion definieren, um so lange zu warten, # bis die Seite geladen ist import time def waitForReadyState(browser, timeout = 15): start_time = time.time() while time.time() < start_time + timeout: page_state = browser.execute_script( 'return document.readyState;' ) if page_state == 'complete': return True time.sleep(0.1) return False

Die Funktion könnte über waitForReadyState(browser) jedes Mal vor dem Zugriff auf ein Element aufgerufen werden, wobei der Parameter browser auf das vom Webdriver bereitgestellte Browser-Objekt verweist. Innerhalb der Funktion wird mittels execute_script() JavaScript im Kontext des Browsers ausgeführt. JavaScript wird häufig für die Interaktion auf Webseiten eingesetzt, hiermit lässt sich tief in die Funktionsweise einer Webseite eingreifen. Auch wenn Sie vielleicht im ersten Moment noch nicht alle Details verstehen, ist dies ein erster Ansatz, falls Sie selbst bei Ihren Experimenten auf das Problem stoßen, warten zu müssen. Weitere Techniken zur Überprüfung des Ladestatus bestehen darin, den alten und den neuen Seiteninhalt zu vergleichen oder so lange zu warten, bis ein Element in der alten Seite ungültig (engl. stale) wird – bei der Umsetzung von Webscraping ist also etwas Kreativität gefragt.Footnote 18

Schritt 3: Daten abspeichern

Wie schon im Abschnitt zum klassischen Webscraping beschrieben, können die Ergebnisse mit pandas wieder in einen Dataframe umgewandelt und als CSV-Datei abgespeichert werden.

# Bibliotheken einbinden import pandas as pd # Liste mit Dictionaries in DataFrame umwandeln results = pd.DataFrame(results) # DataFrame als CSV-Datei abpseichern results.to_csv('results.csv', sep = ";", \ index = False)

Mitunter lohnt es sich, den gesamten Quelltext der Seite für spätere Analysen abzuspeichern. Dieser Quelltext unterscheidet sich in einem entscheidenden Punkt von der HTML-Datei, die beim klassischen Webscraping heruntergeladen wird. Es handelt sich hier um den generierten Quelltext einer Seite, der durch Eingaben in Formulare oder durch interaktive Skripte (JavaScript) verändert werden kann. So kommt es beispielsweise vor, dass Kommentare auf Zeitungsseiten direkt in den HTML-Text eingebunden werden, die Antworten zu den Kommentaren allerdings nachgeladen werden, sobald die Leser:innen auf einen Button wie Antworten zu diesem Kommentar anzeigen klicken. Diese Antworten werden also interaktiv geladen und lassen sich nicht bereits über das bloße HTML-Grundgerüst erheben. Der generierte Quelltext entspricht ganz genau dem sichtbaren Inhalt der Seite, ein Vorteil der Automatisierung über Selenium. Dieser Quelltext wird über das Attribut page_source des Webdriver-Objekts bereitgestellt:

html = browser.page_source

Alternativ kann auch der Quelltext innerhalb einzelner Elemente ausgelesen werden. Selenium stellt dafür innerhalb des Document Object Model (DOM) eine Zugriffsmöglichkeit auf die innerHTML-Eigenschaft von Elementen bereit:

body = browser.find_element(By.TAG_NAME, 'body') html = str(body.get_attribute('innerHTML'))

Um den Quelltext schließlich abzuspeichern, wird eine Datei zum Schreiben (Parameter "w") geöffnet:

with open( "meineseite.html", "w", encoding="utf-8" ) as file: file.write(html)

Da jede Webseite anders aufgebaut ist, muss man sich für die Extraktion der Daten in die Struktur einer Seite eindenken. Will man viele verschiedene Seiten erheben, dann braucht man dagegen eine allgemeinere Technik, um irrelevante Teile wie das Menü, Werbung oder den Footer einer Seite zu entfernen. Für dieses sogenannte Boilerplate Removal gibt es viele verschiedene Ansätze und auch spezialisierte Python-Packages wie trafilatura (Barbaresi 2022; ☛ Repositorium).

Zur Dokumentation der Datenerhebung lassen sich darüber hinaus Screenshots der Seite automatisch abspeichern, wobei nur der sichtbare Bereich erfasst wird:

browser.save_screenshot('meineseite.png')

Mit Firefox können außerdem ganze Seiten oder ausgewählte Teile einer Seite als Screenshot gespeichert werden. Dazu wird zunächst das gewünschte Element identifiziert, zum Beispiel das <body>-Element, um die gesamte Seite zu erfassen. Da Screenshots Pixeldaten in Binärform enthalten, muss die Datei mit dem Parameter "wb" (= write binary) geöffnet werden:

body_element = browser.find_element(\ By.TAG_NAME, 'body') body_png = body_element.screenshot_as_png with open("meineseite.png", "wb") as file: file.write(body_png)

Webscraping über die Automatisierung des Browsers besticht dadurch, dass hier das Surfen einer Nutzerin oder eines Nutzers simuliert wird. Man kann sich automatisiert bei Seiten anmelden sowie manuelles und automatisiertes Surfen kombinieren. Die Seiten sehen nicht anders aus als bei der manuellen Internetnutzung. Im Gegensatz zum klassischen Webscraping ist jedoch insgesamt mehr Geduld erforderlich und auch die Ersteinrichtung kann einige Zeit in Anspruch nehmen.

Alternative: Selenium mit R

Auch mit R und RStudio können Browser über Selenium ferngesteuert werden (☛ Repositorium). Dazu installieren Sie das Package RSelenium (Harrison und Kim 2020). Wenn Sie es anschließend laden, werden bei der ersten Verwendung alle weiteren benötigten Komponenten automatisch nachinstalliert:

library(RSelenium)

Nach dem Laden der Bibliothek werden ein Selenium-Server und ein ferngesteuerter Browser gestartet:

selenium <- rsDriver(browser = "firefox", port = 4566L) server <- selenium$server browser <- selenium$client

Analog zu Python, können nun Seiten aufgerufen werden:

browser$navigate("http://www.google.com")

Der Zugriff auf Eingabefelder gestaltet sich ebenfalls ähnlich:

suche <- browser$findElement(using = 'name', 'q') suche$sendKeysToElement(list("Wie macht ein ")) suche$submitElement()

Die möglichen Befehle und Parameter finden Sie in der Hilfe des Packages RSelenium. Die Befehle zur Interaktion mit dem Browser sind unter „remoteDriver-Class“ dokumentiert, die Befehle zum Auffinden, Auslesen und Interagieren mit den Elementen einer Seite unter „webElement-class“. Am Ende sollten der Browser und der Server wieder geschlossen werden:

browser$close() server$stop()

1.3 Spezialisierte Programme und Plattformen

Um die Komplexität von Webscraping zu bewältigen und den Programmieraufwand zu reduzieren, stehen mittlerweile vielfältige Programme zur Verfügung (siehe Tab. 7.1). Diese lassen sich danach einteilen, wie stark die notwendigen Skripte selbst entwickelt werden müssen oder wie sehr auf die Leistung von Dritten zurückgegriffen wird:

  • Mit Programmierbibliotheken wie Scrapy für Python werden eine Vielzahl von Funktionen zum Webscraping bereitgestellt und einige der gängigen Herausforderungen umschifft. Für andere Programmiersprachen gibt es ebenfalls hilfreiche Bibliotheken, etwa Apify für JavaScript.

  • Mit lokalen Programmen wie HTTrack oder Facepager kann der erste Schritt, das Herunterladen der Quelltexte, umgesetzt werden. Gerade für groß angelegte Datenerhebungen ist dies eine Erleichterung, da Seiten auch parallel heruntergeladen werden können. Programme wie ScrapeBox oder Facepager lesen darüber hinaus gezielt Links aus und können damit als Webcrawler eingesetzt werden. Wenn umfangreiche Funktionen zum Extrahieren und Analysieren der Daten benötigt werden, ist beispielsweise RapidMiner eine Option.

  • Die bislang genannten Programme werden einmal installiert und laufen dann auf dem lokalen Computer. Bei webbasierten Plattformen wie ScrapeBot findet die Datenerhebung und -analyse dagegen auf einem Server statt. Nicht immer ist sofort erkennbar, dass es sich um einen serverbasierten Dienst handelt. So wird das Chrome Plugin von Webscraper.io beispielsweise lokal im Browser installiert, dennoch findet die Datenaufbereitung auf dem Server statt. Von Vorteil ist in der Regel die hohe Performanz serverbasierter Dienste, bedingt durch eine gute Internetanbindung und parallelisierte Prozesse. Neben kostenlosen Einstiegstarifen werden für höhere Leistungsanforderungen mitunter Entgelte erhoben. Auch die Bedienung ist bei kommerziellen Anbietern durchaus komfortabel, denn viele technische Details verschwinden hinter gefälligen Oberflächen. Allerdings gibt man dabei insofern die Hoheit über den Erhebungsprozess auf, als dass die konkrete Umsetzung nicht mehr nachvollzogen werden kann und auch die Daten beim jeweiligen Anbieter gespeichert werden. Diese Vorgehensweise sollte im wissenschaftlichen Kontext gut überlegt sein. Auch im akademischen Umfeld werden Webcrawler angeboten. Eine vielfältige Sammlung spezialisierter Scraper bietet etwa die Digital Methods Initiative (DMI) aus Amsterdam.

Auch wenn die Arbeit mit spezialisierten Programmen und Plattformen effizient ist, sind ein Grundverständnis von Webscraping und eigene Erfahrungen mit der Entwicklung von Webscrapern aus wissenschaftlicher Sicht wichtig. Denn dieses Wissen hilft nicht nur bei der Formulierung der Anforderungen, sondern vor allem bei der Einschätzung der Datenqualität und von typischen Fehlerquellen.

Tab. 7.1 Beispiele für Programmbibliotheken, Programme und Cloud-Dienste zum Webscraping

Zudem müssen rechtliche und ethische Aspekte reflektiert werden, vor allem das Urheberrecht und der Datenschutz. Webscraping ist tendenziell eine unhöfliche Art der Datenerhebung, da es die Server belastet. Einige Anbieter schließen Webscraping deshalb explizit in ihren Nutzungsbedingungen aus und ergreifen technische Maßnahmen zur Verhinderung von Webscraping. Hinweise zur Ethik finden Sie beispielsweise bei Thelwall und Stuart (2006) und eine rechtliche Beurteilung bei RatSWD (2019).

Übungsfragen

  1. 1.

    Fassen Sie kurz zusammen, welche Schritte beim Webscraping vollzogen werden müssen!

  2. 2.

    Worin unterscheiden sich klassisches Webscraping und Browserautomatisierung?

  3. 3.

    Wie unterscheidet sich der heruntergeladene Quelltext einer Seite vom generierten Quelltext?

  4. 4.

    Wie werden beim Webscraping die einzelnen Elemente einer Webseite identifiziert? Öffnen Sie eine Seite Ihrer Wahl, wählen Sie darauf ein Element aus und überlegen Sie sich eine Möglichkeit, dieses Element zu adressieren!

  5. 5.

    Mit welcher Python-Bibliothek können HTML-Texte geparst werden, um Daten zu extrahieren?

  6. 6.

    Was ist mit Boilerplate Removal gemeint?

2 Application Programming Interfaces (APIs)

Application Programming Interfaces (APIs) sind Programmierschnittstellen, über die festgelegt wird, wie zwei Programme miteinander interagieren können (Jacobson et al. 2012, S. 5). Will beispielsweise ein Immobilienportal seine Häuser und Wohnungen auf einer Karte anzeigen und eine Suche nach Orten umsetzen, kann es dafür die Karte von Google Maps über die Google Maps API einbinden. Diese Schnittstellen können auch Wissenschaftler:innen nutzen, um Daten abzufragen oder zu analysieren. Dazu werden meistens sogenannte REST-APIsFootnote 19 verwendet, die ihre Dienste über das Web anbieten. Nicht immer sind mit APIs ausschließlich solche webbasierten Dienste gemeint, das vorliegende Kapitel beschränkt sich aber auf REST-APIs, da sie sich gut für den Einstieg in die Welt der automatisierten Datenerhebung eignen. Die Vorgehensweise ist dabei immer gleich: Zunächst wird eine Anfrage an eine API gestellt. Zum Beispiel wird ein Ortsname an den Google-Maps-Server geschickt (Input). Die API verarbeitet die Anfrage und liefert ein Ergebnis zurück, zum Beispiel die Geokoordinaten des Ortes (Output). Diese Koordinaten können dann verwendet werden, um passende Immobilien anzuzeigen. Wie webbasierte APIs grundsätzlich funktionieren, wie darüber Daten erhoben werden können und wie die Schnittstellen auch anderweitig für die Datenanalyse verwendet werden können, wird in diesem Kapitel theoretisch und praktisch beantwortet.

Warum lohnt sich eine Auseinandersetzung mit APIs? Der Einstieg in eine API kann durchaus Zeit in Anspruch nehmen, wenn man sich erst bei einem Anbieter registrieren, die Dokumentation verstehen und passende Skripte entwickeln muss. Dann aber kommen die Vorteile von APIs gegenüber anderen Datenzugängen zum Tragen. Sie liefern einen über längere Zeiträume stabilen Zugang, der in der Regel gut dokumentiert und nach der Ersteinrichtung einfach zu handhaben ist. Die Daten sind vorstrukturiert, zum Beispiel im JSON-Format, sodass sich der Aufwand bei der Datenaufbereitung in Grenzen hält. Schließlich lassen sich darüber auch komplexe Analysen wie die automatisierte Bilderkennung oder die Transkription von Audiodateien vergleichsweise einfach umsetzen. Dabei ist allerdings immer zu beachten, dass die Analyse über einen Dienst läuft, dessen interne Mechanismen meist aus Sicht der Wissenschaftler:innen eine black box sind. Insofern gilt es stets, die Datenqualität einzuschätzen und zu überprüfen.

2.1 Input: Anfragen an eine API

Da jede API anders funktioniert, lässt sich keine allgemeingültige Anleitung für APIs schreiben. Stattdessen sind alle notwendigen Informationen in den Dokumentationen der jeweiligen API festgehalten. Diese stellen ein grundlegendes Handbuch zur API dar und sind in den Entwicklerportalen oder über Suchmaschinen unter Stichworten wie „Reference“ zu finden. Die Dokumentationen beinhalten üblicherweise eine Übersicht über die verschiedenen APIs eines Dienstes – Anbieter schnüren unterschiedliche Pakete wie eine kostenfreie API oder eine API für Unternehmen. Dort finden sich auch Getting-Started-Anleitungen oder weitere Einstiegshilfen. Besonders die APIs von großen Diensten können auf den ersten Blick sehr kompliziert wirken. Hier lohnt es sich, sich zunächst über die angebotenen Hilfestellungen mit der Struktur und den Möglichkeiten der API vertraut zu machen.

Die Dokumentation enthält insbesondere eine Auflistung der sogenannten Endpunkte. Endpunkte werden bei webbasierten APIs die URLs genannt, über die verschiedene Daten wie Geokoordinaten oder Posts abgefragt (oder auch erstellt) und über die Funktionen wie die Bild- oder Texterkennung ausgeführt werden können. In der Dokumentation wird angegeben, wie sich die URLs zusammensetzen, welche weiteren Parameter eine Abfrage benötigt und wie das Ergebnis aussieht. Bei der Interaktion mit einer API schickt ein Client – beispielsweise ein selbstgeschriebenes Programm – über diese URL eine Anfrage an den Server, bei dem die gewünschten Daten oder Funktionen vorhanden sind. Der Server verarbeitet diese Anfrage und gibt die entsprechenden Informationen an den Client zurück. Client und Server werden demnach über die API als Schnittstelle miteinander verbunden.

Einige Dienste stellen eine Webseite bereit, auf der die Endpunkte und verschiedene Parameter direkt ausprobiert werden können. Verbreitet ist dafür zum Beispiel Swagger UI (Abb. 7.4) oder auf Facebook wird dazu der Graph API Explorer angeboten.

Abb. 7.4
figure 4

Swagger User Interface für die CrossRef-API zur Abfrage von Daten über Zeitschriftenbeiträge (gekürzt). (Quelle: Crossref (2022; https://api.staging.crossref.org/swagger-ui/index.html))

Eine API-Anfrage muss unterschiedliche Elemente beinhalten, damit sie vom Server verstanden und akzeptiert wird: Neben der URL gehören dazu Anfrageheader, eine Methode und für einige Anfragen zudem eine Payload. Die URL setzt sich aus dem Protokoll, der Domain, dem Pfad und Parametern zusammen (ausführlich siehe Kap. 2). Eine URL ist dabei eine eindeutige Adresse, die zu einer Ressource im Web führt. Ressourcen sind Webseiten, die beispielsweise Tabellen, Profile, Posts oder Mediendateien enthalten. Achten Sie beim Surfen im Internet darauf, wie sich die URL verändert, wenn Sie Links und Buttons anklicken! Die URL einer API beginnt in der Regel immer gleich und enthält mitunter die Version der API, zum Beispiel: https://graph.facebook.com/v13.0. An diesen Basispfad werden dann die Pfade der einzelnen Endpunkte angehängt, zum Beispiel ergibt sich daraus https://graph.facebook.com/v13.0/{page-id}/posts, um die Posts einer Facebook-Seite zu erhalten.

Parameter sind ein Teil der URL, wobei sich zwei Formen unterscheiden lassen. Pfadparameter sind Platzhalter im Pfad der URL, die durch eigene Werte ersetzt werden, etwa durch den Benutzernamen der Facebookseite des WWF, um die Posts dieser Seite zu erhalten: https://graph.facebook.com/v13.0/wwfde/posts (siehe auch Abb. 7.4 für ein weiteres Beispiel).

Query-Parameter sind dagegen Name-Wert-Paare, die mit einem ?-Zeichen an den Pfad angehängt werden. Mehrere Parameter werden mit einem &-Zeichen voneinander getrennt. So kann beispielsweise der Zeitraum von Posts eingegrenzt werden: …/wwfde/posts?since=2021-03-01&until=2021-04-01. Einige Parameter sind notwendig, so muss immer der Benutzername einer Facebook-Seite angegeben werden, um Posts dieser Seite zu erheben. Mit optionalen Parametern werden zusätzliche Einstellungen getätigt, beispielsweise die Eingrenzung der Zeiträume oder bei der Erhebung von Kommentaren, ob diese chronologisch oder nach Relevanz sortiert ausgegeben werden sollen.

Auch die Paginierung wird häufig über Query-Parameter umgesetzt. Wenn Sie mit Google etwas suchen, erhalten Sie in der Regel nicht alle Ergebnisse auf einmal zurück, sondern nur eine Seite mit den ersten Treffern, andernfalls wäre das Ergebnis kaum zu handhaben. Auch die Anfrage an eine API gibt in der Regel nicht alle Daten auf einmal zurück, sondern immer nur eine einzelne Seite. Das konkrete Vorgehen, um weitere Ergebnisse oder Seiten zu erhalten, unterscheidet sich von API zu API. Häufig kann die Anzahl der Ergebnisse auf einer einzelnen Seite über Parameter wie limit=10 oder limit=100 gesteuert werden und verschiedene Seiten werden über Parameter wie page=1 oder page=2 angefragt. Eine Alternative ist die cursor-basierte Paginierung: Bei jeder Anfrage wird dazu ein festgelegter Parameter aus der vorangegangenen Anfrage mitgeschickt (der Cursor), sodass die API erkennt, ab welchem Datensatz die Ergebnisliste fortgesetzt werden muss.

Bei jedem Aufruf einer URL werden zudem Anfrage-Header an den Server geschickt. Diese enthalten weitere Informationen zur Verarbeitung, sind im Gegensatz zu den Parametern aber nicht in der URL sichtbar. Die Header enthalten unter anderem Angaben zum verwendeten Client, dem sogenannten User Agent. Schauen Sie sich einmal in der Entwicklerkonsole eines Browsers an, welche Header beim Surfen im Web mitgeschickt werden.Footnote 20 Auch wenn eine API verschiedene Datenformate wie JSON oder XML (siehe Kap. 3) unterstützt, kann ein Client das gewünschte Format mitunter über den Accept-Header angeben, beispielsweise mit Accept: application/json.

Die Methode der Anfrage teilt dem Server mit, welche Operation auf der angefragten Ressource ausgeführt werden soll. Sie wird über sogenannte HTTP-Verben angegeben, unter anderem:

  • GET: Daten von einer Ressource werden gelesen bzw. abgefragt.

  • POST: Daten werden zu einer Ressource auf einem Server geschickt, um sie dort zu speichern.

  • DELETE: Die Ressource soll gelöscht werden.

Bei der Interaktion mit APIs sind im wissenschaftlichen Kontext besonders die Methoden GET und POST üblich. Mit POST werden umfangreichere Daten als sogenannte Payload übertragen – zum Beispiel, wenn Audiodateien oder Bilddateien bei einer Anfrage mitgeschickt werden sollen.

2.2 Output: Die Antwort einer API

Nicht jede Anfrage an einen Server ist erfolgreich: Wenn Zugriffsrechte fehlen, die URL oder andere Elemente der Anfrage falsch formatiert sind oder eine Ressource nicht (mehr) existiert, quittiert dies der Server mit einem entsprechenden Statuscode (Tab. 7.2). Im besten Fall finden sich in der Antwort des Servers weitere Informationen zur Fehlerquelle, etwa welcher Parameter der Anfrage nicht korrekt angegeben wurde. Die Antwort enthält auch Response-Header, in denen manchmal kurze Hinweise auf fehlende Zugriffsrechte erläutert werden.

Tab. 7.2 Typische Statuscodes beim Umgang mit APIs

War die Anfrage erfolgreich, werden die angefragten Daten im Response Body zurückgegeben und können auf dem Client abgespeichert werden. Ein typisches Datenformat dafür ist JSON (ausführlich siehe Abschn. 3.5). Im JSON-Format werden Daten als Objekte in geschweiften Klammern {} zurückgegeben. Objekte enthalten wiederum Schlüssel-Wert-Paare: Die Bezeichnung eines Feldes wird in Anführungszeichen angegeben, es folgen ein Doppelpunkt und danach der Inhalt des Feldes. Mehrere Objekte in einer Liste werden in eckigen Klammern [] zusammengefasst.

Abb. 7.5 zeigt die Profilinformationen einer Facebook-Seite, wie sie im Browser angezeigt und von einer API als JSON-Objekt zurückgegeben werden. Praktisch an API-Daten ist, dass diese immer identisch strukturiert sind, egal welche Facebook-Seite abgefragt wird. Auch wenn andere Facebook-Seiten abgefragt werden, lässt sich über den Schlüssel description immer die Seitenbeschreibung und über den Schlüssel location immer die hinterlegte Ortsangabe der jeweiligen Facebook-Seite auslesen. Finden Sie im Beispiel, über welchen Schlüssel die Anzahl der Personen, denen die Seite gefällt, angegeben wird? Durch diese Strukturierung lassen sich Daten leicht in ein Tabellen-Format überführen, das sich wiederum gut für weitere Analysen eignet (Abb. 7.6). Dabei werden die Schlüssel als Spalten verwendet und jedes Objekt wird in einer eigenen Zeile abgebildet. Die Werte wiederum sind in den entsprechenden Zellen zu finden.

Abb. 7.5
figure 5

Inhalt einer Facebook-Seite im Browser und als JSON-Format. (Quelle: eigene Darstellung)

Abb. 7.6
figure 6

Likes einer Facebook-Seite im JSON-Format und als Tabelle. (Quelle: eigene Darstellung)

2.3 Zugang zu APIs: Authentifizierung und Rate Limits

APIs sind häufig zugangsbeschränkt, zunächst muss man sich deshalb bei einem Dienst registrieren und für die API freischalten lassen. Dazu stellen Social-Media-Plattformen wie Facebook oder Twitter und auch Cloud-Computing-Dienstleister wie Google oder Amazon eigene Portale für Entwickler:innen zur Verfügung. Hier registriert man eine App oder ein Projekt, womit aber keine tatsächlich fertig programmierte Anwendung gemeint ist, sondern lediglich ein Konto bei dem jeweiligen Dienst. Über diese App erhält man Zugangsdaten zur API, wobei insbesondere zwei Verfahren verbreitet sind:

  • Im einfachsten Fall erhält man direkt ein Access Token, das wie ein Passwort funktioniert und bei Anfragen an die API als Parameter an die URL angehängt oder im Header der Anfrage (siehe oben) mitgeschickt wird.

  • Viele Anbieter setzen auf das OAuth-Protokoll (Open Authorization), das Login-Prozeduren für ganz unterschiedliche Szenarien beinhaltet. Wenn Sie sich beispielsweise mit einem Facebook-Konto auf der Seite eines Onlineshops anmelden können, wird dies über OAuth abgewickelt. Hier kommen drei Parteien zusammen: Facebook vermittelt an den Shop im Namen der Nutzer:innen den Zugriff auf die bei Facebook hinterlegten Daten, zum Beispiel die E-Mailadresse, sodass der Shop-Betreiber keine eigene Registrierung anbieten muss. Um eine solche Schnittstelle zu benutzen, erhält man vom API-Betreiber eine Client ID und ein Client Secret. Mit diesen Daten kann dann ein Access Token erzeugt werden, das wiederum in jeder Anfrage an die API mitgeschickt wird.

Wie die Registrierung funktioniert, ist üblicherweise auf der Webseite der jeweiligen API dokumentiert.Footnote 21 Dort finden sich auch Angaben dazu, welche Daten überhaupt abgefragt werden können. Eine wichtige Limitation sind die sogenannten Rate Limits. Damit begrenzt beispielsweise Twitter, wie schnell die Follower eines Twitterprofils abgefragt werden können: In der Standard-API ist dies aktuell auf 15 Abfragen innerhalb eines Zeitfensters von 15 Minuten begrenzt. Will man direkt die Namen der Follower erheben (GET followers/lists), so werden in einer Abfrage bis zu 200 Follower zurückgegeben. Ein anderer Endpunkt (GET followers/ids) liefert pro Abfrage die IDs von bis zu 5000 Followern, allerdings ohne Namen und weitere Profilinformationen.Footnote 22 Gerade bei größeren Projekten, in denen man viele Daten über eine API erheben will, sollte man sich deshalb mit den Ratenbegrenzungen und möglichen Kombinationen von Abfragen auseinandersetzen.

Teilweise können höhere Rate Limits auch über Zugänge zu einer Premium API oder Enterprise API gekauft werden, hier finden sich sowohl pauschale Preismodelle als auch Modelle, in denen einzelne Abfragen abgerechnet werden. Google erlaubt beispielsweise aktuell für die automatisierte Bilderkennung pro Monat 1000 kostenlose Abfragen, für jedes weitere Paket von 1000 Anfragen werden anschließend 1,50 Dollar berechnet.Footnote 23 Einige Anbieter wie Twitter und Facebook stellen mittlerweile für wissenschaftliche Forschungsprojekte kostenlose oder erweiterte API-Zugänge zur Verfügung. Bei der Registrierung müssen dazu allerdings Begutachtungsverfahren durchlaufen werden – die Anbieter bestimmen selbst, welche Projekte sie genehmigen und welche nicht.

2.4 Tools für die Datenerhebung mit APIs

Ist der Zugang zur API geklärt, ist die Arbeit mit einer API trotz der vielen bislang besprochenen Details im Wesentlichen einfach und unterscheidet sich kaum vom normalen Surfen im Web: Eine URL wird zusammengesetzt, aufgerufen und das Ergebnis wird abgespeichert. Sie können URLs für API-Anfragen also durchaus manuell zusammenstellen (sofern keine Authentifizierung nötig ist). Wenn Sie diese URLs in den Browser eintippen, sollten Sie die Daten der Abfrage angezeigt bekommen und können diese herunterladen, abspeichern und anschließend aufbereiten und auswerten.

Zum Ausprobieren oder für eine einmalige Anfrage mag die manuelle Vorgehensweise hilfreich sein. Soll eine API aber automatisiert genutzt werden, gibt es weitere Möglichkeiten, an denen Sie ansetzen können:

  • Mit dem Tool cURL (Stenberg 2022) können Sie die Anfragen über die Kommandozeile formulieren. In R helfen besonders die Pakete httr zum Senden von Anfragen (Wickham 2022a) und jsonlite (Ooms 2014), um die heruntergeladenen Daten in lesbare Datensätze umzuwandeln. Entsprechende Python-Packages sind requests (Reitz 2022) und json (Python Software Foundation 2022c).

  • Für einige APIs finden sich fertige Packages für Python oder R, die speziell auf eine bestimmte API zugeschnitten sind und eine Vielzahl von gut dokumentierten Funktionen implementieren. Um beispielsweise auf die Twitter-API zuzugreifen, lassen sich in R die Packages rtweet (Kearney 2019) oder twitterR (Gentry 2015) bzw. in Python das Package Tweepy (Roesslein 2020) verwenden.

  • Anbieter von Social-Media-Plattformen oder Cloud-Computing-Diensten stellen sogenannte Software Development Kits (SDKs) für verschiedene Programmiersprachen wie JavaScript, PHP, Java oder Python sowie für Betriebssysteme wie Android oder iOS bereit. Damit lassen sich zum Beispiel auf diese Plattformen zugeschnittene Smartphone-Apps (native Anwendungen) bauen.

Darüber hinaus gibt es zahlreiche kommerzielle Dienste oder Tools mit Benutzeroberflächen, über die APIs bedient werden können. Wenn Sie bislang keine Programmierkenntnisse haben und einen schnellen Einstieg in die Datenerhebung über APIs erleben wollen, sind Tools mit Benutzeroberfläche eine gute Option. Darüber können Sie Abfragen relativ einfach zusammenklicken. Eine Vielzahl von Prozessen läuft dabei automatisch im Hintergrund ab und wird von den Programmen für Sie erledigt. Sie sollten sich nach und nach ein Grundverständnis dieser Prozesse erarbeiten. Als universelle Lösungen können Sie zum Beispiel das speziell für den Einstieg in die automatisierte Datenerhebung entworfene FacepagerFootnote 24oder das bei Programmierer:innen beliebte PostmanFootnote 25 einsetzen. In den folgenden Kapiteln werden einmal mit Facepager die Erhebung von Twitter-Daten und einmal mittels des R-Package googleCloudVisionR (Pal et al. 2020) die automatisierte Bilderkennung über Google illustriert.

2.5 Social-Media-Daten über Facepager erheben: Followees eines Twitter-Accounts

Facepager ist ein Open-Source-Tool für die automatisierte Datenerhebung mittels APIs und Webscraping. Das Programm ist besonders für Anfänger lohnend, da keine Programmierkenntnisse notwendig sind und weil es einige Einstiegshilfen bereitstellt. Vor allem eine Erhebung von Daten über die APIs von Facebook, YouTube und Twitter ist über die dafür zugeschnittenen Module unkompliziert, sofern man Zugang zur API der jeweiligen Plattform hat. Das folgende Beispiel verdeutlicht das Prinzip, das sich dann auf andere APIs übertragen lässt. Weitere Möglichkeiten sind im ☛ Repositorium des Buchs aufgeführt.Footnote 26 Weitere APIs können über das universellere Generic Modul abgefragt werden. Für den allerersten Einstieg sind die Getting-Started-Anleitungen im Wiki von Facepager zu empfehlen.Footnote 27 Dort finden sich auch Hinweise zur Auswertung der erhobenen Daten oder ausführliche Erklärungen zu den einzelnen Einstellungen von Facepager. Im zweiten Schritt helfen die Presets weiter, um für einige Szenarien die nötigen Voreinstellungen zu übernehmen, darin sind ebenfalls Erklärungen der notwendigen Schritte zu finden.

Das Layout von Facepager ist in Abb. 7.7 zu sehen. In der Menü-Leiste sind einige der wichtigsten Funktionen aufgeführt, vor allem das Erstellen neuer Datenbanken oder das Hinzufügen von neuen Knoten (engl. nodes) – so werden in Facepager die einzelnen Datensätze wie etwa Posts oder Kommentare bezeichnet. Über das Query Setup können die verschiedenen Module ausgewählt und alle notwendigen Einstellungen für die Abfrage vorgenommen werden. Im Nodes View sind alle Datenknoten tabellarisch aufgelistet, wobei jeder Knoten eine Object ID enthält. Wenn man einen Knoten anklickt, sieht man im Data View die gesamten erhobenen Daten zu einem Knoten. Über das Column Setup kann festgelegt werden, welche dieser Daten in eigenen Spalten angezeigt und exportiert werden sollen. Das Status Log zeigt während der Erhebung den aktuellen Fortschritt und Fehlermeldungen an.

Abb. 7.7
figure 7

Layout von Facepager. (Quelle: eigene Darstellung)

Wie diese einzelnen Elemente zusammenspielen, wird nachfolgend anhand eines Beispiels beschrieben, bei dem die Followees von Twitter-Profilen (Profile, denen ein Profil folgt) abgefragt werden. Eine solche Erhebung kann Grundlage für Netzwerkanalysen sein, um die Verbindungen zwischen verschiedenen Organisationen oder die Diskursgemeinschaften zu aktuellen Themen sichtbar zu machen (siehe Kap. 10). Allerdings: Auch wenn APIs relativ stabil sind und das Programm fortlaufend an aktuelle Entwicklungen in der Online-Welt angepasst wird, wenn Sie das hier lesen, kann sich die Situation schon wieder geändert haben und möglicherweise sind einige Plattformen nicht mehr frei Haus zugänglich oder die unten beschriebenen Mausklicks funktionieren nicht mehr auf die gleiche Weise. Im Zweifelsfall lohnt es sich immer, die aktuellen Dokumentationen der APIs oder verwendeten Tools direkt anzusehen – diese werden üblicherweise von den Betreibern auf dem aktuellen Stand gehalten.

Die grundsätzliche Vorgehensweise bleibt immer gleich: Zunächst muss man sich mit der API vertraut machen. Dann werden Startpunkte festgelegt, in diesem Fall ein Twitter-Profil, und die Einstellungen werden angepasst. Schließlich können die Daten erhoben und exportiert werden.

Schritt 1: Installation und Datenbank anlegen

Installieren Sie sich die aktuelle Version von Facepager, indem Sie der für Ihr System passenden Anleitung auf GitHub folgen.Footnote 28 Dort werden Installationsdateien für Windows und Mac bereitgestellt. Facepager wurde mit Python entwickelt – unter Linux (und auch sonst) können Sie Facepager aus dem Quellcode laufen lassen, haben dann aber keine vorregistrierten Zugänge zu den Social-Media-Plattformen.

Öffnen Sie Facepager und legen sie über New Database (in der Menüleiste) eine neue Datenbank an. In dieser werden alle erhobenen Daten gespeichert. Facepager sichert dabei den Stand der Datenbank fortlaufend automatisch – Sie müssen nicht extra speichern.

Schritt 2: Preset laden und Einstellungen anpassen

Um einen schnellen Einstieg in die Datenerhebung zu bekommen, können Sie ein bereits angelegtes Preset über den Menüpunkt Presets laden. Um die Twitter-Follower eines Profils zu erheben, von dem Sie den Namen kennen, wird zunächst die ID des Profils benötigt. Dazu können Sie das Preset „Lookup user data“ für die API-Version 2 laden.Footnote 29 Bevor Sie auf Apply klicken, lesen Sie sich zunächst die Beschreibung des Presets durch. Hier sind die Funktionsweise und weitere Einstellungsmöglichkeiten beschrieben. Außerdem ist die offizielle Dokumentation des Endpunktes verlinkt. Sobald Sie das Preset anwenden, werden alle grundlegenden Einstellungen in das Query Setup (Abb. 7.8) übertragen.

Abb. 7.8
figure 8

Einstellungen zur Erhebung von Profilinformationen auf Twitter. Der Platzhalter <Object ID> wird bei der Erhebung durch den Startknoten ersetzt. (Quelle: eigene Darstellung)

Aus den Angaben im Query Setup baut Facepager selbstständig die URL für die Abfrage zusammen, indem Base path, Resource und Parameter aneinandergesetzt werden. Ein Grundprinzip von Facepager ist dabei die Arbeit mit Platzhaltern. Diese werden in spitzen Klammern < > angegeben und während der Datenabfrage durch Werte aus den Nodes ersetzt. Wenn man mehrere Nodes hinzufügt oder bereits erhoben hat, können Erhebungsschritte automatisiert werden, indem nacheinander bei gleichbleibenden Einstellungen immer andere Nodes-Daten in die Platzhalter eingefügt werden. In Abb. 7.8 werden zwei Platzhalter verwendet: <Object ID> wird durch den Wert uni_greifswald ersetzt und der Platzhalter <username> wird wiederum durch <Object ID> ersetzt.Footnote 30 Im Ergebnis wird über die gesetzten Einstellungen folgende URL zusammengebaut:

https://api.twitter.com/2 /users/by/username/uni_greifswald ?user.fields=id%2Cname%2Cusername%2Cdescription

Die %2C-Zeichen kodieren dabei das Komma, diese sogenannte Prozentkodierung (engl. percent encoding) wird für Sonderzeichen in URLs verwendet (siehe Abschn. 2.1). Wie die einzelnen Bausteine der URL aussehen müssen und welche zusätzlichen Angaben möglich wären, sind der offiziellen Dokumentation von Twitter zu diesem Endpunkt entnommen (Abb. 7.9). Dort können Sie sehen, dass die Angaben unter „Endpoint URL“ in Facepager auf den Base path und die Ressource aufgeteilt werden und dass der Pfad einen mit Doppelpunkt gekennzeichneten Platzhalter für den Benutzernamen enthält. Die Angaben zum Parameter „user.fields“ sind aus den optionalen Query-Parametern in der Dokumentation zu entnehmen. Öffnen Sie die Dokumentation einmal selbst und finden Sie heraus: Wie können Sie erheben, zu welchem Zeitpunkt der Account erstellt wurde?Footnote 31 Sobald Sie solche Dokumentationen verstehen, können Sie sich selbst beliebige Anfragen zusammenbauen.

Abb. 7.9
figure 9

Dokumentation eines Endpunkts zur Abfrage von Profilinformationen (gekürzt). (Quelle: Twitter (2022e; https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by-username-username))

Schritt 3: Authentifizierung

Um die API nutzen zu können, müssen Sie sich zunächst authentifizieren.Footnote 32 Dieser Prozess gestaltet sich je nach API und teils sogar je nach Version der API unterschiedlich. Das Preset im Beispiel nutzt die zweite Version der API, bei der Sie selbst eine App registrieren müssen. Eine App zu registrieren bedeutet dabei nicht – auch wenn es zunächst so aussieht –, dass Sie unbedingt selbst ein Programm schreiben müssen. Stattdessen kann das wörtlich verstanden werden, dass sie also eine Applikation und damit die Verwendung oder den Gebrauch bei Twitter registrieren. Dies können Sie auf der Seite für Entwickler:innen von Twitter beantragen, wobei der Anwendungsfall zunächst von Twitter geprüft wird.Footnote 33

Nachdem Sie einen Zugang erhalten haben, tragen Sie im Query Setup unter Settings im Feld Client Id den erhaltenen API key und im Feld Client Secret den API secret key ein. Wenn Sie anschließend auf Login klicken, sollte automatisch ein persönliches Access Token generiert werden. Da dieses wie ein geheimes Passwort funktioniert, mit dem Sie die API abfragen, sind die einzelnen Zeichen in Facepager durch schwarze Punkte ersetzt.

Schritt 4: Startpunkte hinzufügen

Um nun Daten zu erheben, fügen Sie über Add Nodes die Namen eines oder mehrerer Twitter-Profile als Startknoten (engl. seed node) hinzu. Social-Media-Accounts haben nicht nur einen Namen wie „Uni Greifswald“, sondern werden häufig über ein Handle identifiziert. Das Handle eines Profils wird in der URL sichtbar, wenn man das Profil im Browser betrachtet – es handelt sich in diesem Fall um den Teil, der direkt nach der Domain folgt: https://twitter.com/uni_greifswald. Darüber hinaus werden Profile über numerische IDs identifiziert, die für jeden Account einzeln vergeben werden und die häufig nicht über den Browser sichtbar sind. Inwiefern für eine Abfrage das Handle oder die ID benötigt wird, ist in der Dokumentation festgelegt. Die Abfrage der Profilinformationen funktioniert mit dem Handle als Input, in den Profilinformationen ist die ID enthalten, mit der dann die Abfrage der Followees gelingt.

Schritt 5: Daten erheben

Um nun die Daten zu erheben, klicken Sie zunächst den Knoten im Nodes View an (hier den Knoten „uni_greifswald“). Wenn Sie mehrere Knoten hinzugefügt haben, können Sie über Select all nodes im Query Setup auch alle Knoten gleichzeitig auswählen. Haben Sie die gewünschten Knoten ausgewählt, klicken Sie auf Fetch Data. Im Status Log können Sie beobachten, wie nun die URLs für die Abfrage zusammengebaut und die einzelnen Daten erhoben werden.

Die neuen Daten werden den Startknoten untergeordnet. Klappen Sie die Startknoten auf, indem Sie auf den Pfeil links neben dem Knoten oder auf Expand all nodes klicken. Sobald Sie einen Knoten ausgewählt haben, können Sie im Data View alle erhobenen Daten inspizieren (Abb. 7.10).

Abb. 7.10
figure 10

Schritte nach der Datenerhebung mit Facepager: Daten inspizieren und Spalten anpassen. (Quelle: eigene Darstellung)

Über das Column Setup passen Sie an, welche Spalten im Data View angezeigt und später exportiert werden (Abb. 7.10). Wenn Sie ein Preset geladen haben, sind bereits einige Spalten voreingestellt. Wollen Sie diese entfernen, klicken Sie auf Clear Columns. Einzelne Spalten fügen Sie hinzu, indem sie ein Key-Value-Paar im Data View auswählen und auf Add Column klicken. Der Schlüssel dieses Paares wird dadurch eine Spalte in der Tabelle im Nodes View. Wollen Sie alle Schlüssel hinzufügen, klicken Sie auf Add All Columns. Nachdem Sie die gewünschten Spalten ausgewählt und hinzugefügt haben, müssen Sie noch abschließend über Apply Column Setup die angepassten Spalten bestätigen. Scrollen Sie nun in der Nodes View nach rechts, dann sehen Sie die zusätzlichen Spalten.Footnote 34

Wenn Sie nun die ID eines Twitter-Profils haben, können Sie die Followees dieses Profils erheben. Laden Sie dafür im nächsten Schritt das Twitter-Preset „Get followees“ (siehe Schritt 4). Bevor Sie auf Fetch Data klicken, kontrollieren Sie noch das Node level. Während sich das hinzugefügte Twitter-Handle auf der obersten Ebene (level 1) befindet, liegt die ID der vorherigen Abfrage auf der zweiten Ebene (level 2). Entweder markieren Sie für die Abfrage der Followees den Knoten mit der ID oder – insbesondere wenn Sie mehrere Startknoten eingefügt haben – Sie setzen in den Settings neben dem Query Setup das Häkchen bei Select all nodes und stellen das Node level auf 2 ein. Mit Fetch Data wird anschließend die Abfrage für alle Knoten auf der zweiten Ebene ausgeführt.

Schritt 6: Daten exportieren

Überprüfen Sie nach der Erhebung, ob Sie weitere Spalten hinzufügen wollen. Um die Daten zu exportieren, wählen Sie dann die gewünschten Knoten aus und klicken auf Export Data. Wenn Sie alle Knoten exportieren wollen, können Sie das direkt im Exportfenster angeben. Dort navigieren Sie zum Arbeitsverzeichnis, legen einen Namen fest und speichern so die erhobenen Daten als CSV-Datei. CSV-Dateien enthalten tabellarische Daten, die mit allen gängigen Statistikprogrammen oder auch mit Tabellenprogrammen wie Excel, Numbers oder Calc eingelesen werden können (siehe Abschn. 3.3).

2.6 Automatische Bilderkennung über eine Cloud-API

Tools wie Facepager bieten eine grafische Bedienoberfläche an, sind für vielfältige APIs nutzbar und enthalten hilfreiche Funktionen etwa für umfangreichere Erhebungen und zur Parallelisierung von Anfragen. Gleichzeitig können Sie aus den Fehlern, die dabei unweigerlich auftreten, etwas über die einzelnen nötigen Schritte lernen und machen sich mit den Dokumentationen von APIs vertraut. Eine Alternative dazu stellen Packages für R oder Python dar, die auf ganz bestimmte APIs zugeschnitten sind. Sie finden solche Packages etwa für die Erhebung von Twitter- oder Telegramdaten und viele andere Social-Media-Plattformen, aber auch für die Analyse und Aufbereitung von Daten. Eine Vielzahl von Anbietern stellt APIs für die automatische Bilderkennung, die Geokodierung von Adressen oder die Sentimentanalyse von Texten zur Verfügung, die über entsprechende Packages verwendet werden können. Bilderkennung können Sie beispielsweise über die Google Cloud Vision API durchführen (Google 2022d). Auch wenn dazu im Hintergrund eine Vielzahl von Schritten nötig ist – die Authentifizierung beim Anbieter, das Hochladen der Bilder, das Formulieren der API-Anfrage, das Abrufen der Ergebnisse – lässt sich diese API beispielsweise über das R-Package googleCloudVisionR mit nur zwei Befehlen benutzen.

Etwas aufwendiger ist lediglich die Ersteinrichtung, denn um die API nutzen zu können, müssen Sie sich zunächst in der Google Cloud Console registrieren.Footnote 35 Die Nutzung von Clouddiensten ist in der Regel kostenpflichtig, allerdings werden häufig Freikontingente gewährt. Aktuell sind über die Google Cloud Vision API die ersten 1000 Abfragen je Monat kostenlos, behalten Sie dennoch die Kosten im Blick. Nach der Registrierung erstellen Sie in der Weboberfläche ein Projekt und aktivieren die Cloud Vision API. Im API-Bereich des Projekts erstellen Sie dann Anmeldedaten – das folgende Beispiel geht davon aus, dass Sie einen Schlüssel für ein sogenanntes Dienstkonto erstellen und auf Ihren Computer herunterladen. Die Anmeldung kann über das Package googleAuthR (Edmondson 2022) erfolgen, wobei Sie den Pfad zum Anmeldeschlüssel angeben:

library(googleAuthR) gar_auth_service(json_file="E:/googlekey.json")

Prinzipiell kann das Login auch über andere Wege wie OAuth oder über Access Token erfolgen. Anschließend reicht mit dem Package googleCloudVisionR ein einziger Befehl, um ein Bild von dem eigenen Computer an die API zu schicken (imagePaths-Parameter) und daraufhin das Ergebnis der Erkennung zu erhalten:

library(googleCloudVisionR) gcv_get_image_annotations( imagePaths = "schmetterling.jpg", feature = "LABEL_DETECTION", maxNumResults = 6 )

Die API gibt nicht nur Bezeichnungen (engl. label) für die verschiedenen erkannten Objekte zurück, sondern auch zwei Kennwerte, mit denen die Erkennungsleistung eingeschätzt werden kann. Der Score gibt auf einer Skala von 0 bis 1 an, mit welcher Sicherheit das Objekt erkannt wurde und die Topikalität sagt aus, wie zentral das Objekt im Bild ist. Im Beispiel in der Abb. 7.11 wird mit einer recht hohen Sicherheit ein brauner Schmetterling identifiziert, der das zentrale Bildmotiv darstellt. Zusätzlich wird ein eindeutiger Bezeichner (mid) zurückgegeben, der für weitere Abfragen des Google Knowledge Graph verwendet werden kann. Der Google Knowledge Graph basiert auf Semantic-Web-Technologie (siehe Abschn. 3.7) und verknüpft mittels festgelegter IDs und Vokabularen eine Vielzahl an Begriffen und Wissensbeständen.

Abb. 7.11
figure 11

Das Ergebnis der Google Bilderkennung. (Quelle: Middelbos (2020))

Eine API kann somit nicht nur für die Datenerhebung, sondern auch für die Vorsortierung und Aufbereitung von Daten hilfreich sein. Nach der ersten Einrichtung lassen sich auf diese Weise komplexe Analysen wie die automatische Transkription von Audioaufnahmen, die Bilderkennung oder auch die Erkennung von Hate-Speech mit beeindruckend wenig Aufwand durchführen. Die Güte der Ergebnisse hängt wesentlich von der Qualität des Ausgangsmaterials und von der Datengrundlage, mit der ein Anbieter das Erkennungsmodell trainiert hat, ab und sollte entsprechend immer überprüft werden (siehe Kap. 8). Das aber gilt grundsätzlich, wenn Sie mit automatisierten Verfahren der Datenerhebung und -analyse arbeiten.

Übungsfragen

  1. 1.

    Sie wollen die Likes einer Facebook-Seite über die Facebook-Graph-API mithilfe von Facepager erheben. Dafür fügen Sie „Universität Greifswald“ als neuen Knoten hinzu und laden ein entsprechendes Preset. Wieso kann diese Abfrage nicht funktionieren?

  2. 2.

    Finden Sie heraus: Wie viele Tweets können gleichzeitig mit einer Abfrage des Endpunktes GET statuses/user_timeline erhoben werden? Wie viele Tweets können Sie pro Tag maximal erheben?Footnote 36

  3. 3.

    Was ist mit der Paginierung von Anfragen gemeint?

  4. 4.

    Was versteht man unter Ratenlimitierungen (engl. rate limits)?

  5. 5.

    Was ist ein Access Token und wie erhalten Sie ein Access Token?

Weiterführende Literatur

  • Magallanes Reyes, J. M. (2017). Introducing data science for social and policy research. Collecting and organizing data with R and Python. Cambridge: Cambridge University Press.

  • Mitchell, R. (2018). Web scraping with Python. Collecting more data from the modern we(2. Aufl.). Sebastopol: O’Reilly.

  • Munzert, S., Rubba, C., Meißner, P. & Nyhuis, D. (2015). Automated data collection with R: A practical guide to web scraping and text mining. Chichester: Wiley.

  • Nyhuis, D. (2021). Application programming interfaces and web data for social research. In: U. Engel, A. Quan-Haase, S. X. Liu & L. Lyberg (Hrsg.), Handbook of Computational Social Science, Volume 2 (S. 33–45). London: Routledge.

  • Russell, M. A. (2014). Mining the social web. Data mining Facebook, Twitter, Linkedin, Google+, GitHub, and more. (2. Aufl.). Sebastopol: O’Reilly.