HTML-Tabellen sind die Art, wie das Web seine analysefertigsten Daten speichert: Aktienlistings, Sportergebnisse, Bevölkerungszahlen, Produktvergleiche, historische Aufzeichnungen. Eine Tabelle auf einer öffentlichen Seite besteht bereits aus Zeilen und Spalten, daher ist der schwierige Teil selten die Analyse. Es ist das saubere und wiederholbare Abrufen der Daten von der Seite in ein Tool, mit dem man arbeiten kann, ohne Zellen von Hand zu kopieren.

Dieser Leitfaden zeigt drei Wege, um Tabellen von einer Website zu scrapen, jeweils für ein anderes Kenntnisstandsniveau und einen anderen Arbeitsablauf geeignet: eine No-Code-Google-Sheets-Formel, einige Zeilen Python mit pandas und ein R-Skript mit rvest. Das laufende Beispiel ist eine öffentliche Wikipedia-Tabelle, die sich gut eignet, da die Daten offen und das Markup sauber ist. Alle hier beschriebenen Methoden beschränken sich auf öffentliche Daten, und der kurze Abschnitt zum verantwortungsvollen Scrapen gegen Ende ist es wert, gelesen zu werden, bevor man das auf eine echte Quelle richtet.

Was du bauen wirst

Am Ende gibt es drei funktionierende Wege, eine öffentliche Tabelle in ein nutzbares Format zu überführen. Jeder zielt auf dieselbe Art von Quelle ab, eine HTML-<table> auf einer öffentlichen Seite, und erzeugt dieselbe Art von Ausgabe: ein sauberes Raster, das sortiert, gefiltert oder exportiert werden kann. Die Komponenten, die entstehen werden:

  • Eine Google-Sheets-Formel, die eine Live-Tabelle mit einem IMPORTHTML-Aufruf importiert, kein Code erforderlich.
  • Ein Python-Skript, das Tabellen mit pandas.read_html in einer Zeile liest, mit einem BeautifulSoup-Fallback für unordentliches Markup.
  • Ein R-Skript, das Tabellen mit der html_table-Funktion von rvest in einen Data Frame extrahiert.
  • Eine saubere tabellarische Ausgabe aus jeder Methode, bereit zum CSV-Export oder zur Einspeisung in die Analyse.

Warum manche Tabellen mehr als eine einfache Anfrage benötigen

Für eine saubere, serverseitig gerenderte Seite wie die meisten Wikipedia-Seiten funktionieren alle drei unten beschriebenen Methoden direkt: das Tabellen-Markup ist bereits im HTML vorhanden, daher zieht eine Formel oder ein einzeiliges Lesen es direkt heraus. Das ist der einfache und häufige Fall, und damit sollte man beginnen.

Die Schwierigkeiten beginnen bei Quellen, die die Tabelle nicht so bereitwillig übergeben. Zwei Probleme tauchen am häufigsten auf. Erstens bauen manche Sites ihre Tabellen mit JavaScript auf, nachdem die Seite geladen ist, sodass das abgerufene rohe HTML die gesuchten Zeilen nicht enthält. Zweitens beobachten viele Sites Scraper-artigen Traffic und ratenbegrenzen oder blockieren Anfragen von Rechenzentrum-IPs nach den ersten paar Treffern. Wenn beides passiert, gibt IMPORTHTML einen Fehler zurück, und ein einfaches requests.get in Python gibt eine Block-Seite oder leeres Markup zurück statt der Tabelle.

Die Lösung für beide ist dieselbe: die Seite über einen Browser abrufen, der seine Skripte ausführt, von einer IP, die die Site als echten Besucher einstuft. Das kann man selbst mit einem rotierenden IP-Pool und einem Headless-Browser zusammenstellen, aber das ist der Großteil der Arbeit. Im Python-Abschnitt verwenden wir die Crawling API genau für diese blockierten oder JavaScript-gerenderten Quellen, während der einfache Weg für alles beibehalten wird, was ihn nicht benötigt.

Voraussetzungen

Was benötigt wird, hängt davon ab, welche Methode gewählt wird. Keine davon dauert lange einzurichten.

Für Google Sheets: nur ein Google-Konto und ein Browser. Es gibt nichts zu installieren.

