JavaScript-Websites mit Selenium in Python scrapen
Im letzten Tutorial haben wir statisches HTML mit requests und BeautifulSoup gescrapt. Viele moderne Seiten — Shops und Dashboards — bauen ihren Inhalt aber erst nach dem Laden per JavaScript auf. Genau hier kommt Selenium ins Spiel: Es liest nicht rohes HTML, sondern steuert einen echten Browser.
Warum BeautifulSoup hier versagt
Die Übungsseite quotes.toscrape.com hat eine /js/-Version, die dieselben Zitate per JavaScript rendert. Laden Sie sie mit requests, bekommen Sie nur eine leere Hülle:
import requests
from bs4 import BeautifulSoup
response = requests.get("https://quotes.toscrape.com/js/")
soup = BeautifulSoup(response.text, "html.parser")
print(soup.select(".quote")) # Ausgabe: [] — nichts gefunden
Selenium installieren
pip install selenium
Seit Version 4.6 lädt Selenium den Browser-Treiber (Chrome/Firefox) selbst herunter und verwaltet ihn — kein manuelles Herunterladen von chromedriver mehr nötig.
Schritt 1: Eine echte Seite öffnen
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://quotes.toscrape.com/js/")
print(driver.title)
driver.quit()
Das öffnet ein echtes Chrome-Fenster, rendert die Seite vollständig samt JavaScript und schließt sie danach.
Schritt 2: Richtig warten, nicht time.sleep
Häufiges Problem: Ihr Code läuft, bevor das JavaScript fertig gerendert hat. Die falsche Lösung ist time.sleep(3) — mal zu kurz, mal verschwendete Zeit. Die richtige Lösung ist WebDriverWait:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://quotes.toscrape.com/js/")
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "quote"))
)
Das wartet bis zu 10 Sekunden, bis das erste .quote-Element erscheint — nicht mehr, nicht weniger.
Schritt 3: Daten extrahieren — ein echtes Beispiel
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import csv
driver = webdriver.Chrome()
driver.get("https://quotes.toscrape.com/js/")
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "quote"))
)
quotes = driver.find_elements(By.CLASS_NAME, "quote")
with open("quotes.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.writer(f)
writer.writerow(["text", "autor"])
for quote in quotes:
text = quote.find_element(By.CLASS_NAME, "text").text
author = quote.find_element(By.CLASS_NAME, "author").text
writer.writerow([text, author])
driver.quit()
Dieselben zehn Zitate wie zuvor, diesmal von der Version, die nur durch Ausführen von JavaScript entsteht.
Headless ausführen (ohne sichtbares Fenster)
Wenn Sie auf einem Server laufen oder einfach kein Chrome-Fenster sehen wollen:
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
Wann Selenium sinnvoll ist — und wann nicht
- Selenium steuert einen kompletten Browser — mehrfach langsamer und schwerer als
requests - Prüfen Sie zuerst die DevTools des Browsers (Tab Network): Hat die Seite eine interne JSON-API, rufen Sie die direkt auf und sparen sich Selenium komplett
- Setzen Sie Selenium nur ein, wenn die Daten wirklich erst nach der JavaScript-Ausführung erscheinen
- Dieselben Regeln aus dem letzten Tutorial gelten weiterhin:
robots.txtprüfen, Pausen zwischen Anfragen einbauen, offizielle API bevorzugen, wenn es eine gibt
Übung
Klicken Sie statt nur der ersten zehn Zitate auf den Button „Next” (driver.find_element(By.LINK_TEXT, "Next").click()) und fügen Sie die Zitate der zweiten Seite derselben CSV-Datei hinzu.