Python-Kurs / HTML-Daten mit Beautiful Soup gezielt extrahieren
Verwenden Sie zum Auslesen von HTML einen Dokumentparser, der Elemente nach Struktur auswählt und deren Text oder Attribute liest. Prüfen Sie erwartete Anzahlen und Pflichtfelder zusätzlich, damit geänderte Klassen oder Markup-Strukturen nicht unbemerkt zu scheinbar gültigen leeren Ergebnissen führen.
Mit einem kontrollierten statischen Dokument beginnen
Diese Übung verarbeitet eine selbst vorgegebene HTML-Zeichenfolge und sendet keine Anfragen an eine Website. HTML-Parsing und das Abrufen fremder Inhalte sind getrennte Schritte. Beim späteren externen Abruf müssen passende Zugriffsrechte, Nutzungsbedingungen, Anfrageraten und die Behandlung persönlicher Daten berücksichtigt werden.
Beautiful Soup ist eine zusätzliche Bibliothek. Der Installationsname lautet beautifulsoup4, der Importname dagegen bs4. Installieren Sie sie in derselben Projektumgebung, mit der Sie anschließend das Programm starten:
python -m pip install beautifulsoup4
Das Beispiel wählt ausdrücklich html.parser, also den HTML-Parser der Python-Standardbibliothek. Bei unvollständigem oder fehlerhaftem HTML können unterschiedliche Parser zu unterschiedlichen Bäumen gelangen; legen Sie deshalb die beabsichtigte Auswahl fest, statt sie einer zufälligen Umgebung zu überlassen. Die Beautiful-Soup-Dokumentation beschreibt Installation, Parser und Auswahloperationen.
Die vollständige Extraktion ausführen
Speichern Sie die folgende vollständige Datei als parse_html.py mit UTF-8 in einem eigenen Übungsordner. Führen Sie python parse_html.py in der Umgebung mit installiertem Beautiful Soup aus. Unter macOS oder Ubuntu kann außerhalb einer virtuellen Umgebung der Interpreterbefehl python3 heißen.
from bs4 import BeautifulSoup
html = """<ul id="expenses">
<li data-amount="3500"><span class="name">coffee</span></li>
<li data-amount="8000"><span class="name">lunch</span></li>
</ul>"""
soup = BeautifulSoup(html, "html.parser")
rows = soup.select("#expenses > li")
if len(rows) != 2:
raise ValueError("unexpected row count")
total = 0
for row in rows:
name = row.select_one(".name")
amount_text = row.get("data-amount")
if name is None or not amount_text or not amount_text.isascii() or not amount_text.isdecimal():
raise ValueError("missing or invalid field")
amount = int(amount_text)
print(name.get_text(" ", strip=True), amount)
total += amount
print("total:", total)
Erwartete Ausgabe:
coffee 3500
lunch 8000
total: 11500
Die Auswahl liefert zwei Listenelemente mit den Betragsattributen 3500 und 8000. Vor der Umwandlung werden vorhandener Betragstext, ASCII-Zeichen und Dezimalziffern verlangt. Dadurch werden ein Minuszeichen und alphabetischer Text abgelehnt; null und führende Nullen bleiben als nichtnegative Ganzzahltexte erlaubt.
Die Prüfung läuft je Zeile vor deren Ausgabe. Ein Fehler in der zweiten Zeile kann deshalb auftreten, nachdem die erste bereits gedruckt wurde. Die abschließende Gesamtzeile fehlt dann. Verwenden Sie solche Teilausgaben nicht als Beleg einer vollständig gelungenen Extraktion; wenn Ihre Anwendung nur vollständige Ergebnisse weitergeben darf, prüfen Sie zunächst alle Zeilen und veröffentlichen Sie erst danach.
Selektoren, fehlende Elemente und Textabstände verstehen
| Ausdruck | Bedeutung in dieser Übung |
|---|---|
#expenses > li |
Direkte li-Kinder des Elements mit der ID expenses |
.name |
Ein Nachfahre mit der Klasse name innerhalb der aktuellen Zeile |
row.get("data-amount") |
Attributwert oder None bei fehlendem Attribut |
get_text(" ", strip=True) |
Textteile mit Leerzeichen verbinden und Randabstände der Teile entfernen |
Das Zeichen > beschränkt die erste Auswahl auf direkte Kinder. Ein Leerzeichen als Nachfahrenkombinator würde dagegen auch tiefer verschachtelte passende Elemente berücksichtigen. Der Klassen-Selektor .name ist auf die aktuelle Zeile eingegrenzt, damit nicht versehentlich ein Name aus einer anderen Zeile ausgewählt wird.
select_one liefert beim Fehlen eines passenden Elements None. Prüfen Sie diesen Fall, bevor Sie dessen Text lesen. Ein vorhandenes, aber leeres Namenselement wird vom Beispiel hingegen nicht abgelehnt. Falls ein nichtleerer Name verlangt ist, müssen Sie auch das Ergebnis von get_text überprüfen. Ein Strukturtreffer garantiert keinen sinnvollen Feldinhalt.
Bei coffee<b>large</b> verbindet der Textseparator die Teile zu coffee large, statt sie direkt zusammenzukleben. Das kann nützlich sein, ist aber eine gewählte Normalisierung. Beurteilen Sie anhand Ihrer Felder, welche Leerzeichen erhalten oder ergänzt werden sollen.
Beautiful Soup sieht nur die übergebene Zeichenfolge. Führt eine Website später JavaScript aus und erzeugt zusätzliche Elemente, sind diese nicht allein deshalb im heruntergeladenen HTML vorhanden. Vergleichen Sie vor einer Fehlersuche die tatsächliche Antwort mit der im Browser sichtbaren Struktur. Der Kurs zu regulären Ausdrücken erklärt die andere Aufgabe der Textmustersuche; ein Muster für einzelne Textstellen ersetzt nicht die Dokumentstruktur.
Änderungen und Fehler bewusst erkennen
Das Programm verlangt exakt zwei Zeilen, weil die kontrollierte Eingabe zwei Datensätze enthält. Bei einem anderen Datenvertrag müssen Sie einen sinnvollen erwarteten Bereich und die erforderlichen Felder festlegen. Null Treffer können eine geänderte Struktur bedeuten; behandeln Sie sie nicht automatisch als erfolgreichen leeren Bestand.
- Ändern Sie in der ersten HTML-Zeile nur die Klasse
namein einen anderen Namen. Die Pflichtfeldprüfung muss fehlschlagen. Stellen Sie die Klasse danach wieder her. - Ändern Sie den ersten Betrag erst zu
-1, dann zuabc. Beide Varianten müssen vor einer passenden Ausgabe abgelehnt werden. Eine Ganzzahlumwandlung allein wäre keine Prüfung der vorgesehenen Ziffernregel. - Fügen Sie im ersten Namen vorübergehend ein verschachteltes Tag ein und vergleichen Sie die Leerzeichen des extrahierten Texts. Stellen Sie anschließend das Original wieder her.
- Entfernen Sie versuchsweise eine vollständige Zeile. Die Anzahlprüfung muss scheitern, bevor die Schleife Teildaten ausgibt.
Für reale Sammler prüfen Sie außerdem Höchstlängen und Betragsbereiche und halten Sie den beobachteten Umfang fest. Die einzelne numerische Feldprüfung bestätigt nicht die Echtheit einer Transaktion oder eine vollständige Sammlung. Ein klarer Fehlerstatus ist hilfreicher als eine stillschweigend abgesenkte Treffererwartung.