Für Python: Python 3.8 oder neuer. Die Version mit python --version prüfen. Man sollte in der Lage sein, ein Skript auszuführen und Pakete mit pip zu installieren. Wer mit dem Parsen von HTML noch nicht vertraut ist, findet in unserem Leitfaden zur Verwendung von BeautifulSoup in Python die Grundlagen, die dieser Abschnitt voraussetzt.

Für R: eine aktuelle R-Installation (4.0 oder neuer ist gut) und die Möglichkeit, Pakete von CRAN zu installieren.

Für blockierte oder JavaScript-gerenderte Quellen: ein Crawlbase-Konto und Token. Anmelden, das Dashboard öffnen und den normalen Token kopieren. Den Token wie ein Passwort behandeln und aus der Versionskontrolle heraushalten. Das wird nur für den Python-Pfad benötigt, wenn eine einfache Anfrage fehlschlägt.

Methode 1: Google Sheets mit IMPORTHTML

Der schnellste Weg, eine Tabelle von einer öffentlichen Seite zu bekommen, benötigt überhaupt keinen Code. Google Sheets hat eine eingebaute IMPORTHTML-Funktion, die eine Seite abruft, eine Tabelle oder Liste nach Index findet und sie als Live-Zellen in die Tabelle einfügt. Sie aktualisiert sich sogar von selbst, sodass die Daten aktuell bleiben.

Eine neue Tabelle öffnen, auf eine leere Zelle klicken und die Formel eingeben. Sie nimmt drei Argumente: die Seiten-URL, ob man eine "table" oder eine "list" möchte, und den Index, welche man nehmen möchte (die erste Tabelle auf der Seite ist 1, die zweite ist 2 usw.).

html
=IMPORTHTML("https://en.wikipedia.org/wiki/List_of_largest_cities", "table", 1)

Enter drücken und Sheets ruft die Seite ab, extrahiert die erste Tabelle und verteilt sie über die Zellen, beginnend dort, wo die Formel eingegeben wurde. Wenn die erste Tabelle nicht die gesuchte ist, den Index erhöhen, bis man die richtige findet; eine Seite hat oft Navigations- oder Infobox-Tabellen vor den Hauptdaten. Sobald die Daten geladen sind, kann man Spalten in der Größe anpassen oder Zellen neu formatieren, und die Formel kann an Ort und Stelle bleiben, damit die Tabelle sich aktualisiert, wenn sich die Quelle ändert.

Wenn IMPORTHTML einen Fehler zurückgibt

IMPORTHTML ruft rohes HTML ab und führt kein JavaScript aus, sodass nur Tabellen gesehen werden, die im Seitenquelltext vorhanden sind. Wenn es #N/A oder ein leeres Ergebnis zurückgibt, wird die Tabelle wahrscheinlich nach dem Laden durch JavaScript aufgebaut, oder die Site hat die Anfrage blockiert. Das sind genau die Fälle, die die Python-Methode mit der Crawling API abhandelt, da sie die Seite rendern und von einer vertrauenswürdigen IP abrufen kann.

Crawlbase Crawling API

Diese IMPORTHTML-Formel funktioniert, weil Wikipedia seine Tabellen als einfaches HTML aus einer offenen Quelle bereitstellt. In dem Moment, in dem eine Tabelle mit JavaScript aufgebaut wird oder hinter Bot-Schutz sitzt, gibt die Formel #N/A zurück, und das gilt auch für eine einfache Python-Anfrage. Die Crawling API rotiert serverseitig durch Residential-IPs, rendert die Seite in einem echten Browser, wenn gewünscht, und übergibt fertiges HTML, damit man selbst keine Headless-Browser-Flotte und keinen Proxy-Pool betreiben muss. Zunächst auf einer öffentlichen Seite im kostenlosen Kontingent testen.

Methode 2: Python mit pandas und der Crawling API

Python ist das Arbeitstier dafür. Für eine saubere öffentliche Tabelle erledigt pandas.read_html fast alles in einer Zeile: eine URL oder einen HTML-Chunk übergeben, und es gibt eine Liste aller Tabellen auf der Seite als Data Frames zurück. Zunächst die Bibliotheken installieren.

