
Nach all den theoretischen Ratschlägen zu Python möchten wir jetzt ein praktisches Beispiel betrachten. Konkret werden wir eine Website scrapen, die aktuelle Kraftstoffpreise aus Polen veröffentlicht und für die keine kostenfreie API zur Verfügung steht. So unkompliziert, wie es in vielen Tutorials dargestellt wird, ist es jedoch selten. In den meisten Beispielen sind die Daten ordentlich in einem „div“ strukturiert, der über eine eindeutige „class“ verfügt. Bei solchen idealen Szenarien werden viele schnell überzeugt, dass Python die perfekte Sprache für Anfänger ist, selbst wenn es um das Extrahieren von Informationen von Webseiten geht. Die Praxis hält jedoch oft bedauerliche Herausforderungen bereit, die sich nicht mit lediglich 3 bis 8 Zeilen Python-Code bewältigen lassen – zumindest nicht für Einsteiger.
**Webmaster ändern gelegentlich den Quellcode** ihrer Webseiten, was dazu führen kann, dass ein Scraper zu einem späteren Zeitpunkt nicht mehr funktioniert. Eine effektive Methode, um solche Änderungen im Blick zu behalten, ist die Einrichtung von Continuous Integration. Diese Vorgehensweise ermöglicht es, dein Scraper-Skript regelmäßig zu testen. So wirst du umgehend informiert, sobald Fehler auftreten.
Nutze zur Analyse der Website am besten die Entwicklertools deines Browsers. Beim Firefox nennen sie sich“Firefox Tools für Webentwickler“ und sind über die Funktionstaste F12 erreichbar. Im Chrome übrigens auch.
Die Aufgabe
Im vorliegenden Beispiel sollen die aktuellen Diesel- und Benzinpreise von dieser Website extrahiert werden. Im Gegensatz zu den „Schulungsbeispielen“ handelt es sich hier um eine weit weniger klare Struktur. Die relevanten Informationen sind in einer unscheinbaren Tabelle untergebracht, die sich innerhalb mehrerer „div“-Elemente mit derselben „class“ befindet.
<div class="box"> <h3 class="page-header">Treibstoffpreise heute</h3> <table class="table table-hover"> <thead> <tr> <th>Treibstoff</th> <th>Durchschnittlich in Słubice</th> <th>Durchschnittlich in Polen</th> </tr> </thead> <tr> <td><img src="/img/fuels/default/gasoline.png" alt="" /> Benzin 95</td> <td>6,76 PLN/L</td> <td>6,63 PLN/L</td> </tr> <tr> <td><img src="/img/fuels/default/diesel.png" alt="" /> Diesel</td> <td>7,58 PLN/L</td> <td>7,42 PLN/L</td> </tr> <tr> <td><img src="/img/fuels/default/lpg.png" alt="" /> Autogas</td> <td>3,72 PLN/L</td> <td>3,72 PLN/L</td> </tr> <tr> <td><img src="/img/fuels/default/gasoline98.png" alt="" /> Benzin 98</td> <td>7,05 PLN/L</td> <td>7,05 PLN/L</td> </tr> </table> </div>
Wie bringen wir Python bei, diesen HTML-Code zu verstehen? Wir müssen zunächst in den HTML-Tags ein Schema erkennen, mit dessen Hilfe die Programmierer die Daten einkapseln, uns präsentieren.
Der Codeblock mit den Daten wird von einem DIV umschlossen:
<div class="box"> ... ... </di>
Die Inhalte in diesem DIV möchten wir auswerten. Wir schreiben uns jetzt folgendes kleines Script.
#!/usr/bin/python3 # ===== Abfangen von Fehlern try: # ===== Damit Ausgabe im Browser erfolgen kann print ("Content-Type: text/html; charset=UTF-8\n") # ===== Module importieren # Ggf. mit Befehl "pip3 install MODULNAME" auf Server per SSH installieren import sys import requests from bs4 import BeautifulSoup # ===== URL festlegen, die eingelesen werden soll baseURL = 'https://de.fuelo.net' stadt= '148291' URL = baseURL + '/gasstations/settlement/' + stadt + '?lang=de' # ===== HTTP Header head = {'User-Agent': 'Mozilla/4.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTM, like Gecko) Chrome/51.0.2704.103 Safari/537.36 '} # ===== Webseite aufrufen und parsen webseite = requests.get(URL, headers = head) quelltext = BeautifulSoup(webseite.text, 'html.parser') # ===== Inhalte auslesen inhalt_div = quelltext('div', {'class':'box'}) table_tr = inhalt_div[0]('tr') print ( f"Anzahl Zeilen: { len(inhalt_table_tr)} | Zeile 1 ist Kopfzeile ") print(inhalt_div[0]) print(table_tr [0]) except Exception as e: print("Fehlermeldung:", e)
In diesem Beispiel ist das Problem folgendes – die Daten werden nicht explizit mit „class“ oder „id“ gekennzeichnet. Die aktuellen Dieselpreise für die Stadt Slubize stehen stattdessen einsam im 2. <td>-Tag des 3. <tr>-Tag.
Als PHP-Programmierer bin ich vertraut damit, wie ich bestimmte Abschnitte aus dem Quellcode mithilfe von Delimitern und regulären Ausdrücken extrahiere, um sie weiter zu analysieren. Diese Technik beherrsche ich gut, und ein PHP-Scraper lässt sich in kürzester Zeit entwickeln. Doch wie verhält es sich in Bezug auf „Python für Anfänger“?
Die Bibliothek Beautiful Soup
Diese Bibliothek wurde geschaffen, um Informationen aus Webseiten „herauszuschneiden“. Doch aufgepasst, es gibt mehrere Versionen dieser Bibliothek, die nicht mit jeder Python Version funktioniert.
Die aktuelle und neuere Bibliothek Beautiful Soup 4 arbeitet mit Python 3 und Pythons 2. Beautiful Soup 3 hingegen funktioniert nur mit Python 2.
Tutorial zum Scraping mit dem Modul requests und Beautiful Soup 4.
Die Bibliothek „pandas“
Pandas ist eine Python-Bibliothek für die Analyse und Verarbeitung von Tabellen-Inhalten. Sie ist dann von Vorteil, wenn Tabellendaten
Aber lesen wir zunächst die Webseite ein.
import requests # Modul 'requests' zum Aufrufen von Webseiten wird importieet from bs4 import BeautifulSoup # Aus der Bibliothek 'Bs4' wird das Modul 'BeautifulSoup'geladen baseURL = 'https://de.fuelo.net' # Basis-URL stadt= '148291' # Parameter für die Stadt 'Slubize' URL = baseURL + '/gasstations/settlement/' + stadt + '?lang=de' # komplette url header = {'User-Agent': 'Mozilla/4.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTM, like Gecko) Chrome/51.0.2704.103 Safari/537.36 '} # ein Header kann nützlich sein, falls Websiten unbekannte Scraper blockeiren InhaltWebseite = requests.get(URL, headers = header) # Inhalt der angefragrten Webseite soup = BeautifulSoup(InhaltWebseite.text, 'html.parser') # geparster Inhalt # DivPreiseAktuell = soup('div', {'class':'box'})