Python ist die Standardsprache für Web-Scraping, und das aus gutem Grund: Ein paar Zeilen requests und BeautifulSoup verwandeln eine Live-Webseite in strukturierte Daten, die Sie speichern, abfragen und analysieren können. Wenn Sie HTML lesen und eine Schleife schreiben können, können Sie heute einen funktionierenden Scraper bauen.
Dieser Leitfaden zeigt Ihnen, wie Sie eine Webseite mit Python von Anfang bis Ende scrapen. Sie installieren den Standard-Stack, rufen eine Seite ab, parsen sie, wählen die gewünschten Elemente aus, extrahieren saubere Felder, durchlaufen die Paginierung und schreiben die Ergebnisse in CSV. Wir verwenden eine öffentliche Übungsseite, sodass jeder Codeausschnitt tatsächlich läuft. Dann kommt der ehrliche Teil: Einfaches requests versagt bei JavaScript-gerenderten Seiten und wird bei großem Volumen blockiert, also werden Sie sehen, wie die Crawling API beide Probleme in einem einzigen Aufruf löst.
Was Sie bauen werden
Ein kleiner Python-Scraper, der eine paginierte Liste von Zitaten von einer öffentlichen Übungsseite liest, den Text, Autor und Tags jedes Zitats extrahiert, dem "weiter"-Link folgt, bis keine Seiten mehr vorhanden sind, und alles in einer CSV-Datei speichert. Dasselbe Muster, Abrufen dann Parsen dann Schleifen dann Speichern, ist das Grundgerüst fast jedes Scrapers, den Sie je schreiben werden.
Wir zielen auf quotes.toscrape.com, eine Seite, die speziell zum Erlernen des Scrapens gebaut wurde. Sie ist statisch, gut strukturiert und frei zugänglich, sodass Sie sich auf die Technik konzentrieren können, ohne bei Ihrem ersten Versuch gegen Blockierungen anzukämpfen.
Voraussetzungen
Sie brauchen nicht viel, um anzufangen.
Grundkenntnisse in Python. Sie sollten mit dem Ausführen eines Skripts und dem Installieren von Paketen mit pip vertraut sein. Schleifen, Funktionen und Dictionaries reichen aus.
Python 3.8 oder höher. Überprüfen Sie Ihre Version mit python --version. Falls Sie es nicht haben, installieren Sie es von python.org.
Das ist alles für die erste Hälfte des Tutorials. Die zwei benötigten Bibliotheken werden in einem einzigen Befehl installiert, den wir als Nächstes behandeln.
Projekt einrichten
Erstellen Sie eine virtuelle Umgebung, damit die Abhängigkeiten des Projekts vom Rest Ihres Systems isoliert bleiben, und installieren Sie dann die zwei Bibliotheken, die die Arbeit erledigen.
python --version python -m venv scraper_env source scraper_env/bin/activate pip install requests beautifulsoup4
Unter Windows aktivieren Sie die Umgebung mit scraper_env\Scripts\activate anstelle der source-Zeile. Zwei Abhängigkeiten tragen das Tutorial: requests ruft die Seite über HTTP ab, und beautifulsoup4 parst das zurückgegebene HTML, sodass Sie Elemente nach Tag und CSS-Klasse herausziehen können.
Schritt 1: Eine Seite abrufen
Jeder Scrape beginnt mit einer HTTP-Anfrage. Senden Sie einen GET an die URL, prüfen Sie, dass der Statuscode 200 ist, bevor Sie irgendetwas anderes tun, und Sie haben das HTML der Seite in der Hand.
import requests url = "https://quotes.toscrape.com/page/1/" headers = {"User-Agent": "Mozilla/5.0 (scraper tutorial)"} response = requests.get(url, headers=headers, timeout=10) if response.status_code == 200: print(response.text[:500]) else: print(f"Request failed: {response.status_code}")
Zwei kleine Gewohnheiten zahlen sich sofort aus. Ein User-Agent-Header lässt Ihre Anfrage wie einen Browser statt wie ein anonymes Skript aussehen, was viele Seiten bevorzugen. Ein timeout verhindert, dass Ihr Scraper ewig hängt, wenn ein Server ins Stocken gerät. Führen Sie dies aus und Sie sollten die ersten 500 Zeichen echter HTML-Ausgabe in Ihrem Terminal sehen. Das bestätigt, dass der Abruf funktioniert, bevor Sie einen einzigen Selektor schreiben.
Schritt 2: Das HTML mit BeautifulSoup parsen
Rohes HTML ist nur ein String. Um Elemente auszuwählen, laden Sie es in BeautifulSoup, das das Markup in einen Baum umwandelt, den Sie nach Tag-Name und CSS-Klasse abfragen können. Öffnen Sie die Seite in Ihrem Browser, klicken Sie mit der rechten Maustaste auf ein Zitat und wählen Sie Inspizieren, um die Struktur zu sehen: Auf dieser Seite befindet sich jedes Zitat in einem div.quote, mit dem Text in span.text, dem Autor in small.author und Tags in a.tag.
from bs4 import BeautifulSoup soup = BeautifulSoup(response.text, "html.parser") quotes = soup.select("div.quote") print(f"Found {len(quotes)} quotes on this page")
Das html.parser-Argument teilt BeautifulSoup mit, welche Engine zu verwenden ist; sie wird mit Python geliefert und benötigt keine zusätzliche Installation. Die select-Methode nimmt einen CSS-Selektor und gibt jedes passende Element als Liste zurück, sodass div.quote Ihnen alle zehn Zitatblöcke auf der Seite gibt. Wenn Sie find und find_all bevorzugen, machen diese dieselbe Arbeit mit einem Methodenaufruf-Stil statt Selektoren. Für eine tiefere Tour durch beides, lesen Sie wie Sie BeautifulSoup in Python verwenden.
Schritt 3: Die Felder extrahieren
Jetzt ziehen Sie die Daten aus jedem Zitatblock. Schleifen Sie über die Elemente, lesen Sie den Text aus jedem Kind und sammeln Sie ein sauberes Dictionary pro Zitat. Das Umwickeln der Selektoren in einen kleinen Helfer verhindert, dass ein fehlendes Feld den gesamten Lauf abbricht.
def text_of(element, selector): el = element.select_one(selector) return el.get_text(strip=True) if el else None def parse_quotes(soup): rows = [] for quote in soup.select("div.quote"): tags = [t.get_text(strip=True) for t in quote.select("a.tag")] rows.append({ "text": text_of(quote, "span.text"), "author": text_of(quote, "small.author"), "tags": ", ".join(tags), }) return rows
Der text_of-Helfer tut zwei nützliche Dinge auf einmal: Er fragt ein einzelnes Element ab und gibt None zurück, wenn das Element fehlt, statt bei einem .get_text()-Aufruf gegen nichts zu werfen. Tags benötigen ein List Comprehension, weil es mehrere pro Zitat gibt, und sie in einen String zusammenzuführen hält jede Zeile flach und CSV-freundlich. Rufen Sie parse_quotes(soup) auf und Sie erhalten eine ordentliche Liste von Dictionaries, eines pro Zitat.
Schritt 4: Paginierung folgen
Eine Seite ist ein Demo; die echte Liste erstreckt sich über viele Seiten. Diese Seite verlinkt die nächste Seite mit einem li.next a-Element, und wenn es verschwunden ist, haben Sie das Ende erreicht. Die Schleife ist also einfach: Aktuelle Seite abrufen, parsen, nächsten Link finden und wiederholen, bis kein nächster Link mehr vorhanden ist.
import time BASE = "https://quotes.toscrape.com" def scrape_all(): all_rows = [] next_url = f"{BASE}/page/1/" while next_url: response = requests.get(next_url, headers=headers, timeout=10) if response.status_code != 200: print(f"Stopped at {next_url}: {response.status_code}") break soup = BeautifulSoup(response.text, "html.parser") all_rows.extend(parse_quotes(soup)) next_link = soup.select_one("li.next a") next_url = BASE + next_link["href"] if next_link else None time.sleep(1) return all_rows
Die while next_url-Schleife läuft, bis der Selektor für den nächsten Link nichts zurückgibt, woraufhin next_url zu None wird und die Schleife natürlich endet. Der href auf der Seite ist relativ, also stellen Sie die Basis-URL voran, um ihn absolut zu machen. Das time.sleep(1) zwischen Seiten ist bei einem echten Ziel keine optionale Höflichkeit: Ihre Anfragen zu verteilen ist der einfachste Weg, unter den Ratenlimits einer Seite zu bleiben.
Schritt 5: In CSV speichern
Daten, die nur im Speicher leben, verschwinden, wenn das Skript endet. Schreiben Sie sie in eine CSV-Datei, damit Sie sie in einer Tabelle öffnen, in pandas laden oder an alles übergeben können, was als Nächstes kommt. Pythons eingebautes csv-Modul erledigt das ohne zusätzliche Abhängigkeiten.
import csv def save_csv(rows, filename="quotes.csv"): if not rows: return with open(filename, "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=rows[0].keys()) writer.writeheader() writer.writerows(rows) if __name__ == "__main__": data = scrape_all() save_csv(data) print(f"Saved {len(data)} quotes to quotes.csv")
DictWriter ordnet die Schlüssel jedes Dictionaries den CSV-Spalten zu, sodass die Kopfzeile sich aus den bereits gewählten Feldnamen selbst schreibt. Das newline=""-Argument verhindert Leerzeilen zwischen Zeilen unter Windows, und encoding="utf-8" hält Anführungszeichen und akzentuierte Autorennamen intakt. Führen Sie das Skript aus und Sie haben eine vollständige CSV aller Zitate über alle Seiten. Das ist ein vollständiger, funktionierender Scraper.
Wo einfaches requests aufhört zu funktionieren
Die obige Übungsseite ist statisch, was genau der Grund ist, warum sie ein gutes erstes Ziel ist. Echte Webseiten sind selten so freundlich. Zwei Probleme tauchen auf, sobald Sie diesen Code auf ein ernsthaftes Ziel richten, und keines ist durch das Anpassen von Selektoren lösbar.
JavaScript-gerenderte Seiten
Viele moderne Seiten senden eine nahezu leere HTML-Hülle und bauen den sichtbaren Inhalt im Browser mit JavaScript auf. requests ruft nur diese anfängliche Hülle ab; es führt keine Skripte aus. Wenn Sie also die Antwort parsen, finden Sie keine der Daten, die Sie in Ihrem Browser sahen, weil diese Daten erst erscheinen, nachdem das JavaScript der Seite ausgeführt wurde. Ein einfacher Abruf kann sie schlicht nicht sehen. Das vollständige Bild dieses Problems finden Sie unter wie Sie JavaScript-Seiten mit Python scrapen.
Blockierungen bei großem Volumen
Die zweite Wand ist Anti-Bot-Abwehr. Datacenter-IPs, sich wiederholende Anfragemuster und Traffic, der nicht wie ein echter Browser aussieht, werden mit CAPTCHAs herausgefordert oder direkt blockiert. Ihr Scraper funktioniert vielleicht für zehn Anfragen und gibt dann 403s oder leere Seiten zurück. Headers und Sleeps hinzuzufügen hilft ein wenig, aber bei jedem echten Volumen benötigen Sie IPs, die als echte Besucher gelten, was ein einzelner Rechner nicht liefern kann. Das tiefere Playbook liegt in wie Sie Webseiten scrapen ohne blockiert zu werden.
Die Lösung: In einem Aufruf rendern und rotieren
Sie können beide Probleme selbst lösen, indem Sie einen Headless-Browser zum Rendern von JavaScript betreiben und einen Pool von rotierenden Residential-Proxys für die IPs pflegen. Das funktioniert, aber diese Teile zusammenzufügen und gesund zu halten, ist der Großteil des Engineering-Aufwands, und es hat nichts mit den Daten zu tun, die Sie eigentlich wollen.
Die Crawling API fasst beides in einer einzigen Anfrage zusammen. Sie senden die URL, sie rendert die Seite in einem echten Browser hinter einer vertrauenswürdigen rotierenden IP und gibt fertiges HTML zurück, das Sie mit genau demselben BeautifulSoup-Code parsen, den Sie bereits geschrieben haben. Installieren Sie den offiziellen Client neben den bereits vorhandenen Bibliotheken.
pip install crawlbase
Hier ist der Vorher-Nachher-Vergleich. Der einfache Abruf auf einer JavaScript-lastigen Seite gibt eine Hülle zurück; der Crawling API-Aufruf gibt die gerenderte Seite zurück. Die Parsing-Schicht darunter ändert sich überhaupt nicht.
# Before: plain requests, breaks on JS pages and blocks response = requests.get(url, headers=headers, timeout=10) html = response.text # After: Crawling API renders the page behind a trusted IP from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"}) options = {"ajax_wait": "true", "page_wait": 5000} result = api.get(url, options) html = result["body"].decode("utf-8") if result["status_code"] == 200 else None # Same parser as before, unchanged soup = BeautifulSoup(html, "html.parser") rows = parse_quotes(soup)
Die zwei Warteoptionen sind bei einem clientseitig gerenderten Ziel wichtig. ajax_wait weist die API an, auf das Fertigladen von asynchronem Inhalt zu warten, und page_wait hält für eine feste Anzahl von Millisekunden nach dem Laden, damit spät erscheinende Elemente vor der Erfassung erscheinen. Verwenden Sie das JavaScript-Token für Seiten, die im Browser rendern; für statische Seiten ist das normale Token schneller. Der wichtige Punkt ist, dass html in dieselbe parse_quotes-Funktion fließt, die Sie in Schritt 3 geschrieben haben, also ist die Übernahme der API ein einzeiliger Tausch, keine Neuschreibung.
Crawlbase bietet zwei Token-Typen an. Das normale Token ruft statisches HTML ab, was alles ist, was Sie für eine Seite wie die Zitat-Übungsseite benötigen. Das JavaScript (JS)-Token rendert die Seite zuerst in einem echten Browser, was Sie für jede Seite benötigen, die ihren Inhalt clientseitig aufbaut. Wenn Ihre geparsten Felder bei einem echten Ziel leer zurückkommen, ist der Wechsel zum JS-Token normalerweise die Lösung.
Einfaches requests versagt bei JavaScript-Seiten und wird bei großem Volumen blockiert. Die Crawling API rendert die Seite in einem echten Browser, rotiert serverseitig durch Residential-IPs und gibt Ihnen fertiges HTML, sodass der bereits geschriebene BeautifulSoup-Code bei Zielen weiter funktioniert, die ein einfacher Abruf nicht berühren kann. Testen Sie es auf dem kostenlosen Tarif, bevor Sie selbst eine Headless-Flotte aufbauen.
Nützliche Python-Scraping-Bibliotheken
Der Zwei-Bibliotheken-Stack erledigt die meisten statischen Aufgaben, aber einige andere sind es wert zu kennen, wenn Ihre Anforderungen wachsen.
- requests ist der bewährte HTTP-Client zum Abrufen von Seiten. Einfach, zuverlässig und die richtige Standardwahl für statische Ziele.
- BeautifulSoup parst HTML und XML in einen navigierbaren Baum. Es ist tolerant gegenüber unordentlichem Markup, was echte Seiten immer haben.
- Selenium steuert einen echten Browser und kann daher JavaScript rendern und mit Seiten durch Klicken und Tippen interagieren. Leistungsstark, aber ressourcenintensiv und bei großem Volumen langsam.
- Scrapy ist ein vollständiges Crawling-Framework mit eingebauter Parallelität, Wiederholungen und Pipelines. Greifen Sie darauf zurück, wenn ein Skript zu einem echten Projekt wächst.
- pandas ist kein Scraper, aber dort landen gescrapte Daten oft zum Bereinigen, Analysieren und Exportieren in andere Formate.
Gewohnheiten, die einen Scraper gesund halten
Ein Scraper, der einmal funktioniert, ist einfach; einer, der weiter funktioniert, erfordert einige Disziplinen. Diese gelten, ob Sie einfaches requests oder eine verwaltete API verwenden.
-
Anfragen zeitlich verteilen. Eine kleine Verzögerung zwischen Anfragen, wie das
time.sleep(1)oben, hält Sie unter Ratenlimits und von Blocklisten fern. Eine Seite in einer engen Schleife zu hämmern ist der schnellste Weg, gedrosselt zu werden. -
Fehler behandeln. Seiten ändern sich, Felder fehlen und Server stocken. Prüfen Sie Statuscodes, schützen Sie Selektoren gegen
Noneund umwickeln Sie riskantes Parsen, damit eine schlechte Seite nicht den gesamten Lauf beendet. - Erwarten Sie, dass Markup driftet. Klassennamen und Strukturen ändern sich ohne Vorankündigung. Wenn ein Feld anfängt, leer zurückzukommen, prüfen Sie die Live-Seite und aktualisieren Sie den Selektor. Periodische Pflege ist normal, kein Zeichen für einen kaputten Scraper.
-
Das Ziel respektieren. Lesen Sie die
robots.txtund die Nutzungsbedingungen der Seite, halten Sie Ihr Volumen vernünftig und sammeln Sie nur öffentliche Daten.
Wichtigste Erkenntnisse
- Die Kernschleife ist Abrufen, Parsen, Schleifen, Speichern. requests holt das HTML, BeautifulSoup extrahiert Felder, Paginierung durchläuft die Seiten und das csv-Modul speichert das Ergebnis.
- Inspizieren vor dem Selektieren. Öffnen Sie die Dev Tools der Seite, um die Tags und Klassen zu finden, die Ihre Daten enthalten, dann ordnen Sie jedes Feld einem CSS-Selektor zu.
-
Ihren Code verteilen und absichern. Fügen Sie eine Verzögerung zwischen Anfragen hinzu und geben Sie
Nonebei fehlenden Elementen zurück, damit eine schlechte Seite den Lauf nicht abbricht. - Einfaches requests hat zwei Grenzen. Es kann kein JavaScript ausführen und wird bei großem Volumen blockiert, beides ist durch Selektoren nicht behebbar.
- Die Crawling API löst beides in einem Aufruf. Sie rendert die Seite hinter einer vertrauenswürdigen rotierenden IP und gibt fertiges HTML zurück, sodass Ihr bestehender BeautifulSoup-Parser unverändert weiter funktioniert.
Häufig gestellte Fragen
Benötige ich sowohl requests als auch BeautifulSoup?
Für eine typische statische Seite ja, und sie ergänzen sich natürlich. requests ruft die Seite über HTTP ab und gibt Ihnen das rohe HTML als String; BeautifulSoup wandelt diesen String in einen Baum um, den Sie nach Tag und CSS-Klasse abfragen können, um einzelne Felder herauszuziehen. requests lädt herunter, BeautifulSoup extrahiert.
Warum sind meine gescrapten Daten leer, obwohl die Seite eindeutig Inhalt hat?
Fast immer weil die Seite ihren Inhalt mit JavaScript rendert. requests ruft nur die anfängliche HTML-Hülle ab und führt keine Skripte aus, sodass die Daten, die Sie in Ihrem Browser sehen, nicht in dem vorhanden sind, was Sie parsen. Sie müssen die Seite zuerst rendern, entweder mit einem Headless-Browser oder mit dem JavaScript-Token der Crawling API, bevor BeautifulSoup die Felder finden kann.
Wie scrape ich mehrere Seiten?
Finden Sie den Link oder das Muster, das die Seite für ihre nächste Seite verwendet, dann schleifen Sie. Wenn es eine "Weiter"-Schaltfläche gibt, folgen Sie ihrem href, bis er verschwindet, wie in Schritt 4 gezeigt. Wenn die URLs einem Zahlenmuster folgen wie /page/2/, können Sie sie stattdessen in einer Bereichsschleife aufbauen. Fügen Sie auf jeden Fall eine kurze Verzögerung zwischen Seiten hinzu, um höflich und nicht blockiert zu bleiben.
Wie vermeide ich das Blockiertwerden beim Scrapen?
Verteilen Sie Ihre Anfragen zeitlich mit einer Verzögerung, senden Sie einen realistischen User-Agent-Header und variieren Sie Ihre Ziele, statt einen Pfad zu hämmern. Bei großem Volumen benötigen Sie auch IPs, die wie echte Besucher aussehen, was ein einzelner Rechner nicht liefern kann. Durch rotierende Residential-IPs zu routen, ob über die Crawling API oder den Smart AI Proxy, ist es, was Hochvolumen-Läufe davor bewahrt, Ratenlimits auszulösen.
Wann sollte ich die Crawling API anstelle von einfachem requests verwenden?
Verwenden Sie einfaches requests für statische, niedrigvolumige Ziele, bei denen ein einfacher Abruf die Daten zurückgibt, wie die Übungsseite in diesem Leitfaden. Wechseln Sie zur Crawling API, wenn die Seite JavaScript-gerendert ist, wenn Sie blockiert oder herausgefordert werden, oder wenn Sie in einem Volumen scrapen müssen, das eine einzelne IP nicht aufrechterhalten kann. Da die API HTML zurückgibt, ändert sich Ihr bestehender Parser nicht.
Ist Web-Scraping mit Python legal?
Das Scrapen öffentlicher Daten ist generell zulässig, hängt aber von den Nutzungsbedingungen der Seite, Ihrer Rechtsprechung und der Verwendung der Daten ab. Prüfen Sie die robots.txt und die Bedingungen der Seite, bevor Sie beginnen, vermeiden Sie personenbezogene Daten, die unter Datenschutzgesetze wie DSGVO fallen, und scrapen Sie niemals Inhalte hinter einem Login. Im Zweifelsfall sammeln Sie nur öffentliche Daten und halten Sie Ihr Volumen niedrig genug, dass Sie den Server nicht belasten.
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.