bash
python -m venv tables_env
source tables_env/bin/activate

pip install pandas lxml beautifulsoup4 crawlbase

Unter Windows die Umgebung statt mit der source-Zeile mit tables_env\Scripts\activate aktivieren. pandas übernimmt das Tabellen-Lesen, lxml ist der darunter liegende Parser, beautifulsoup4 ist der Fallback für unordentliches Markup, und crawlbase ist der offizielle Client für die Crawling API.

Für eine öffentliche, serverseitig gerenderte Seite ist die einfachste Version wirklich ein einziger Aufruf. Die URL an read_html übergeben und in die zurückgegebene Liste indexieren.

python
import pandas as pd

url = "https://en.wikipedia.org/wiki/List_of_largest_cities"

# read_html returns a list of every table it finds on the page
tables = pd.read_html(url)
print(f"Found {len(tables)} tables")

# pick the one you want by index, then work with it as a DataFrame
df = tables[0]
print(df.head())
df.to_csv("cities.csv", index=False)

Das ist die ganze Arbeit, wenn die Seite kooperiert: read_html scannt das HTML, erstellt für jede <table> einen Data Frame, und man behält den gewünschten und schreibt ihn als CSV. Genau wie der Sheets-Index muss man möglicherweise ein paar Indizes ausprobieren, um die Haupttabelle statt einer Seitenleiste oder eines Navigationsblocks zu finden.

Wenn die Quelle einfache Anfragen blockiert oder ihre Tabelle mit JavaScript aufbaut, das HTML zunächst über die Crawling API abrufen und dann an read_html übergeben. Die einzige Änderung ist, woher das Markup kommt.

