Zurück zum Blog
Anleitungen
Mihai MaximLast updated on Mar 31, 20268 min read

HTML wie ein Profi analysieren: Web-Scraping mit Python und regulären Ausdrücken meistern

HTML wie ein Profi analysieren: Web-Scraping mit Python und regulären Ausdrücken meistern

Die Menge der im Internet verfügbaren Daten ist in den letzten Jahrzehnten stark angestiegen. Menschen nutzen diese Daten für eine Vielzahl von Zwecken, von persönlichen Interessen bis hin zur geschäftlichen Recherche.

Werden diese Daten jedoch nicht in einem formatierten Format wie XML oder JSON bereitgestellt, kann es schwierig oder unmöglich sein, sie mit Softwareanwendungen auszulesen. Hier kommt die Technik des Web Scraping ins Spiel.

Web Scraping ist der Prozess des Sammelns und Verarbeitens von Rohdaten aus dem Internet. Diese Daten werden geparst und für eine Vielzahl von Zwecken genutzt, wie beispielsweise Preisinformationen, Marktforschung, das Trainieren von KI-Modellen, Stimmungsanalysen, Markenaudits und SEO-Audits.

Einer der wichtigsten Aspekte des Web-Scrapings ist das Parsen von HTML. Dies kann mit einer Vielzahl von Tools erfolgen, wie beispielsweise BeautifulSoup für Python, Cheerio für NodeJS und Nokogiri für Ruby.

Reguläre Ausdrücke (Regex) sind Zeichenfolgen, die ein Suchmuster definieren.

In diesem Artikel werden wir untersuchen, wie man ein HTML-Dokument mithilfe von Regex und Python parst. Wir werden auch einige der Herausforderungen und alternativen Lösungen besprechen, die mit Web-Scraping einhergehen.

Am Ende des Artikels werden Sie ein umfassendes Verständnis des Themas sowie der verschiedenen verfügbaren Tools und Techniken haben.

Grundlagen der Regex-Analyse

Die meisten universellen Programmiersprachen unterstützen Regex. Sie können Regex in einer Vielzahl von Programmiersprachen verwenden, darunter Python, C, C++, Java, Rust, OCaml und JavaScript.

So sieht eine Regex-Regel zum Extrahieren des Werts aus dem <title>-Tag aus:

<title>(.*?)</title>

Beängstigend, nicht wahr? Denken Sie daran, dass dies erst der Anfang ist. Wir werden uns bald tiefer in die Materie vertiefen.

Für diesen Artikel verwende ich Python 3.11.1. Nehmen wir diese Regel und setzen wir sie in Code um. Erstelle eine Datei namens main.py und füge diesen Codeausschnitt ein:

import re

html = "<html><head><title>Scraping</title></head></html>"

title_search = re.search("<title>(.*?)</title>", html)

title = title_search.group(1)

print(title)

Sie können diesen Code ausführen, indem Sie den Befehl `python main.py` eingeben. Als Ausgabe erhalten Sie das Wort „Scraping“.

In diesem Beispiel verwenden wir das `re`-Modul, um mit regulären Ausdrücken zu arbeiten. Die Funktion `re.search()` sucht nach einem bestimmten Muster innerhalb einer Zeichenkette. Das erste Argument ist das Regex-Muster, und das zweite Argument ist die Zeichenkette, in der wir suchen.

Das Regex-Muster in diesem Beispiel lautet „<title>(.*?)</title>“. Es besteht aus mehreren Teilen:

  • <title>: Dies ist eine literale Zeichenkette, die genau mit den Zeichen „<title>“ übereinstimmt.
  • (.*?): Dies ist eine Erfassungsgruppe, die durch Klammern gekennzeichnet ist. Das Zeichen . passt auf ein beliebiges einzelnes Zeichen (außer einem Zeilenumbruch), und der Quantifizierer * bedeutet, dass 0 oder mehr des vorangehenden Zeichens gefunden werden sollen. Zusätzlich macht das ? das * nicht-gierig, was bedeutet, dass die Suche beendet wird, sobald das schließende Tag gefunden wird.
  • </title>: Dies ist ebenfalls eine literale Zeichenkette, die genau mit den Zeichen „</title>“ übereinstimmt.

Die Funktion re.search() gibt ein Match-Objekt zurück, wenn eine Übereinstimmung gefunden wird, und die Methode group(1) wird verwendet, um den Text zu extrahieren, der mit der ersten Erfassungsgruppe übereinstimmt, also den Text zwischen dem öffnenden und schließenden title-Tag.

Dieser Text wird der Variablen title zugewiesen, und die Ausgabe lautet „Scraping“.

Erweiterte Regex-Analyse

Das Extrahieren der Daten aus einem einzelnen HTML-Tag ist nicht besonders nützlich. Es gibt Ihnen zwar einen Einblick in die Möglichkeiten von regulären Ausdrücken, lässt sich aber in der Praxis nicht anwenden.

Schauen wir uns die PyPI-Website an, den Python Package Index. Auf der Startseite werden vier Statistiken angezeigt: die Anzahl der Projekte, die Anzahl der Releases, die Anzahl der Dateien und die Anzahl der Benutzer.

Wir möchten die Anzahl der Projekte extrahieren. Dazu können wir diesen regulären Ausdruck verwenden:

([0-9,]+) projects

Der reguläre Ausdruck findet jede Zeichenfolge, die mit einer oder mehreren Ziffern beginnt, optional durch Kommas getrennt, und mit dem Wort „projects“ endet. So funktioniert er:

  • ([0-9,]+): Dies ist eine Erfassungsgruppe, gekennzeichnet durch die Klammern; die eckigen Klammern [0-9,] passen auf jede Ziffer von 0 bis 9 und das Zeichen `,`; der Quantifizierer `+` bedeutet, dass 1 oder mehr der vorangehenden Zeichen übereinstimmen müssen.
  • projects: Dies ist eine wörtliche Zeichenfolge, die genau mit „projects“ übereinstimmt.

Zeit, die Regel zu testen. Aktualisieren Sie den Code in `main.py` mit diesem Ausschnitt:

import urllib.request

import re

response = urllib.request.urlopen("https://pypi.org/")

html = response.read().decode("utf-8")

matches = re.search("([0-9,]+) projects", html)

projects = matches.group(1)

print(projects)

Wir verwenden die Methode `urlopen` aus der Bibliothek `urllib`, um eine GET-Anfrage an die Website pypi.org zu stellen. Wir lesen die Antwort in die Variable `html` ein. Wir wenden die Regex-Regel auf den HTML-Inhalt an und geben die erste übereinstimmende Gruppe aus.

Führen Sie den Code mit dem Befehl `python main.py` aus und überprüfen Sie die Ausgabe: Es wird die Anzahl der Projekte auf der Website angezeigt.

Da wir nun einen einfachen Scraper haben, der das HTML-Dokument einer Website abrufen kann, wollen wir ein wenig mit dem Code experimentieren.

Mit dieser Regel können wir alle Links extrahieren:

href=[\'"]?([^\'" >]+)

Dieser reguläre Ausdruck besteht aus mehreren Teilen:

  • href=: Dies ist eine literale Zeichenkette, die genau mit den Zeichen „href=” übereinstimmt.
  • [\'"]?: Die eckigen Klammern [] passen auf jedes einzelne Zeichen in ihrem Inneren, in diesem Fall die Zeichen ' oder "; der Quantifizierer ? bedeutet, dass null oder eines der vorangehenden Zeichen übereinstimmen muss, d. h., der href-Wert kann von " oder ' umschlossen sein oder gar nicht vorhanden sein.
  • ([^\'" >]+): Dies ist eine Erfassungsgruppe, gekennzeichnet durch die Klammern; das ^ innerhalb der eckigen Klammern bedeutet Negation, es passt auf jedes Zeichen, das kein ', ", > oder ein Leerzeichen ist; der Quantifizierer + bedeutet, dass 1 oder mehr der vorangehenden Zeichen übereinstimmen müssen, d. h. die Gruppe erfasst ein oder mehrere Zeichen, die dem Muster entsprechen.

Bilder extrahieren

Noch eine Sache, dann sind wir fast fertig mit dem Schreiben der Regex-Regeln: Wir müssen die Bilder extrahieren. Verwenden wir diese Regel:

<img.*?src="(.*?)"

Dieser reguläre Ausdruck besteht aus mehreren Teilen:

  • <img: Dies ist eine literale Zeichenkette, die genau mit den Zeichen „<img“ übereinstimmt.
  • .*?: .* passt 0 oder mehr Mal auf ein beliebiges Zeichen (außer einem Zeilenumbruch), und der Quantifizierer ? bedeutet, dass so wenige wie möglich der vorangehenden Zeichen übereinstimmen sollen; dies wird verwendet, um auf jedes Zeichen zu passen, das vor dem src-Attribut im <img>-Tag erscheint, und ermöglicht es dem Muster, auf jedes <img>-Tag zu passen, unabhängig von der Anzahl seiner Attribute.
  • src=": Dies ist eine Literalzeichenfolge, die genau mit den Zeichen „src=” übereinstimmt.
  • (.*?): Dies ist eine Erfassungsgruppe, gekennzeichnet durch die Klammern; .*? passt auf ein beliebiges Zeichen (außer einem Zeilenumbruch) 0 oder mehr Mal, und der Quantifizierer ? bedeutet, dass so wenige wie möglich der vorangehenden Zeichen übereinstimmen sollen; diese Gruppe erfasst den src-Wert des <img>-Tags.
  • ": Dies ist eine Literalzeichenfolge, die genau mit dem Zeichen " übereinstimmt.

Probieren wir es aus. Ersetzen Sie den vorherigen Codeausschnitt durch diesen:

import urllib.request

import re

response = urllib.request.urlopen("https://pypi.org/")

html = response.read().decode("utf-8")

images = re.findall('<img.*?src="(.*?)"', html)

print(*images, sep = "\n")

Die Ausgabe dieses Codes zeigt eine Liste mit allen Bild-Links von der Pypi-Seite an.

Einschränkungen

Web-Scraping mit regulären Ausdrücken kann ein leistungsstarkes Werkzeug zum Extrahieren von Daten aus Websites sein, hat jedoch auch seine Grenzen. Eines der Hauptprobleme bei der Verwendung von Regex für Web-Scraping ist, dass es fehlschlagen kann, wenn sich die Struktur des HTML-Codes ändert.

Betrachten Sie zum Beispiel das folgende Codebeispiel, in dem wir versuchen, den Text aus dem h2-Tag mithilfe von Regex zu extrahieren:

<html>

   <head>

       <title>Example Title</title>

   </head>

   <body>

       <h1>Page Title</h1>

       <p>This is a paragraph under the title</p>

       <h2>First Subtitle</h2>

       <p>First paragraph under the subtitle</p>

       <h2>Second Subtitle</p>

   </body>

</html>

Vergleichen Sie das erste <h2>-Tag mit dem zweiten. Sie werden feststellen, dass das zweite <h2> nicht ordnungsgemäß geschlossen ist und der Code </p> anstelle von </h2> enthält. Aktualisieren wir den Codeausschnitt wie folgt:

import re

html = "<html><head><title>Example Title</title></head><body><h1>Page Title</h1><p>This is a paragraph under the title</p><h2>First Subtitle</h2><p>First paragraph under the subtitle</p><h2>Second Subtitle</p></body></html>"

headingTags = re.findall("<h2>(.*?)</h2>", html)

print(*headingTags, sep = "\n")

Führen wir den Code aus und überprüfen wir die Ausgabe:

First Subtitle

Der Text aus dem zweiten Überschriften-Tag fehlt. Dies geschieht, weil die Regex-Regel nicht mit dem nicht geschlossenen Überschriften-Tag übereinstimmt.

Eine Lösung für dieses Problem ist die Verwendung einer Bibliothek wie BeautifulSoup, mit der Sie die HTML-Baumstruktur durchsuchen können, anstatt sich auf reguläre Ausdrücke zu verlassen. Mit BeautifulSoup können Sie den Titel einer Webseite wie folgt extrahieren:

from bs4 import BeautifulSoup

html = "<html><head><title>Example Title</title></head><body><h1>Page Title</h1><p>This is a paragraph under the title</p><h2>First Subtitle</h2><p>First paragraph under the subtitle</p><h2>Second Subtitle</p></body></html>"

soup = BeautifulSoup(html, 'html.parser')

for headingTag in soup.findAll('h2'):

   print(headingTag.text)

BeautifulSoup kann fehlerhafte Tags extrahieren, und die Ausgabe sieht wie folgt aus:

First Subtitle

Second Subtitle

Dieser Ansatz ist robuster gegenüber Änderungen in der HTML-Struktur, da er nicht auf bestimmte Muster im HTML-Code angewiesen ist. Wenn Sie mehr über BeautifulSoup erfahren möchten, ist dieser Artikel genau das Richtige für Sie.

Eine weitere Lösung ist die Verwendung einer Web-Scraping-API wie WebScrapingAPI, die die Komplexität des Web-Scrapings abstrahiert und es Ihnen ermöglicht, die benötigten Daten einfach zu extrahieren, ohne sich um die zugrunde liegende HTML-Struktur kümmern zu müssen.

Mit WebScrapingAPI können Sie Daten von jeder Website mit einem einfachen API-Aufruf extrahieren, und Änderungen in der HTML-Struktur werden automatisch verarbeitet.

Abschließende Gedanken

Das Parsen von Daten mit regulären Ausdrücken kann ein leistungsstarkes Werkzeug zum Extrahieren von Daten aus Websites sein.

In diesem Artikel haben wir die Grundlagen regulärer Ausdrücke, deren Verwendung zum Parsen von HTML sowie einige der Herausforderungen besprochen, auf die Sie bei deren Einsatz stoßen können. Wir haben außerdem gesehen, wie Bibliotheken wie BeautifulSoup als alternative Lösung genutzt werden können.

Sie haben gelernt, wie Sie Daten mithilfe regulärer Ausdrücke aus Webseiten extrahieren und wie Sie die Zuverlässigkeit Ihres Codes durch die Verwendung einer robusteren Bibliothek wie BeautifulSoup verbessern können.

Web-Scraping kann eine zeitaufwändige Aufgabe sein, aber mit den richtigen Tools lässt es sich einfach und effizient durchführen. Wenn Sie nach einer Web-Scraping-Lösung suchen, die Ihnen Zeit und Mühe spart, probieren Sie WebScrapingAPI aus.

Wir bieten eine kostenlose 14-tägige Testversion an, in der Sie unseren Service testen und die Vorteile einer Web-Scraping-API kennenlernen können.

Über den Autor
Mihai Maxim, Full-Stack-Entwickler @ WebScrapingAPI
Mihai MaximFull-Stack-Entwickler

Mihai Maxim ist Full-Stack-Entwickler bei WebScrapingAPI, wo er in verschiedenen Bereichen des Produkts mitwirkt und an der Entwicklung zuverlässiger Tools und Funktionen für die Plattform mitarbeitet.

Los geht’s

Sind Sie bereit, Ihre Datenerfassung zu erweitern?

Schließen Sie sich den über 2.000 Unternehmen an, die WebScrapingAPI nutzen, um Webdaten im Unternehmensmaßstab ohne zusätzlichen Infrastrukturaufwand zu extrahieren.