Web Scraping mit Python — Der komplette Guide 2026
Web Scraping mit Python lernen: requests + BeautifulSoup, Pagination, Playwright für JavaScript-Seiten — und wann eine Scraping API DIY schlägt.
Du brauchst Daten, die auf einer Webseite leben — Preise, Listings, Suchergebnisse, Bewertungen — und es gibt keinen Download-Button. Jedes Tutorial, das du geöffnet hast, hört entweder beim „Hello World“-Scraping einer Demo-Site auf oder springt direkt zu einem Framework-Diagramm, ohne irgendetwas Lauffähiges dazwischen. Währenddessen liefert dein eigentliches Ziel einen 403, rendert alles mit JavaScript oder ändert sein Markup in der Woche, nachdem dein Skript endlich funktioniert.
Dieser Guide ist der ganze Weg an einem Ort: ein lauffähiger erster Scraper, dann Pagination und Höflichkeit, dann JavaScript-Seiten mit Playwright, dann eine ehrliche Bestandsaufnahme, warum Produktions-Scraper kaputtgehen — und was zu tun ist, wenn es deinen trifft. Jeder Codeblock unten läuft wie geschrieben gegen öffentliche Demo-Sites. Wir scrapen ausschließlich öffentliche Daten, und wir sagen klar, wo DIY aufhört, das richtige Werkzeug zu sein.
Der Python-Scraping-Stack 2026
Python ist nach wie vor die Standardsprache für Web Scraping, weil die drei Tools, die du brauchst, ausgereift, dokumentiert und nur ein pip install entfernt sind:
| Stufe | Tools | Wann einsetzen |
|---|---|---|
| Statisches HTML | requests + beautifulsoup4 | Die Daten stehen im Seitenquelltext (View Source zeigt sie) |
| JavaScript-Seiten | playwright | Die Daten erscheinen erst, nachdem der Browser Skripte ausgeführt hat |
| Geschützt / im großen Maßstab | Scraping API | Die Website blockiert dich, oder die Wartung kostet mehr, als die Daten wert sind |
Die aktuellen Versionen Mitte 2026: requests 2.x, BeautifulSoup 4.15 (erschienen im Juni 2026) und Playwright für Python 1.61. Die Regel, die Projekte gesund hält: nimm das kleinste Werkzeug, das zur Seite passt. Ein Headless-Browser auf statisches HTML losgelassen verschwendet 50× so viele Ressourcen für dasselbe Ergebnis; requests auf eine React-App gerichtet liefert dir ein leeres div.
Installiere die erste Stufe und du bist startklar:
pip install requests beautifulsoup4
Quickstart: dein erster Scraper in 15 Zeilen
Wir scrapen books.toscrape.com, einen Demo-Buchladen, der genau für diesen Zweck gebaut wurde — 1.000 Bücher mit Titeln, Preisen und Lagerstatus. Das Muster ist: abrufen, parsen, auswählen:
import requests
from bs4 import BeautifulSoup
url = "https://books.toscrape.com/"
resp = requests.get(url, timeout=10)
resp.raise_for_status() # crash loudly on 4xx/5xx instead of parsing an error page
soup = BeautifulSoup(resp.text, "html.parser")
books = []
for card in soup.select("article.product_pod"):
books.append({
"title": card.h3.a["title"],
"price": card.select_one("p.price_color").get_text(strip=True),
"in_stock": "In stock" in card.select_one("p.availability").get_text(),
})
print(f"Scraped {len(books)} books")
print(books[0])
# {'title': 'A Light in the Attic', 'price': '£51.77', 'in_stock': True}
Drei Dinge tragen hier das ganze Gewicht:
resp.raise_for_status()— Anfänger lassen das weg und verbringen dann eine Stunde damit zu debuggen, warum BeautifulSoup auf etwas „nichts gefunden“ hat, das in Wirklichkeit eine 404-Seite war.soup.select(...)nimmt CSS-Selektoren entgegen, dieselben, die du in den DevTools deines Browsers testest. Rechtsklick auf das Element, Untersuchen, und baue den Selektor dort, bevor du eine Zeile Python schreibst. Dieser Schritt — unordentliches Markup in benannte Felder zu verwandeln — ist HTML-Parsing, und hier lebt der Großteil des Codes deines Scrapers (und der Großteil seiner künftigen Brüche).- Strukturierte Ausgabe von Anfang an. Eine Liste von Dicts wird in einer Zeile zu CSV, JSON oder einem DataFrame — den Export verdrahten wir einen Abschnitt weiter.
BeautifulSoup geht viel tiefer als select — find_all mit Attributfiltern, Baumnavigation, Umgang mit kaputtem Markup. Die komplette API behandeln wir im BeautifulSoup-Tutorial; dieser Guide geht weiter zu den Problemen, die auftauchen, nachdem die erste Seite funktioniert.
Level 2: Pagination und Höflichkeit
Eine Seite ist eine Demo. Echte Datensätze erstrecken sich über Pagination — und in dem Moment, in dem du Seiten in einer Schleife anfragst, bist du ein Bot-Traffic-Muster, also beginnt hier auch die Scraping-Etikette zu zählen.
import time
import requests
from bs4 import BeautifulSoup
BASE = "https://books.toscrape.com/catalogue/page-{}.html"
HEADERS = {"User-Agent": "book-price-research/1.0 ([email protected])"}
books = []
for page in range(1, 6): # first 5 of 50 pages
resp = requests.get(BASE.format(page), headers=HEADERS, timeout=10)
if resp.status_code == 404:
break # walked off the end of the catalogue
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
for card in soup.select("article.product_pod"):
books.append({
"title": card.h3.a["title"],
"price": card.select_one("p.price_color").get_text(strip=True),
})
time.sleep(1.0) # ~1 request/second
print(f"{len(books)} books across 5 pages")
Die Gewohnheiten, die einen guten Bürger von einem Ärgernis trennen:
- Drossle dich selbst. Das
time.sleep(1.0)ist ein Boden, keine Formalität. Eine Website, der eine Anfrage pro Sekunde nie auffallen würde, bemerkt fünfzig ganz sicher. Server verteidigen sich mit Rate Limiting — und eine 429-Antwort ist die höfliche Warnung vor dem 403, das keine mehr ist. - Prüfe zuerst robots.txt. Rufe
https://the-site.com/robots.txtab und respektiere dieDisallow-Regeln — Pythons eingebauterurllib.robotparserkann sie für dich auswerten. Es ist kein Gesetz, aber es zu ignorieren ist der schnellste Weg, eine tolerante Website in eine feindselige zu verwandeln, und es zieht auch deine rechtliche Position nach unten. (Zu diesem Thema: Das Scrapen öffentlicher Daten kann rechtmäßig sein, aber das hängt von den Daten, den Bedingungen und deiner Rechtsordnung ab — siehe is web scraping legal in 2026.) - Identifiziere dich ehrlich im User-Agent mit einer Möglichkeit, dich zu erreichen, und respektiere 429er, indem du exponentiell zurückweichst, statt in einer engen Schleife erneut zu versuchen.
- Scrape nur öffentliche Seiten. Nichts hinter einem Login, nichts Persönliches, nichts, was die Bedingungen der Website klar einzäunen.
Speichere es an einem nützlichen Ort
Weil wir Dicts gesammelt haben, ist der Export Standardbibliotheks-Territorium — kein pandas nötig für den einfachen Fall:
import csv
with open("books.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["title", "price"])
writer.writeheader()
writer.writerows(books)
Zwei Gewohnheiten, die du dir jetzt angewöhnen solltest, solange der Datensatz klein ist. Erstens: bereinige an der Kante — wandle "£51.77" schon beim Scrapen in einen Float um, nicht drei Skripte weiter stromabwärts. float(price.lstrip("£")) heute erspart dir später einen Locale-Parsing-Bug. Zweitens: behalte das rohe HTML für alles, was du eventuell neu parsen musst — Speicherplatz ist billig, und wenn du nächsten Monat feststellst, dass du auch die Sternebewertung gebraucht hättest, schlägt das Neu-Parsen gespeicherter Seiten das Neu-Crawlen der Website. Wenn das Ziel eine Tabelle auf jemandes Schreibtisch statt einer Datenbank ist, steht die komplette Pipeline — Formatierung, mehrere Sheets, wiederkehrende Refreshes — in scrape a website to Excel.
Level 3: JavaScript-Seiten mit Playwright
Lass das Quickstart-Muster gegen eine moderne React- oder Vue-Site laufen und du bekommst eine hohle Hülle — das HTML kommt fast leer an, und JavaScript füllt es danach. requests führt dieses JavaScript nie aus. Die schnelle Diagnose: Wenn View Source die Daten nicht enthält, die gerenderte Seite aber schon, brauchst du einen Headless-Browser.
Playwright ist 2026 der Standard dafür in Python — es bringt seine eigenen Browser mit und wartet intelligent auf Inhalte:
pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://quotes.toscrape.com/js/", timeout=30000)
page.wait_for_selector("div.quote") # block until JS has rendered the data
quotes = []
for q in page.locator("div.quote").all():
quotes.append({
"text": q.locator("span.text").inner_text(),
"author": q.locator("small.author").inner_text(),
})
browser.close()
print(f"{len(quotes)} quotes rendered by JavaScript")
Dieses Ziel — quotes.toscrape.com/js/ — liefert eine leere Seite aus und baut jedes Zitat clientseitig, es beweist den Punkt also: requests bekommt null Zitate, Playwright bekommt zehn. Die Schlüsselzeile ist wait_for_selector, die den fragilen sleep(5)-und-hoffen-Ansatz durch ein explizites Warten auf genau das Element ersetzt, das du wirklich brauchst.
Die Kosten sind allerdings real. Eine Headless-Browser-Session verbraucht Hunderte Megabyte RAM, wo requests ein paar brauchte, und läuft eine Größenordnung langsamer. Zwei Faustregeln: Greife nur zu Playwright, wenn die Daten wirklich nicht im rohen HTML stehen, und schau zuerst in den Network-Tab — viele „JavaScript-Sites“ holen ihre Daten von einem sauberen JSON-Endpoint, den du direkt mit requests aufrufen kannst. Wenn du wirklich einen Browser brauchst, gehen wir in web scraping with Playwright tief in Selektoren, Waits und Skalierung. Wenn du einen älteren Stack pflegst, funktioniert Selenium weiterhin gut und hat fünfzehn Jahre Stack-Overflow-Antworten hinter sich — wir vergleichen beide in Selenium web scraping.
Der ehrliche Teil: warum Produktions-Scraper kaputtgehen
Alles oben funktioniert — wirklich, nicht nur auf Demo-Sites. Viele interne Tools und Forschungsprojekte laufen jahrelang auf requests, BeautifulSoup und einem Cron-Job. Aber zwischen „funktioniert auf meiner Maschine gegen eine Demo-Site“ und „läuft jede Nacht gegen ein kommerzielles Ziel“ steht eine Mauer, und es lohnt sich, sie klar zu beschreiben, denn hier sterben die meisten Scraping-Projekte tatsächlich.
Anti-Bot-Systeme antworten, bevor der Inhalt es tut. Cloudflare, DataDome, Akamai und ihre Verwandten sitzen vor einem großen Teil kommerzieller Websites. Sie bewerten jede Anfrage, und ein Python-Client fällt bei dieser Bewertung schnell durch: 403er auf die erste Anfrage, 429er, sobald du ein Muster hast, JavaScript-Challenges, die requests nicht ausführen kann. Das ist kein Randfall — es ist 2026 die Standardhaltung von E-Commerce-, Reise-, Immobilien- und Such-Zielen.
Deine IP hat eine Reputation, und sie ist schlecht. Datacenter-IPs — dein Laptop im Cloud-WLAN, deine AWS-Box, dein CI-Runner — sind katalogisiert und vorab markiert. Daran vorbeizukommen heißt Residential- oder Mobile-IPs, die pro Anfrage durch einen Rotating-Proxy-Pool rotieren — also ein Proxy-Anbieter, Abrechnung pro GB und eine neue Kategorie von Infrastruktur, die betreut werden will.
Selbst Headless-Browser werden enttarnt. Anti-Bot-Anbieter prüfen TLS-Handshakes, Canvas-Rendering, installierte Schriften und Dutzende weitere Signale, um eine Gerätesignatur zu berechnen — Browser-Fingerprinting — und Standard-Playwright hat eine wiedererkennbare. Gepatchte Builds und Stealth-Plugins existieren, aber sie sind ein Laufband: Anbieter aktualisieren, Patches hinken hinterher, dein Scraper beginnt an einem Dienstag still zu versagen.
Layout-Drift ist der leise Killer. Die Website liefert ein Redesign aus, p.price_color existiert nicht mehr, und dein Scraper stürzt nicht ab — er schreibt leere Felder in deine Pipeline, bis jemandem auffällt, dass das Dashboard falsch aussieht. Jeder Selektor, den du schreibst, ist ein unversionierter Vertrag, den die Gegenseite nie unterschrieben hat.
Rechne alles zusammen und das Muster ist vertraut: Der Scraper hat ein Wochenende gekostet und frisst jetzt jede Woche ein paar Stunden in Proxy-Rechnungen, Selektor-Reparaturen und Block-Untersuchungen. Diese Wartungssteuer — nicht irgendeine fehlende Python-Fähigkeit — ist der wahre Preis von DIY, und wir rechnen sie in web scraping vs API ehrlich zusammen. Für die Gegenmaßnahmen, die funktionieren, wenn du bei DIY bleiben willst, siehe scraping sites that block bots.
Der API-Weg: ein Aufruf ersetzt den Stack
Die Alternative zum Kampf gegen diese Mauer ist, den ganzen Stack — Proxys, Browser, Fingerprints, Parser — an eine Web Scraping API zu übergeben, die diesen Kampf hauptberuflich für dich führt. Hier eine echte Amazon-Suche, strukturiertes JSON zurück, kein Browser, kein Proxy-Pool, kein Parser:
import requests
resp = requests.get(
"https://api.crawlora.net/api/v1/amazon/search",
params={"k": "mechanical keyboard"},
headers={"x-api-key": "YOUR_API_KEY"},
)
resp.raise_for_status()
for item in resp.json()["data"]:
print(item["title"], item["price"], item["rating"])
Dieselbe requests-Bibliothek, die du im Quickstart gelernt hast — die Fähigkeit überträgt sich direkt. Was sich geändert hat, ist, wofür du verantwortlich bist:
- Strukturierte Felder statt HTML. Die Antwort ist normalisiertes JSON —
title,price,rating,asin,review_count— wenn Amazon also ein Redesign ausliefert, ist das Crawloras Parser, der repariert wird, bevor du es merkst, nicht deiner. - Der Anti-Bot-Kampf findet auf der anderen Seite des Keys statt. Proxy-Rotation, Rendering, Retries und Fingerprint-Pflege sind der Vollzeitjob des Anbieters.
- Abgerechnet wird pay-on-success — dir werden nur erfolgreiche 2xx-Antworten berechnet, was genau deshalb zählt, weil das Scrapen harter Ziele Fehlschläge einschließt.
- Der Free Tier umfasst 2.000 Credits/Monat, ohne Karte — genug, um herauszufinden, ob die Daten es wert sind, darauf zu bauen, bevor du irgendetwas ausgibst.
Dasselbe Muster deckt Dutzende Plattformen ab — Google Search, TikTok, Zillow, GitHub, App Stores — jede mit dokumentierten Endpoints in den API-Docs und Copy-Paste-Python für jede einzelne in den Python-Beispielen. Wenn dein Scraper einen LLM-Agenten statt einer Tabelle füttert, sind dieselben Endpoints als gehosteter MCP-Server verfügbar (siehe die MCP-Integration) — und dieses Agent-plus-Scraping-Muster ist ein eigenes Thema, behandelt in web scraping with AI.
Um in beide Richtungen fair zu sein: Eine API hat einen Preis pro Request, deckt die Plattformen ab, die sie abdeckt, und setzt einen Anbieter in deine Pipeline. DIY hat keine dieser Einschränkungen — und genau deshalb ist die richtige Antwort meistens eine Mischung.
DIY vs Scraping API: wie du dich entscheidest
| Faktor | DIY (requests / Playwright) | Scraping API |
|---|---|---|
| Anfangskosten | Kostenlos — alles Open Source | Free Tier, danach Credits pro Request |
| Ungeschützte Websites | Gewinnt — schnell, kostenlos, volle Kontrolle | Funktioniert, aber du zahlst für Schutz, den du nicht brauchst |
| Geschützte Websites (Cloudflare etc.) | Proxys + Stealth + ständige Pflege | Gewinnt — hinter dem Key erledigt |
| Long-Tail / Nische / interne Websites | Gewinnt — keine API deckt jede Website ab | Nur unterstützte Plattformen |
| Wartung | Deine: Selektoren, Proxys, Blocks | Beim Anbieter: Parser und Unblocking |
| Ausgabe | Was immer du parst — voll individuell | Normalisiertes JSON pro Plattform |
| Lernwert | Gewinnt — du verstehst den ganzen Stack | Abstrahiert die interessanten Teile weg |
Die ehrliche Aufteilung: DIY gewinnt bei Kosten, Abdeckung von Nischenzielen und Kontrolle; die API gewinnt bei geschützten Plattformen, Wartung und Time-to-Data. Die meisten Teams scrapen am Ende die einfachen und internen Ziele selbst und leiten die feindseligen, hochwertigen Plattformen über eine API.
Bevor du eines von beiden in Produktion nimmst, geh die Checkliste durch:
- Sind die Daten öffentlich, und erlauben robots.txt und die Bedingungen der Website, was du tust?
- Stehen die Daten im rohen HTML (requests + BeautifulSoup) oder werden sie per JavaScript gerendert (Playwright)?
- Bist du auf eine höfliche Rate gedrosselt, mit Timeouts, raise_for_status und exponentiellem Backoff bei 429ern?
- Validierst du gescrapte Felder (nicht leer, plausible Typen), damit Layout-Drift laut statt still fehlschlägt?
- Hast du die Wartungssteuer — Proxys, Selektor-Reparaturen, Block-Bekämpfung — gegen den Preis pro Request einer Scraping API gerechnet?
- Für geschützte Ziele: Hast du getestet, ob ein einziger API-Aufruf dir dieselben Daten ganz ohne die Infrastruktur liefert?
Wie es weitergeht
Du hast jetzt die vollständige Karte für 2026: requests und BeautifulSoup für statische Seiten, Playwright, wenn JavaScript im Weg ist, echte Höflichkeitsgewohnheiten und einen klaren Blick auf die Produktionsmauer plus die API-Tür hindurch. Der beste nächste Schritt ist, den Quickstart gegen ein Ziel laufen zu lassen, das dich wirklich interessiert — innerhalb einer Stunde weißt du, welche Stufe des Stacks dein Projekt braucht. Und wenn diese erste Anfrage mit 403 zurückkommt, weißt du genau, was du vor dir hast — und dass es so oder so ein gelöstes Problem ist. Die Preisseite hat die Credit-Rechnung, falls du sie mit deiner Proxy-Rechnung vergleichen willst.
Überspring die Mauer — teste die API Seite an Seite mit deinem Scraper
Strukturiertes JSON von Amazon, Google, TikTok und mehr. Verwaltete Proxys, Rendering und Retries; Abrechnung nur bei Erfolg. 2.000 Credits/Monat kostenlos, ohne Karte.
Weiterführende Artikel:
Häufig gestellte Fragen
Ist Web Scraping mit Python legal?
Das Scrapen öffentlicher Daten kann rechtmäßig sein, aber es hängt davon ab, was du sammelst, von den Nutzungsbedingungen der Website und von deiner Rechtsordnung. Bleib auf öffentlichen Seiten, meide alles hinter einem Login, lass persönliche Daten aus, respektiere robots.txt und halte deine Anfragerate höflich. Gerichtsurteile haben das Scrapen öffentlich zugänglicher Daten überwiegend begünstigt, aber das ist Hintergrund, keine Rechtsberatung — prüfe die Details für deinen Anwendungsfall.
Was ist die beste Python-Bibliothek für Web Scraping?
Das hängt von der Seite ab. Für statisches HTML ist requests plus BeautifulSoup das Standardpaar — einfach, schnell und gut dokumentiert. Für JavaScript-gerenderte Seiten ist Playwright 2026 die Standard-Headless-Browser-Bibliothek. Für das Crawlen vieler Seiten ergänzt Scrapy Scheduling und Pipelines. Die Faustregel: Nimm das kleinste Werkzeug, das zur Seite passt, die du scrapst.
Ist Python gut für Web Scraping?
Ja — Python ist die beliebteste Scraping-Sprache, weil sein Ökosystem jede Stufe des Jobs abdeckt: requests für HTTP, BeautifulSoup fürs HTML-Parsing, Playwright für Browser-Automatisierung und pandas fürs Bereinigen und Exportieren der Ergebnisse. Ein funktionierender Scraper ist etwa 15 Zeilen Code, und fast jedes Scraping-Tutorial, jede Stack-Overflow-Antwort und jedes API-Beispiel erscheint zuerst in Python.
Wie scrape ich eine Website, die JavaScript nutzt?
Wenn die Daten in View Source fehlen, auf der gerenderten Seite aber sichtbar sind, liefert reines requests nur eine leere Hülle. Nutze Playwright für Python: Starte Headless-Chromium, rufe page.goto auf und warte mit wait_for_selector auf das benötigte Element, bevor du Text extrahierst. Prüfe außerdem zuerst den Network-Tab des Browsers — viele JavaScript-Sites laden ihre Daten von einem JSON-Endpoint, den du direkt aufrufen kannst, was weit günstiger ist, als einen Browser laufen zu lassen.
Wie vermeide ich Blockierungen beim Scrapen?
Drossle auf ungefähr eine Anfrage pro Sekunde, setze einen ehrlichen User-Agent, respektiere robots.txt und weiche bei 429-Antworten exponentiell zurück. Bei Websites hinter Cloudflare oder ähnlichen Anti-Bot-Systemen reicht das oft nicht — Datacenter-IPs sind vorab markiert und Headless-Browser werden gefingerprintet. Ab dem Punkt lauten die Optionen: rotierende Residential-Proxys plus Stealth-Patches, oder eine Scraping API, die das Unblocking für dich übernimmt.
Was ist der Unterschied zwischen BeautifulSoup und Scrapy?
BeautifulSoup ist eine Parsing-Bibliothek: Du gibst ihr HTML, das du selbst geholt hast, und sie hilft dir, Felder mit CSS-Selektoren zu extrahieren. Scrapy ist ein vollständiges Crawling-Framework: Es verwaltet Requests, Nebenläufigkeit, Link-Verfolgung, Drosselung und Export-Pipelines. Nutze BeautifulSoup mit requests für Skripte und kleine Jobs; ziehe Scrapy in Betracht, wenn du Tausende Seiten einer Website crawlst.
Kann ich eine API nutzen, statt einen Python-Scraper zu schreiben?
Ja, für unterstützte Plattformen. Eine Scraping API wie Crawlora stellt dokumentierte Endpoints bereit — Amazon-Suche, Google Search, TikTok und mehr —, die normalisiertes JSON in einem requests.get-Aufruf mit x-api-key-Header zurückgeben, während Proxys, Rendering und Retries serverseitig erledigt werden. Abgerechnet wird pay-on-success (nur 2xx-Antworten werden berechnet), und der Free Tier umfasst 2.000 Credits/Monat, ohne Karte. Für Nischen-Websites, die keine API abdeckt, gewinnt weiterhin DIY.
