11.4. Weitere Tipps und Tricks#
# Dieses Modul müsst ihr nicht importieren
from utils import skip
11.4.1. User Agent im HTTP-Header bearbeiten#
In manchen Fällen kann es notwendig sein, den Header der HTTP-Anfrage zu bearbeiten. Standardmäßig wird in einer HTTP-Anfrage über das requests-Paket als User Agent das requests-Paket angegeben:
# Default-Header der HTTP-Anfrage
import requests
url = "https://chroniclingamerica.loc.gov/search/pages/results/?andtext=&phrasetext=book+review&format=json"
response = requests.get(url)
print(response.request.headers)
{'User-Agent': 'python-requests/2.31.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
Macht es einen Unterschied, ob im Header als User Agent python-requests/2.29.0 oder Mozilla/5.0 (bzw. ein anderer Browser) steht? Ja, denn mit dem Default-Header erkennt der Server, dass die Anfrage von einer Webscraping Bibliothek ausgeht. Manche Websitebetreiber:innen behandeln solche Anfragen anders und schränken den Zugriff für solche Anfragen ein. Allerdings darf der User Agent nicht immer geändert werden, denn manche Nutzungsbedingungen schließen so eine Art der “Vortäuschung” explizit aus.
# User Agent im Request-Header ersetzen
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers)
Wenn eine requests Session verwendet wird, muss der Header sogar nicht im Gesamten ersetzt werden, sondern es können einzelne Werte ganz einfach ausgetauscht werden. Laut requests-Dokumentationsseiten geht das wie folgt:
# s = requests.Session()
# s.headers.update({'User-Agent': 'Mozilla/5.0'})
Wenn ihr Schnittstellen öffentlicher Institutionen nutzt, ist es oft empfehlenswert, als User Agent den Namen des Forschungsprojekts anzugeben. Manche Websitebetreiber:innen bitten sogar explizit darum, wie beispielsweise die Betreiber:innen der API der Gemeinsamen Normdatei (GND):
Wir bitten darum, bei der Nutzung von lobid eine aussagekräftige, wiederkehrende Zeichenkette als User Agent mitzusenden, damit wir bei der statistischen Auswertung unserer Infrastruktur Nutzungsweisen der API erkennen und unsere Dienstleistungen aus den gewonnenen Erkenntnissen verbessern können. Die statistische Erfassung der Nutzung dient außerdem der Begründung der Relevanz unserer Daten und Dienste gegenüber Geldgeber:innen und Entscheider:innen. In der Zeichenkette des User Agent kann sich die zugreifende Person, Institution oder ein Projekt zu erkennen geben, gegebenenfalls auch eine Kontaktmöglichkeit (E-Mail-Adresse) hinzufügen, eine anonyme beziehungsweise pseudonyme Kennung ist jedoch ebenso möglich. Eine solche Agent-Kennung sollte über die Dauer eines Projektes möglichst unverändert bleiben. (Quelle: lobid-gnd)
11.4.2. Selenium im Headless Mode#
Bisher haben wir Selenium immer so verwendet, dass sich beim Aufruf einer Seite der automatisierte Chrome Browser geöffnet hat. Wenn ihr gerade dabei seid, den Code zu schreiben, die Web Scraping-Strategie zu planen und die extrahierten Daten zu überprüfen, dann empfiehlt es sich, den Browser in diesem “sichtbaren” Modus zu automatisieren. Aber wenn das Skript dann fertig ist und ihr nicht mehr im Browserfenster nachverfolgen müsst, ob alle Aktionen so ausgeführt werden wie gewünscht, könnt ihr den Browser auch im sogenannten “headless mode” automatisieren, bei dem sich das Browserfenster nicht öffnet:
%%skip
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
11.4.3. Reguläre Ausdrücke#
Reguläre Ausdrücke (engl. Regular Expression, kurz: RegEx, RegExp) sind verallgemeinerte Suchmuster (patterns) für Zeichenketten. Mithilfe von regulären Ausdrücken können syntaktische Konstrukte so beschrieben werden, dass sie ein Computer versteht. Ein syntaktisches Konstrukt ist zum Beispiel eine Zahl zwischen 1900 und 2000, eine Telefonnummer, eine Adresse, eine URL oder auch ein bestimmtes Wort in verschiedenen Flexionsformen. Mithilfe von regulären Ausdrücken können also Texte nach bestimmten Mustern durchsucht werden, und die gefundenen Konstrukte können anschließend z.B. entfernt oder bearbeitet werden. Die meisten Programmiersprachen, darunter auch Python, stellen Funktionen bereit, welche die Verwendung von regulären Ausdrücken erlauben.
Bei der Bereinigung der extrahierten Daten sind reguläre Ausdrücke oft sehr nützlich. Deswegen lohnt es sich, sich mit dieser speziellen Sprache etwas zu beschäftigen und die Syntax zumindest in den Grundzügen zu verstehen. Als Einführung empfehle ich das Regular Expressions HOWTO in den Python-Dokumentationsseiten, und für einen schnellen Überblick über die Syntax empfehle ich dieses Cheatsheet, und für fortgeschrittene Themen empfehle ich regular-expressions.info. Regex-Suchmuster könnt ihr auch online testen, zum Beispiel auf der Seite https://regex101.com/.
Wir betrachten im Folgenden zwei typische Anwendungsfälle für reguläre Ausdrücke in Web Scraping Projekten.
Anwendungsbeispiel 1: Suche nach bestimmten Mustern in den Daten
In einer der letzten Übungsaufgaben solltet ihr mithilfe der Methode .str.contains()
überprüfen, ob die von der Seite Pinterest extrahierten Kommentare die Zeichenkette “cute” enthalten. Die Methode akzeptiert laut den Pandas Dokumentationsseiten als Argument eine “character sequence or regular expression”. Anstatt nur nach dem Wort “cute” zu suchen, könntet ihr einen regulären Ausdruck formulieren, der nach verschiedenen Varianten des Wortes und nach Synonymen sucht:
# comments_df["comment"].str.contains("(cuti?e)|(sweet(ie)?)")
Verständnisfrage
Welche Wörter werden mit diesem Suchmuster gefunden?
Wird auch die Zeichenkette “sweeti” gefunden?
Probiert es aus: Fügt das Suchmuster und einen Beispieltext auf der Seite https://regex101.com/ ein.
Anwendungsbeispiel 2: Dateinamen vor dem Speichern bearbeiten
Bisher haben wir Metadaten immer genauso, wie sie sind, als Dateinamen verwendet. Das ist aber nicht immer möglich oder gewünscht. Dateinamen können mithilfe von regulären Ausdrücken und der Funktion sub() aus dem Modul re aus der Python-Standardbibliothek bearbeitet werden. Die Funktion sub() tauscht alle Sequenzen in einem String, die einem gesuchten Muster entsprechen, gegen einen neuen String aus. Die Funktion nimmt einen regulären Ausdruck, einen String, gegen den die gefundenen Sequenzen ausgetauscht werden sollen, und einen String, in dem gesucht werden soll, als Argumente an. Ein Beispiel:
import re
title = "Arizona sun. [volume]_19550121.txt"
title = re.sub("\\. \\[volume\\]", "", title) # Zusatz [volume] entfernen
title = re.sub(" ", "_", title) # Leerzeichen durch Unterstriche ersetzen
title
'Arizona_sun_19550121.txt'
Für weitere Funktionen zur Arbeit mit regulären Ausdrücken schaut in die Dokumentationsseiten zum Modul re.
11.4.4. Fehler, Ausnahmen und Ausnahmebehandlung#
In Python gibt es verschiedene Arten von Fehlern: zum einen Syntaxfehler (syntax errors), die verhindern, dass Code überhaupt erst ausgeführt werden kann, und zum anderen Ausnahmen (exceptions), also Fehler, die dazu führen, dass die Ausführung des Codes abgebrochen und eine Fehlermeldung angezeigt wird. Bisher haben wir immer umgangssprachlich gesagt, dass eine Fehlermeldung “angezeigt” wird. Ganz korrekt würde man aber eigentlich sagen, dass eine Ausnahme “geworfen” wird. Eine Liste aller Ausnahmen, die beim Ausführen von Python-Code geworfen werden können, findet sich hier: https://docs.python.org/3/library/exceptions.html#bltin-exceptions.
Grundsätzlich sollte euer Code vorbeugend mit möglichen Fehlerquellen umgehen: Wenn ihr zum Beispiel Dateien über eine API bezieht, solltet ihr bei der Wahl des Dateinamens bedenken, dass Dateinamen zum Beispiel nicht unendlich lang sein dürfen, oder dass Schrägstriche in den Dateinamen beim Schreiben der Dateien fälschlich als Dateipfade interpretiert werden können. In beiden Fällen würde jeweils eine Ausnahme geworfen werden und die Ausführung des Codes würde abbrechen. Ihr solltet euren Code also immer vorausschauend schreiben. Im Beispiel mit den Dateinamen könnten vorausschauend Metadaten für die Dateinamen ausgewählt werden, welche immer dieselbe Form haben und somit immer gültig sind, oder indem die Dateinamen vor dem Schreiben der Dateien vereinheitlicht werden. Aber nicht immer kann im Voraus abgeschätzt werden, welche Art von ungültigen Werten auftreten können. Für diesen Fall gibt es in Python spezielle Anweisungen, die erlauben, bestimmte Ausnahmen gezielt abzufangen und so ein vorzeitiges Beenden des Programms zu verhindern: sogenannte try/exept-Anweisungen.
Try/except-Anweisungen haben die allgemeine Form:

Fig. 11.18 Try/Except-Anweisungen in der allgemeinen Form#
Der Code im except-Zweig wird dabei nur dann ausgeführt, wenn beim Ausführen des Codes im try-Zweig eine Ausnahme geworfen wird. Diese einfache try/except-Anweisung kann um weitere Zweige ergänzt werden. Das bereits zuvor in diesem Kurs zitierte Handbuch von Johannes Ernesti und Peter Kaiser enthält eine Überblicksdarstellung einer komplexen try/except-Anweisung mit mehreren Zweigen, inklusive Erläuterung:

Fig. 11.19 Schaubild: try/except-Anweisung mit mehreren Zweigen. Quelle: Ernesti und Kaiser (2020).#
Beispiele und weitere Erläuterungen zum Thema Ausnahmebehandlung findet ihr im erwähnten Handbuch von Ernesti und Kaiser, in diesem Beitrag von Said van de Klundert, und natürlich in den offiziellen Python-Dokumentationsseiten.
Note
Ausnahmen sollten immer so spezifisch wie möglich abgefangen werden. Prinzipiell ist es möglich, mit except Exception
alle möglichen Ausnahmen gleichzeitig abzufangen, aber das ist laut Ernesti und Kaiser (sowie den allermeisten seriösen Quellen zufolge) fast nie sinnvoll und kein guter Stil.
11.4.5. Verschiedene Lösungen vergleichen#
In der Sitzung “Fortsetzung BeautifulSoup” haben wir versucht, verschiedene Lösungen auf eine recht naive Art zu vergleichen, indem wir einfach die Zeit, die beim einmaligen Ausführen einer Codezelle verstrichen ist, gemessen haben. Die Ausführungszeit kann aber beim wiederholten Ausführen desselben Codeblocks schwanken. Um eine etwas genauere Messung zu erhalten, kann anstelle von %%time
%timeit
verwendet werden, um die durchschnittliche Ausführungszeit einer Funktion bei mehreren wiederholten Aufrufen zu messen. Als Beispiel messen wir die Ausführungszeit der is_even()-Funktion aus Abchnitt 4.1:
def is_even(i):
"""
Input: i, a positive int
Returns True if i is even, otherwise False
"""
return i%2 == 0
%timeit is_even(10)
55.4 ns ± 0.405 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Angenommen, wir haben eine weitere Lösung für dasselbe Problem gefunden: Anstatt den Modulo-Operator zu verwenden, um zu bestimmen, ob die angegebene Zahl durch 2 teilbar ist, reduzieren wir die Zahl in einer Schleife immer weiter um 2, bis 0 erreicht ist (oder nicht). Dann können wir die durchschnittliche Ausführungszeit dieser Lösung mit der ersten vergleichen:
def is_even_v2(i):
"""
Input: i, a positive int
Returns True if i is even, otherwise False
"""
while i > 1:
i -= 2
return i == 0
%timeit is_even_v2(10)
157 ns ± 5.13 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Der Vergleich der durchschnittlichen Ausführungszeit kann einen ersten Anhaltspunkt geben, welche der zwei Lösungen effizienter im Hinblick auf die Ausführungszeit ist.
Gerade beim Web Scrapen hängt die Ausführungszeit aber auch von Faktoren ab, die wir gar nicht kontrollieren können und die sich von Ausführung zu Ausführung unterscheiden können, zum Beispiel der Zeit, die der Server braucht, um eine Antwort zu senden. Deswegen reicht der Vergleich der durchschnittlichen Ausführungszeit oft alleine nicht aus. Die gemessene Laufzeit lässt beispielsweise keine Rückschlüsse darüber zu, wie sich die Laufzeit entwickelt, wenn nicht nur 10 oder 20 sondern 100, 1000 oder 10000 Anfragen gestellt und die extrahierten Daten verarbeitet werden sollen. Mit einer theoretischen Analyse der Laufzeit, also der Bestimmung der sogenannten “Laufzeitkomplexität” des Codes, kann untersucht werden, wie sich die Laufzeit bei einer immer größer werdenden Anzahl von Eingabe-URLs unabhängig von äußeren Einflüssen wie dem Rate Limit oder der Antwortzeit des Servers entwickelt. Einen leicht verständlichen Einstieg in das Thema findet ihr hier. Sehr, sehr kurz gefasst: Die theoretische Laufzeit wird anhand der Anzahl der grundlegenden Operationen in dem Code verglichen. Bei jedem Funktionsaufruf der Funktion is_even()
findet beispielsweise nur eine Operation statt: Der Ausdruck i % 2 == 0 berechnet den Rest der Division von i durch 2 und gibt direkt das Ergebnis zurück. Es findet also die gleiche Anzahl an Operationen statt, egal welche Zahl für i eingesetzt wird. Eine solche Laufzeit wird auch konstante Laufzeit genannt. Beim Aufruf der Funktion is_even_v2()
finden jedoch mehrere Operationen statt, wobei die Anzahl der Operationen steigt, wenn i größer ist, weil die while-Schleife für größere Zahlen mehr Durchläufe braucht, bis i < 1 ist. Eine solche Laufzeit wird lineare Laufzeit genannt, weil die Anzahl der Operationen proportional mit der Eingabegröße wächst. Die theoretische Laufzeit der Funktion is_even()
deswegen deutlich geringer als die der Funktion is_even_v2()
. In der formalen Syntax zur Beschreibung von Laufzeitkomlexität (der sogenannten O-Notation) wird die konstante Laufzeit der Funktion is_even()
als O(1) notiert und die lineare Laufzeit der Funktion is_even_v2()
als O(n).
11.4.6. Effizienter Scrapen mit Sitemaps#
Eine Sitemap ist eine strukturierte Übersicht über alle Unterseiten einer Website. Webseitenbetreiber:innen stellen Sitemaps zur Verfügung, damit beim Crawlen der Seite durch Web Crawler verschiedener Suchmaschinen alle Unterseiten einfach gefunden werden können. Je nach gesuchten Daten können Sitemaps auch beim Web Scraping eingesetzt werden, um effizienter eine Liste von zu scrapenden Unterseiten zusammenzustellen. Sitemaps werden meist im XML-Format bereitgestellt, das heißt, dass zur Suche in solchen Sitemaps ebenfalls XPath verwendet werden kann. Sitemaps sind oft unter der Adresse www.beispielwebseite.com/sitemap.xml erreichbar, aber anders als bei der robots.txt gibt es noch einige andere typische Adressen. Eine Übersicht über solche typischen Sitemap-Adressen findet ihr hier. Manche Webseitenbetreiber:innen verlinken die Sitemap zudem in der robots.txt. Dies ist zum Beispiel bei der Website realpython.com der Fall. Die Sitemap ist hier unter https://realpython.com/robots.txt verlinkt und hat die Adresse https://realpython.com/sitemap.xml. Die Sitemap selbst sieht so aus:

Fig. 11.20 Sitemap der Website realpython.com#
11.4.7. Abfragerate kontrollieren und Rate Limits einhalten in komplexeren Fällen#
Wir haben bereits im Abschnitt 8.3 im Zusammenhang mit der API der Library of Congress drei ganz grundlegende Strategien kennengelernt, wie die Anzahl der Anfragen über das Paket requests begrenzt werden kann. In den besprochenen Beispielen wurde aber immer nur einmal im Skript eine Anfrage gestellt, also zum Beispiel einmal im Körper eine for-Schleife. Aber was ist, wenn von mehreren Stellen im Code Anfragen an dieselbe Seite gestellt werden sollen? Dann müsst ihr sichergehen, dass die Anzahl der Anfragen im Gesamten limitiert wird, und nicht nur für eine der beiden Codeabschnitte. Eine einfache Lösung, die mit allen drei besprochenen Strategien umsetzbar ist, ist die Definition einer generischen fetch_content()
Funktion, über die alle Anfragen von überall im Code geleitet werden:
%%skip
import requests
from ratelimit import limits, sleep_and_retry
PERIOD_SEC = 60
CALLS_PER_PERIOD_SEC = 80
@sleep_and_retry
@limits(calls=CALLS_PER_PERIOD_SEC, period=PERIOD_SEC)
def fetch_content(url):
return requests.get(url)
def get_page(url):
response = fetch_content(url).json()
items = response["results"]
for item in items:
image_id = item["pk"]
image_url = item["image"]["full"]
image = fetch_content(image_url)
filename = f"{image_id}.jpg"
with open(filename, "wb") as file:
file.write(image.content)
base_url = "https://www.loc.gov/pictures/search/?q=suffragettes&fo=json"
no_pages = 14
for page in range(1, no_pages + 1):
request_url = f"{base_url}&sp={page}"
get_page(request_url)
Diesen Code erkennt ihr vermutlich wieder: Es handelt sich um eine vereinfachte Version der Musterlösung zum Übungsblatt 9.
11.4.8. Versionsverwaltung nutzen#
Im Laufe des Semesters hat sich euer Ordner mit den Notebooks bestimmt mit einer Reihe Dateien der Art “uebung_9_loesung_v1.ipynb”, “uebung_9_loesung_v2.ipynb”, “uebung_9_loesung_final.ipynb” gefüllt. Klar: Wenn ihr eine alternative Lösung gefunden habt, wollt ihr diese vielleicht nicht löschen, oder ihr wollt lieber erstmal eine Sicherheitskopie anlegen, bevor ihr den Code noch einmal umschreibt. Weil das beim Coden ein häufiges Problem ist, haben sich Systeme zur sogenannten Versionsverwaltung etabliert. In der professionellen Softwareentwicklung ist die Verwendung solcher Systeme ein unverzichtbarer Standard. Eine extrem verbreitete, kostenfreie und betriebssystemübergreifende Variante ist die Kombination von Git mit GitHub. Die Git-Dokumentationsseiten definieren Versionsverwaltung wie folgt:
Was ist “Versionsverwaltung”, und warum solltest du dich dafür interessieren? Versionsverwaltung ist ein System, welches die Änderungen an einer oder einer Reihe von Dateien über die Zeit hinweg protokolliert, sodass man später auf eine bestimmte Version zurückgreifen kann. Die Dateien, die in den Beispielen in diesem Buch unter Versionsverwaltung gestellt werden, enthalten Quelltext von Software. Tatsächlich kann in der Praxis nahezu jede Art von Datei per Versionsverwaltung nachverfolgt werden. (Quelle: Git Dokumentationsseiten)
Die mithilfe von Git lokal angelegten Git Repositories (also Ordner auf dem Computer, in denen mithilfe von Git Änderungen an Dateien nachverfolgt werden) können auf Online-Plattformen wie GitHub hochgeladen werden, um sie mit anderen zu teilen oder für die private Nutzung an zentraler Stelle zu speichern. In einem GitHub-Repository kann neben dem Code und den Daten für ein Webscraping-Projekt auch eine Datei mit den Versionen der verwendeten Python Pakete und der Python-Version geteilt werden. Das ist empfehlenswert, denn so macht ihr es anderen leichter, euren Code zu reproduzieren. Eine solche Datei könnt ihr ganz einfach in Anaconda Prompt bzw. dem Terminal generieren, indem ihr die virtuelle Umgebung aktiviert und dann eingebt conda env export --no-builds > environment.yml
. Diese Datei kann dann jemand anderes nutzen, um bei sich auf dem Computer mit dem Befehl conda env create -f environment.yml
eine virtuelle Umgebung mit denselben Paketen zu erstellen.
Über GitHub könnt ihr auch andere Projekte und Code, der zum Beispiel ein ganz konkretes Paket oder eine Funktion, deren Einsatzmöglichkeiten ihr verstehen wollt, suchen. Gebt dazu in der Suchmaske einfach den Namen des Pakets oder der Funktion ein und filtert die Ergebnisse anschließend nach der Programmiersprache. Bevor ihr euch dazu entscheidet, für eine Seite einen Web Scraper zu schreiben, könnt ihr auch erst einmal auf GitHub suchen, ob es vielleicht bereits einen Web Scraper für die Seite gibt. Aber Vorsicht! Bevor ihr fremden Code ausprobiert, lest euch den Abschnitt “Sicher scrapen” durch und trefft ggf. Vorsichtsmaßnahmen. Allgemein gilt: Wenn ein GitHub Repository viele Maintainer:innen hat und die letzten Änderungen (Commits) erst wenige Tage, Wochen oder Monate alt sind, dann handelt es sich meist um vertrauenswürdigen Code.
11.4.9. Aufbau von Python-Projekten#
Bisher habt ihr Code immer in Jupyter Notebooks geschrieben und ausgeführt. Aber wenn ihr euch auf GitHub oder woanders auf die Suche nach fremdem Code macht, dann begegnen euch häufig auch Pythonskripte mit der Dateiendung .py und größere Projekte, die aus mehreren .py, .ipynb oder anderen Dateien bestehen. Das kann verwirrend sein. Wenn euer Webscraping Projekt komplexer wird und nicht mehr nur aus einem Jupyter Notebook, sondern noch aus Input- und Output-Dateien oder weiteren Skripten besteht, fragt ihr euch vielleicht, wie ihr die verschiedenen Dateien am besten organisieren solltet. Wir schauen uns in der letzten Stunde ein paar Beispiele an. Zum Nachlesen empfehle ich die Kapitel 24: “Module Packages” und 25: Module Odds and Ends in Martin Lutz (2025), Learning Python.
11.4.10. Sicher Scrapen#
Die Anforderungen an Sicherheit und Anonymität können sich von Web Scraping Projekt zu Web Scraping Projekt unterscheiden. Ein paar Dinge sind aber allgemein empfehlenswert:
Achtet nach Möglichkeit darauf, dass in eurer Anfrage-URL https statt http steht.
Falls ihr euch auf einer Webseite anmelden müsst, um Inhalte scrapen zu können, solltet ihr immer ein Profil speziell für diesen Zweck erstellen. Gebt niemals sensible Passwörter in den automatisierten Chrome Browser ein.
Seid außerdem vorsichtig, wenn ihr verschiedene Tipps online lest: Bevor ihr einfach komplexen Code von stackoverflow oder einem ähnlichen Forum kopiert, recherchiert, ob es nicht vielleicht einen einfacheren Weg gibt, um euer Problem zu lösen. Denn wenn ihr gar nicht versteht, was ihr gerade macht, könnt ihr auch nicht abschätzen, welche Risiken das kopierte Vorgehen mit sich bringt, und welche Sicherheitsvorkehrungen die andere Person vielleicht vorher getroffen hat – das ist ja eigentlich selbsterklärend, aber im Eifer des Gefechts vergisst man das gerne.
Es empfiehlt sich außerdem, beim Web Scrapen ganz allgemein einen Useraccount auf eurem Computer zu verwenden, der keine Administratorrechte hat. Falls doch etwas schief gehen sollte, ist dadurch der Schaden zumindest begrenzt.
Wenn ihr ganz sicher gehen wollt, verwendet eine virtuelle Maschine zum Scrapen. Virtuelle Maschinen können mithilfe spezialisierter Software wie UTM für MacOS erstellt werden.
Je nach Web Scraping Projekt kann es empfehlenswert sein, die eigene IP Adresse mithilfe von VPN oder Proxy zu verstecken. Allerdings ist das ethisch und rechtlich eine schwierige Sache: Wir haben beispielsweise bereits besprochen, dass man sich strafbar machen kann, wenn man beim Web Scraping blockiert wird und anstatt seinen Web Scraper robots.txt-konform umzuschreiben einfach seine IP-Adresse versteckt. Hier ist also Vorsicht und Eigenrecherche geboten.
11.4.11. Don’t do this…#
Zum Schluss möchte ich euch noch eine kleine Empfehlung mit auf den Weg geben: Nicht immer ist Web Scraping wirklich die schnellste und effizienteste Lösung für euer Problem. Es macht wahrscheinlich mehr Spaß, Code zu schreiben, als direkt die Aufgabe anzugehen, aber wenn ihr unbedingt eine Deadline einhalten müsst, dann ist es natürlich auch okay, ein Web Scraping Projekt abzubrechen und eure Aufgabe einfach manuell zu lösen. Also in diesem Sinne:

Fig. 11.21 Don’t do this… Quelle: Kevin Sahin 2022#
11.4.12. Quellen#
Peter Ernesti, Johannes und Kaiser. Python 3: Ausnahmebehandlung. 2020. URL: https://openbook.rheinwerk-verlag.de/python/22_001.html.
Ognian Mikov. How to Find the Sitemap of a Website. 2021. URL: https://seocrawl.com/en/how-to-find-a-sitemap/.
Ryan Mitchell. Webscraping with Python. Collecting More Data from the Modern Web. O'Reilley, Farnham et al., 2018.
Jonathan Mondaut. Take Advantage of Sitemaps for Efficient Web Scraping: A Comprehensive Guide. 2023. URL: https://medium.com/@jonathanmondaut/take-advantage-of-sitemaps-for-efficient-web-scraping-a-comprehensive-guide-c35c6efe52d3.
Kenneth Reitz. Requests Documentation: Errors and Exceptions. 2023. URL: https://requests.readthedocs.io/en/latest/user/quickstart/?highlight=cookie#errors-and-exceptions.
Kevin Sahin. Web Scraping Using Selenium and Python. 2022. URL: https://www.scrapingbee.com/blog/selenium-python/.
Baiju Muthukadan. Selenium with Python. Waits. 2024. URL: https://selenium-python.readthedocs.io/waits.html.
Python 3.11.3 Documentation. Built-in Exceptions. URL: https://docs.python.org/3/library/exceptions.html#bltin-exceptions.
Python 3.11.3 Documentation. Compound Statements: The Try Statement. URL: https://docs.python.org/3/reference/compound_stmts.html#the-try-statement.
Python 3.11.3 Documentation. Errors and Exceptions. URL: https://docs.python.org/3/tutorial/errors.html.
Said van de Klundert. Python Exceptions: An Introduction. URL: https://realpython.com/python-exceptions/.
Selenium 4 Documentation. Browser Options: pageLoadStrategy. 2022. URL: https://www.selenium.dev/documentation/webdriver/drivers/options/#pageloadstrategy.
Selenium 4.10 Documentation. Waits. 2023. URL: https://www.selenium.dev/documentation/webdriver/waits/.
W3Docs. How to Find an Element by CSS Class Name with XPath. 2023. URL: https://www.w3docs.com/snippets/css/how-to-find-an-element-by-css-class-name-with-xpath.html.