python
import pandas as pd
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def fetch_html(url, render=False):
    options = {"country": "US"}
    if render:
        # use the JS token for JavaScript-built tables
        options["ajax_wait"] = "true"
    response = api.get(url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

url = "https://en.wikipedia.org/wiki/List_of_largest_cities"
html = fetch_html(url)

if html:
    tables = pd.read_html(html)
    df = tables[0]
    print(df.head())
    df.to_csv("cities.csv", index=False)

Die country-Option bindet die Anfrage an eine US-Ausgangs-IP, und die Übergabe von render=True weist den Aufruf an, einen JavaScript-Token zu verwenden (hier über ajax_wait), damit die Seite gerendert wird, bevor das HTML empfangen wird. Mit dem Markup zur Hand verhält sich read_html genau wie zuvor. Das ist die Variante, die man einsetzen sollte, sobald der einfache Weg eine Block-Seite oder eine leere Tabellenliste zurückgibt.

Fallback auf BeautifulSoup für unordentliche Tabellen

Manchmal stolpert read_html: eine Tabelle mit zusammengeführten Zellen, kein echtes <table>-Tag, oder Zeilen verstreut über verschachteltes Markup. In diesem Fall auf BeautifulSoup zurückfallen und die Zeilen selbst aufbauen, indem man jede Zelle liest. Das ist derselbe feldweise Ansatz wie in unserem Leitfaden zu CSS-Selektoren, angewandt auf Tabellenzellen.

python
import pandas as pd
from bs4 import BeautifulSoup

def table_to_rows(html, index=0):
    soup = BeautifulSoup(html, "html.parser")
    table = soup.find_all("table")[index]
    rows = []
    for tr in table.find_all("tr"):
        cells = tr.find_all(["th", "td"])
        row = [cell.get_text(strip=True) for cell in cells]
        if row:
            rows.append(row)
    return rows

rows = table_to_rows(html)
df = pd.DataFrame(rows[1:], columns=rows[0])
print(df.head())

Der Helfer geht jedes <tr> durch, liest jedes <th> und <td> als bereinigten Text und überspringt leere Zeilen. Die erste Zeile als Header und den Rest als Daten zu behandeln, liefert einen sauberen Data Frame, auch wenn read_html die Tabelle nicht selbst parsen konnte. Das gleiche Crawling-API-HTML an diesen Helfer übergeben, wenn die unordentliche Tabelle zufällig auch blockiert oder gerendert ist.

Methode 3: R mit rvest

Wenn die Analyse bereits in R stattfindet, muss man R nicht verlassen. Das rvest-Paket liest HTML, und seine html_table-Funktion verwandelt jede Tabelle auf einer Seite in einen Data Frame, ähnlich wie pandas es tut. Das Paket einmalig von der R-Konsole aus installieren.

r
install.packages("rvest")

Mit geladenem rvest die Seite lesen, ihre Tabellen extrahieren und die gewünschte auswählen. Das Muster spiegelt das Python-Muster wider: HTML lesen, Liste der Tabellen erhalten, in die gewünschte indexieren.

r
library(rvest)

url <- "https://en.wikipedia.org/wiki/List_of_largest_cities"

# read the page, then pull every table into a list of data frames
page <- read_html(url)
tables <- page %>% html_elements("table") %>% html_table()

# keep the first table and inspect it
df <- tables[[1]]
head(df)

# write it out for analysis elsewhere
write.csv(df, "cities.csv", row.names = FALSE)

R verwendet doppelte Klammern, tables[[1]], um ein einzelnes Element aus der Liste herauszuziehen, während Python einfache Klammern verwendet. Abgesehen davon ist der Ablauf identisch: die Seite lesen, die Tabellen sammeln, die gewünschte behalten und exportieren. Von hier aus verhält sich der Data Frame wie jeder andere in R, bereit für dplyr, ggplot2 oder einen CSV-Export. Wenn die Quelle den direkten Lesevorgang blockiert, das gerenderte HTML über die Crawling API wie im Python-Abschnitt abrufen und diesen String statt der URL an read_html übergeben.

Wie die Ausgabe aussieht

Welche Methode auch immer verwendet wird, das Ergebnis hat dieselbe Form: ein sauberes Raster mit einer Header-Zeile und einer Zeile pro Datensatz. Als CSV exportiert sieht die Tabelle der größten Städte so aus.

csv
Rank,City,Country,Population,Year
1,Tokyo,Japan,37468000,2018
2,Delhi,India,28514000,2018
3,Shanghai,China,25582000,2018
4,Sao Paulo,Brazil,21650000,2018
5,Mexico City,Mexico,21581000,2018

Die genauen Spalten hängen von der Quelltabelle ab, aber die Struktur ist konsistent: der Header wird zu den Spaltennamen und jede nachfolgende Zeile ist ein Datensatz. Aus einer solchen CSV kann man direkt in eine Tabellenkalkulation, ein Notebook oder eine Datenbank laden, ohne weitere Bereinigung außer der gelegentlichen Typkonvertierung.

Tabellen verantwortungsvoll scrapen

Die obigen Methoden sind einfach auszuführen, was es wert macht, bewusst zu entscheiden, worauf man sie richtet. Die Nutzungsbedingungen und die robots.txt jeder Quelle prüfen, bevor man etwas in großem Umfang sammelt, und wirklich öffentliche Daten bevorzugen (die Art, die ein Besucher ohne Login sieht), gegenüber allem hinter einem Account oder einer Paywall. Anfragen so verteilen, dass ein Server nicht in einer engen Schleife bombardiert wird, und eine offizielle API oder einen veröffentlichten Datensatz nutzen, wenn die Quelle einen anbietet, da das fast immer der leichtere und zuverlässigere Weg ist.

Wenn man eine gescrapte Tabelle weiterveröffentlicht, die Quelle angeben und ihre Lizenz respektieren. Offene Datensätze wie Wikipedia tragen klare Wiederverwendungsbedingungen (Namensnennung unter einer Creative-Commons-Lizenz in diesem Fall), und viele andere Sites erlauben eine Weiterverbreitung überhaupt nicht. Öffentliche Zahlen für die eigene Analyse zu sammeln, ist eine weitaus leichtere Nutzung als die kompilierten Daten eines anderen als eigene weiterzuverbreiten, also im Zweifel auf die Quelle verlinken statt sie vollständig zu kopieren.

Zusammenfassung

Wichtigste Erkenntnisse

  • Das passende Tool für den Arbeitsablauf wählen. Google Sheets IMPORTHTML für No-Code, pandas read_html für Python und rvest html_table für R ziehen eine öffentliche Tabelle in einer Zeile oder zwei.
  • In die Tabellenliste indexieren. Alle drei Methoden geben jede Tabelle auf der Seite zurück; also ein paar Indizes ausprobieren, um die Hauptdaten statt einer Seitenleiste oder eines Navigationsblocks zu finden.
  • Bei unordentlichem Markup auf BeautifulSoup zurückfallen. Zusammengeführte Zellen oder nicht-standardmäßige Tabellen, die read_html brechen, können Zeile für Zeile aus <tr>-, <th>- und <td>-Tags neu aufgebaut werden.
  • Die Crawling API für blockierte oder JavaScript-Tabellen verwenden. Wenn eine Formel oder einfache Anfrage ein leeres Ergebnis zurückgibt, das gerenderte HTML hinter einer vertrauenswürdigen IP abrufen und es dann mit demselben Code parsen.
  • Verantwortungsvoll scrapen. Die ToS und robots.txt jeder Quelle respektieren, öffentliche Daten und offizielle APIs bevorzugen und alle weiterveröffentlichten Daten kennzeichnen oder lizenzieren.

Häufig gestellte Fragen

Was ist der einfachste Weg, eine Tabelle von einer Website zu scrapen?

Für eine öffentliche, serverseitig gerenderte Seite ist Google Sheets am einfachsten. =IMPORTHTML(url, "table", 1) in eine Zelle eintippen, und Sheets ruft die Seite ab und fügt die erste Tabelle als Live-Zellen in die Tabelle ein, kein Code erforderlich. Es funktioniert für jede Seite, deren Tabelle im rohen HTML vorhanden ist, und es aktualisiert sich von selbst.

Warum gibt IMPORTHTML #N/A oder ein leeres Ergebnis zurück?

IMPORTHTML liest rohes HTML und führt kein JavaScript aus, daher kann es Tabellen, die eine Seite nach dem Laden mit Skripten aufbaut, nicht sehen. Es schlägt auch fehl, wenn die Site die Anfrage blockiert. In beiden Fällen zur Python-Methode wechseln und die Seite über die Crawling API abrufen, die die Seite in einem echten Browser rendern und von einer vertrauenswürdigen IP anfordern kann, bevor sie geparst wird.

Wie scrapt man eine Tabelle mit Python?

Der kürzeste Weg ist pandas.read_html(url), das eine Liste von Data Frames zurückgibt, einen pro Tabelle auf der Seite. In die Liste indexieren, um die gewünschte zu behalten, und mit to_csv exportieren. Für Quellen, die einfache Anfragen blockieren oder Tabellen mit JavaScript rendern, das HTML zunächst über die Crawling API abrufen und dieses Markup statt der URL an read_html übergeben.

Wie scrapt man eine Tabelle in R?

rvest installieren, die Seite mit read_html lesen, dann html_elements("table") %>% html_table() ausführen, um eine Liste von Data-Frame-Tabellen zu erhalten. Mit doppelter Klammerindizierung wie tables[[1]] eine auswählen und mit write.csv exportieren. Der Ablauf spiegelt den pandas-Ansatz nahezu exakt wider.

Was wenn pandas read_html die Tabelle nicht parsen kann?

Manche Tabellen haben zusammengeführte Zellen, fehlende <table>-Tags oder in ungewöhnlichem Markup verschachtelte Zeilen, mit denen read_html nicht umgehen kann. Auf BeautifulSoup zurückfallen: über jedes <tr> iterieren, jedes <th> und <td> als Text lesen und die Zeilen selbst in einem Data Frame aufbauen. Das gibt volle Kontrolle darüber, wie jede Zelle interpretiert wird.

Wie scrapt man Tabellen von einer Site, die einen blockiert?

Sites, die ratenbegrenzen oder automatisierten Traffic herausfordern, benötigen eine Anfrage, die wie ein echter Besucher aussieht. Den Abruf über rotierende Residential-IPs leiten, damit keine einzelne Adresse ein Limit auslöst, und JavaScript rendern, wenn die Tabelle clientseitig aufgebaut wird. Die Crawling API übernimmt beides in einem Aufruf; sobald das zurückgegebene HTML vorliegt, es mit pandas, BeautifulSoup oder rvest wie jede andere Seite parsen.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar