Zurück zum Blog
Leitfäden
Suciu Dan13. April 20238 Minuten Lesezeit

Parsen Sie HTML wie ein Profi: Mastering Web Scraping mit Python und Regex

Parsen Sie HTML wie ein Profi: Mastering Web Scraping mit Python und Regex

Grundlegendes Regex-Parsing

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.

Here’s what a regex rule for extracting the value from the <title> tag looks like:

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

Beängstigend, nicht wahr? Denken Sie daran, dass dies erst der Anfang ist. Wir werden bald in den Kaninchenbau einsteigen.

Für diesen Artikel verwende ich Python 3.11.1. Nehmen wir diese Regel und setzen sie in Code um. Erstellen Sie eine Datei namens main.py und fügen Sie diesen Ausschnitt 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` ausführen. Das Ergebnis, das Sie als Ausgabe sehen, ist das Wort "Scraping".

In diesem Beispiel verwenden wir das Modul `re`, um mit Regex 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 Zeichenfolge, in der wir suchen.

The regex pattern in this example is "<title>(.*?)</title>". It consists of several parts:

  • <title>: This is a literal string, it will match the characters "<title>" exactly.
  • (.*?): Dies ist eine Erfassungsgruppe, die durch Klammern gekennzeichnet ist. Das Zeichen . passt auf jedes einzelne Zeichen (außer einem Zeilenumbruch), und der Quantifizierer * bedeutet, dass 0 oder mehr der vorangehenden Zeichen übereinstimmen. Außerdem macht ? den * nicht gierig, was bedeutet, dass er aufhört, sobald er den schließenden Tag findet.
  • </title>: This is also a literal string, it will match the characters "</title>" exactly.

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, d. h. den Text zwischen dem öffnenden und dem schließenden Titel-Tag.

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

Fortgeschrittenes Regex-Parsing

Das Extrahieren der Daten aus einem einzelnen HTML-Tag ist nicht sehr nützlich. Es gibt Ihnen einen Einblick, was Sie mit regulären Ausdrücken tun können, aber Sie können es nicht in einer realen Situation verwenden.

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 Veröffentlichungen, die Anzahl der Dateien und die Anzahl der Benutzer.

Wir wollen die Anzahl der Projekte extrahieren. Um dies zu erreichen, können wir diese Regex verwenden:

([0-9,]+) Projekte

Der reguläre Ausdruck passt auf jede Zeichenfolge, die mit einer oder mehreren Ziffern beginnt, optional durch Kommata getrennt, und mit dem Wort "projects" endet. So funktioniert er:

  • ([0-9,]+): Dies ist eine Erfassungsgruppe, die durch die Klammern gekennzeichnet ist; die eckigen Klammern [0-9,] entsprechen einer beliebigen Ziffer von 0 bis 9 und dem Zeichen `,`; der Quantifizierer + bedeutet, dass 1 oder mehrere der vorangehenden Zeichen übereinstimmen.
  • Projekte: Dies ist eine wörtliche Zeichenfolge, die genau mit "projects" übereinstimmt.

Es ist an der Zeit, die Regel auf die Probe zu stellen. Aktualisieren Sie den "main.py"-Code mit diesem Schnipsel:

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 urlopen-Methode aus der urllib-Bibliothek, um eine GET-Anfrage an die Website pypi.org zu stellen. Wir lesen die Antwort in der Variablen html. Wir lassen die Regex-Regel gegen den HTML-Inhalt laufen und drucken die erste übereinstimmende Gruppe aus.

Führen Sie den Code mit dem Befehl `python main.py` aus und prüfen Sie die Ausgabe: Sie zeigt die Anzahl der Projekte auf der Website an.

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

Mit dieser Regel können wir alle Links extrahieren:

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

Dieser reguläre Ausdruck besteht aus mehreren Teilen:

  • href=: Dies ist eine wörtliche Zeichenfolge, die genau mit den Zeichen "href=" übereinstimmt.
  • [\'"]?: die eckigen Klammern [] passen zu jedem einzelnen Zeichen innerhalb dieser Klammern, in diesem Fall zu den Zeichen ' oder "; der ? Quantifizierer bedeutet, dass er mit null oder einem der vorangehenden Zeichen übereinstimmt, d.h. der href-Wert kann mit " oder ' oder ohne eingeschlossen werden.
  • ([^\'" >]+): Dies ist eine Erfassungsgruppe, die durch die Klammern gekennzeichnet ist; das ^ in den eckigen Klammern steht für die Negation, d. h. es passt auf jedes Zeichen, das kein ',", > oder ein Leerzeichen ist; der Quantifizierer + bedeutet, dass mindestens ein Zeichen des vorangehenden Zeichens passt, d. h. die Gruppe erfasst ein oder mehrere Zeichen, die dem Muster entsprechen.

Bilder extrahieren

Eine Sache noch, und wir sind fast fertig mit dem Schreiben von Regex-Regeln: Wir müssen die Bilder extrahieren. Verwenden wir diese Regel:

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

Dieser reguläre Ausdruck besteht aus mehreren Teilen:

  • <img: This is a literal string, it will match the characters "<img" exactly.
  • .*?: the .* match any character (except a newline) 0 or more times, and the ? quantifier means to match as few as possible of the preceding character; this is used to match any character that appears before the src attribute in the <img> tag, and it allows the pattern to match any <img> tag regardless of the number of attributes it has.
  • src=": Dies ist eine wörtliche Zeichenfolge, die genau mit den Zeichen "src=" übereinstimmt.
  • (.*?): this is a capturing group, denoted by the parentheses; the .*? match any character (except a newline) 0 or more times, and the ? quantifier means to match as few as possible of the preceding character; this group captures the src value of the <img> tag.
  • ": Dies ist eine wörtliche Zeichenkette, die genau mit dem Zeichen " übereinstimmt.

Probieren wir es aus. Ersetzen Sie den vorherigen Codeschnipsel 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.

Beschränkungen

Web Scraping mit regulären Ausdrücken kann ein leistungsfähiges Werkzeug für die Extraktion von Daten aus Websites sein, hat aber 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 ändert.

Betrachten Sie zum Beispiel das folgende Codebeispiel, in dem wir versuchen, den Text aus h2 mit 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>

Compare the first <h2> tag with the second one. You may notice the second <h2> is not properly closed, and the code has </p> instead of </h2>. Let’s update the snippet with this:

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:

Erster Untertitel

Der Text des zweiten Überschrift-Tags fehlt. Dies geschieht, weil die Regex-Regel nicht auf das nicht geschlossene Überschrift-Tag passt.

Eine Lösung für dieses Problem ist die Verwendung einer Bibliothek wie BeautifulSoup, mit der Sie in der HTML-Baumstruktur navigieren und suchen 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 schafft es, fehlerhafte Tags zu extrahieren, und die Ausgabe sieht wie folgt aus:

Erster Untertitel

Zweiter Untertitel

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, sollten Sie diesen Artikel lesen.

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

Mit WebScrapingAPI können Sie mit einem einfachen API-Aufruf Daten aus jeder beliebigen Website extrahieren, wobei Änderungen an der HTML-Struktur automatisch berücksichtigt werden.

Abschließende Überlegungen

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

In diesem Artikel haben wir die Grundlagen der regulären Ausdrücke besprochen, wie man sie zum Parsen von HTML verwendet und auf welche Herausforderungen man bei ihrer Verwendung stoßen kann. Wir haben auch gesehen, wie Bibliotheken wie BeautifulSoup als alternative Lösung verwendet werden können.

Sie haben gelernt, wie man mit regulären Ausdrücken Daten aus Webseiten extrahiert und wie Sie die Zuverlässigkeit Ihres Codes durch den Einsatz einer robusteren Bibliothek wie BeautifulSoup verbessern können.

Web Scraping kann eine zeitraubende Aufgabe sein, aber mit den richtigen Tools kann es einfach und effizient sein. Wenn Sie auf der Suche nach einer Web-Scraping-Lösung sind, die Ihnen Zeit und Mühe spart, sollten Sie WebScrapingAPI ausprobieren.

Wir bieten eine kostenlose 14-tägige Testphase an, in der Sie unseren Service testen und sich von den Vorteilen einer Web Scraping API überzeugen können.

Über den Autor
Suciu Dan, Mitbegründer von WebScrapingAPI
Suciu DanMitbegründer

Suciu Dan ist Mitbegründer von WebScrapingAPI und verfasst praxisorientierte, auf Entwickler zugeschnittene Anleitungen zu den Themen Web-Scraping mit Python, Web-Scraping mit Ruby und Proxy-Infrastruktur.

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.