Zurück zum Blog
Leitfäden
Mihnea-Octavian Manolache28. Februar 202311 Min. Lesezeit

Die ultimative Anleitung zum Erstellen eines Web Scrapers mit Pyppeteer

Die ultimative Anleitung zum Erstellen eines Web Scrapers mit Pyppeteer

Was ist Pyppeteer eigentlich und wie können Sie es nutzen?

Wenn Sie dies lesen, sind Sie wahrscheinlich bereits damit vertraut, was Web-Skripting im Allgemeinen ist. Und Sie haben wahrscheinlich schon von Puppeteer oder Selenium gehört, je nachdem, welche Programmiersprache Sie bevorzugen. Aber Pyppeteer ist in der Tat neu in der Szene des Web Scraping. Nun, um es kurz zu machen, Pyppeteer ist Puppeteer sehr viel ähnlicher als Selenium.

Puppeteer ist eine Node.js-Bibliothek, die die Steuerung einer Headless-Version von Chrome über das DevTools-Protokoll ermöglicht. Pyppeteer ist eine Python-Portierung von Puppeteer. Genau wie das Original Puppeteer ist Pyppeteer eine in Python geschriebene Bibliothek, die im Wesentlichen einen Browser automatisiert. Mit anderen Worten: Pyppeteer ist eine Python-Implementierung der Puppeteer-API, mit der Sie die Funktionen von Puppeteer in einer Python-Umgebung nutzen können. Der Hauptunterschied zwischen den beiden ist die verwendete Sprache.

Pyppeteer-Terminologie, die Sie kennen sollten

Bevor wir weitermachen, sollten wir einige Begriffe diskutieren, die im Zusammenhang mit Pyppeteer häufig verwendet werden:

  • Kopflos: Dies bedeutet, dass ein Browser ohne grafische Benutzeroberfläche (GUI) gestartet wird. Mit anderen Worten: Er läuft "hinter den Kulissen" und ist auf dem Bildschirm nicht zu sehen. Es wird normalerweise verwendet, um die Ressourcennutzung beim Scraping zu reduzieren.
  • Kopflastig: Ein "Headful"-Browser ist dagegen ein Browser, der mit einer grafischen Benutzeroberfläche läuft. Er ist das Gegenteil eines Headless-Browsers und wird häufig zum Testen, Debuggen oder für die manuelle Interaktion mit Webseiten verwendet.
  • Browser-Kontext: Dies ist ein Status, der von allen Seiten in einem Browser gemeinsam genutzt wird. Er wird normalerweise verwendet, um browserweite Einstellungen wie Cookies, HTTP-Header und Geolocation festzulegen.
  • DOM: Das Document Object Model (DOM) ist eine Programmierschnittstelle für HTML- und XML-Dokumente. Es stellt die Struktur einer Webseite in einem baumartigen Format dar, mit Knoten, die Elemente darstellen. Mit Pyppeteer können Sie mit den Elementen einer Seite interagieren, indem Sie das DOM manipulieren.
  • Elemente: Die Bausteine einer Web-Seite. Sie werden durch Tags, Attribute und Werte definiert.

Natürlich gibt es noch mehr, und Sie werden auf dem Weg dorthin noch einiges lernen. Aber ich wollte, dass Sie einen Überblick darüber bekommen, damit wir einen soliden Start haben. Ich bin überzeugt, dass die Kenntnis dieser Begriffe Ihnen helfen wird, das Wesentliche dieses Artikels besser zu verstehen.

Warum sollten Sie Pyppeteer für Ihr Scraping-Projekt verwenden?

Ich denke, es gibt zwei Aspekte in dieser Angelegenheit. Der erste ist, warum Pyppeteer eine gute Wahl für Web Scraping im Allgemeinen ist. Der zweite ist, warum Pyppeteer statt Selenium verwendet werden sollte. Im Allgemeinen sind einige der Vorteile von Pyppeteer für:

  • JavaScript auswerten: Pyppeteer bietet eine Funktion `page.evaluate()`. Damit können Sie JavaScript-Code im Kontext der Seite ausführen.
  • Netzsteuerung: Pyppeteer bietet eine `page.on()` Methode. Diese erlaubt es, auf Netzwerkereignisse, wie Anfragen und Antworten, die auf einer Seite passieren, zu hören.
  • Verfolgung und Protokollierung: Mit Pyppeteer können Sie die Aktivitäten des Browsers verfolgen und Browsermeldungen von einer Seite protokollieren. Dies erleichtert die Fehlersuche, das Tracing und das Verständnis der Aktivitäten einer Website.

Im Vergleich zu Selenium ist es recht ähnlich, da beide zur Automatisierung eines Webbrowsers verwendet werden. Es gibt jedoch ein paar wichtige Unterschiede und Vorteile, die Pyppeteer gegenüber Selenium hat:

  • Einfachheit: Pyppeteer hat eine einfachere und konsistentere API als Selenium, was die Nutzung für Anfänger erleichtert. Die Pyppeteer-API basiert auf dem DevTools-Protokoll, das dem Browser sehr ähnlich ist, und ist leicht zu erlernen und zu verwenden.
  • Leistung: Pyppeteer kann schneller sein als Selenium, weil es auf dem DevTools-Protokoll aufbaut. Das Protokoll wurde für das Debugging von Webseiten entwickelt und ist viel schneller als Selenium WebDriver.
  • Bessere Netzwerkkontrolle: Pyppeteer ermöglicht eine bessere Kontrolle über die Netzwerkeinstellungen des Browsers, wie z. B. das Abfangen von Anfragen und das Blockieren von Anfragen/Antworten. Dies erleichtert das Testen und Diagnostizieren von netzwerkbezogenen Problemen.

Und natürlich ist es auch eine Frage der Wahl. Nehmen Sie mich zum Beispiel. Ich programmiere tagtäglich in JavaScript. Und mit Puppeteer bin ich gut vertraut. Aber meine Lieblingsprogrammiersprache ist Python auf der anderen Seite. Wenn ich also einen Scraper mit einer bekannten Technologie in einer von mir bevorzugten Sprache bauen sollte, würde ich mich wahrscheinlich für Pyppeteer entscheiden.

Und damit haben wir, denke ich, die "Gesprächs"-Aspekte dieses Artikels abgedeckt. Es ist an der Zeit, mit der eigentlichen Codierung zu beginnen.

Wie man einen Web Scraper mit Pyppeteer erstellt

Bevor wir mit dem Programmieren beginnen, möchte ich Ihnen die offizielle Pyppeteer-Dokumentation vorstellen. Ich bin ein Verfechter der Verwendung der offiziellen Dokumentation, wann immer man sich festgefahren fühlt. Das heißt, bevor man Fragen in der Community stellt (z. B. auf Stackoverflow). Ich habe die Erfahrung gemacht, dass die meisten Antworten gefunden werden können, wenn man zuerst die Dokumentation liest. Nehmen Sie dies also als eine freundliche Bitte von mir. Wenn Sie nicht weiterkommen, lesen Sie die Dokumentation, suchen Sie dann nach Antworten und stellen Sie erst als letzten Ausweg Fragen.

#1: Einrichten der Umgebung

Das Wichtigste zuerst: Als Python-Entwickler sind Sie wahrscheinlich mit virtuellen Umgebungen vertraut. Das erste, was wir tun müssen, ist eine virtuelle Umgebung für unser Projekt zu erstellen. Im Allgemeinen verwende ich die folgende Befehlsfolge:

# Erstelle ein neues Verzeichnis und wechsle dorthin

~ » mkdir py_project && cd py_project 

# Erstelle die virtuelle Umgebung

~ » python3 -m venv env 

# Aktiviere die virtuelle Umgebung

~ » source env/bin/activate

Was die virtuelle Umgebung anbelangt, so ist nun alles vorbereitet. Nun ist es an der Zeit, Pyppeteer zu installieren. Da Sie Ihr Terminal geöffnet haben, geben Sie einfach ein:

# Installiere das Paket mit pip

~ » python3 -m pip install pyppeteer

# Öffne das Projekt in deiner IDE

~ » code .

#2: Einen einfachen Pyppeteer-Scraper erstellen

Mit dem letzten Befehl öffnen Sie Visual Studio Code oder Ihre bevorzugte IDE. Da Sie sich nun in der Entwicklungsumgebung befinden, lassen Sie uns eine neue `.py`-Datei erstellen, die unseren Code enthalten wird. Ich werde meine Datei `scraper.py` nennen. Beachten Sie, dass Pyppeteer von Haus aus asynchrone Ausführung unterstützt. Lassen Sie uns also sowohl `asyncio` als auch `pyppeteer` in unsere Datei importieren:

import asyncio
from pyppeteer import launch

Wenn das geschafft ist, können wir zu komplizierterem Code übergehen. Im Allgemeinen bin ich nicht der größte Verfechter der funktionalen Programmierung. Dennoch denke ich, dass die Aufteilung des Codes in kleine Teile ein besseres Lernen ermöglicht. Lassen Sie uns also unseren Code in eine Funktion einpacken:

async def scrape(url):

   browser = await launch()

   page = await browser.newPage()

   await page.goto(url)

   content = await page.content()

   await browser.close()

  

   return content
Nebeneinander angeordnete Code-Editor-Fenster, in denen ein Puppeteer-Skript angezeigt wird, das einen Browser startet und eine Seite lädt

Diese Funktion nimmt eine URL als Eingabe und startet einen Headless-Browser mit pyppeteer. Dann navigiert sie zu der angegebenen URL, ruft den Inhalt der Seite ab und schließt den Browser. Der zurückgegebene Wert ist nichts anderes als der von der Seite gesammelte HTML-Code. Mit dieser Funktion können Sie fast jede beliebige Website scrapen. Um die Funktion zu verwenden, rufen Sie sie in einer "Asyncio"-Ereignisschleife auf, etwa so:

async def main():

   content = await scrape('https://www.example.com')

   print(content)

loop = asyncio.get_event_loop()

loop.run_until_complete(main())

#Nr. 3: Mehr Funktionen hinzufügen

Bis zu diesem Punkt haben wir einen funktionierenden Abstreifer. Aber das ist so ziemlich alles, was wir haben. Wenn Sie einen fortschrittlicheren Web Scraper mit Pyppeteer bauen wollen, müssen Sie mehr Funktionalität zu id hinzufügen. Spoiler-Alarm: Wir werden in die Welt der objektorientierten Programmierung eintauchen. Aber lassen Sie uns zunächst unsere Ziele verfolgen. Was soll unser Scraper können?

  • Initialisieren des Browsers mit einigen benutzerdefinierten Werten
  • Navigieren und Extrahieren von Inhalten aus einer Webseite
  • Text in ein Eingabefeld schreiben
  • Den Wert eines einzelnen Elements extrahieren
  • Wert aus mehreren Elementen extrahieren

3.1. Benutzerdefinierte Optionen

Lassen Sie uns also erst einmal eine neue Klasse "Scraper" erstellen, deren Methoden wir später hinzufügen werden:

Klasse Scraper:

   def __init__(self, launch_options: dict) -> None:

       self.options = launch_options['options']

     self.viewPort = launch_options['viewPort'], sofern 'viewPort' in launch_options enthalten ist, andernfalls None

pass

Das einzige Argument, das wir für unseren Scraper verwenden, ist ein `launch_options`-Wörterbuch. Wie Sie sehen, enthält es zwei Schlüssel. Ein Schlüssel definiert die Startoptionen von Pyppeteer. Die zweite Option ist entweder `None` oder ein Wörterbuch, das die `width` und `height` des `viewPort` enthält. Letzteres wird für diese Methode verwendet.

3.2. Zu einer Seite navigieren

Wenn Sie sich die Funktion ansehen, die wir zuvor verwendet haben, werden Sie sehen, dass wir sowohl das Navigieren als auch das Extrahieren von Rohdaten aus einer bestimmten URL abdecken. Das Einzige, was wir tun müssen, ist, die Funktion zu optimieren und in eine Methode für unseren Scraper zu verwandeln:

async def goto(self, url: str) -> None:

       self.browser = await launch(options=self.options)

       self.page = await self.browser.newPage()

       await self.page.setViewport(self.viewPort) if self.viewPort != None else print('[i] Verwende Standard-Viewport')

       await self.page.goto(url)

Diese Methode ist recht einfach. Zuerst wird ein neuer Browser gestartet, mit den benutzerdefinierten Optionen, die wir zuvor festgelegt haben. Dann wird eine neue Seite erstellt und, wenn unser `launch_options` Wörterbuch `viewPort` enthält, wird der viewPort der Seite gesetzt. Andernfalls wird eine einfache Meldung protokolliert. Zu guter Letzt führt es uns zum Ziel.

3.3. Extrahieren von Rohdaten aus einer Seite

Wieder haben wir die Methode in unserer anfänglichen "Scraper"-Funktion. Wir werden nur darauf warten, dass der "page.content()" geladen wird und seinen Wert zurückgibt:

async def get_full_content(self) -> str:

       content = await self.page.content()

       return content

3.4. Text in ein Eingabefeld schreiben

Um mit Pyppeteer etwas in ein Eingabefeld zu schreiben, benötigen Sie zwei Dinge. Erstens muss das Element gefunden werden. Zweitens muss man ihm einen Wert hinzufügen. Glücklicherweise hat Pyppeteer Methoden für diese beiden Aktionen:

async def type_value(self, selector: str, value: str) -> None:

       element = await self.page.querySelector(selector)

       await element.type(value)

3.5. Wert von Seite extrahieren

Denken Sie daran, dass wir in der Lage sein wollen, entweder den Wert aus einem einzelnen Element oder Werte aus mehreren Elementen zu extrahieren. Wir könnten eine einzige Methode für beides verwenden. Aber ich mag es normalerweise, wenn die Dinge getrennt sind. Deshalb füge ich jetzt zwei weitere Methoden hinzu:

async def extract_one(self, selector) -> str:

       element = await self.page.querySelector(selector)

       text = await element.getProperty("textContent")

       return await text.jsonValue()

Hier suchen wir das Element mit der Methode "querySelector". Dann warten wir auf den "textContent" und geben seinen "jsonValue()" zurück. Wenn wir hingegen viele Elemente auswählen wollen, verwenden wir "querySelector":

async def extract_many(self, selector) -> list:

       result = []

       elements = await self.page.querySelectorAll(selector)

       for element in elements:

           text = await element.getProperty("textContent")

           result.append(await text.jsonValue())

       return result

Diese Methode funktioniert ähnlich wie `extract_one`. Der einzige Unterschied ist ihr Rückgabewert. Dieses Mal geben wir eine Liste aller Texte innerhalb der ausgewählten Elemente zurück. Und ich denke, damit haben wir alle unsere Ziele erreicht.

#Nr. 4: Unsichtbar machen

Beim Web-Scraping kann Stealthiness als die Fähigkeit beschrieben werden, unentdeckt zu bleiben. Natürlich erfordert die Entwicklung eines völlig unentdeckbaren Scrapers eine Menge Arbeit. Der Stealth-Modus der Web Scraping API wird zum Beispiel von einem engagierten Team gepflegt. Und der Aufwand, der darin steckt, macht den Fingerabdruck unseres Scrapers bei jeder Anfrage einzigartig.

Aber mein übergeordnetes Ziel für dieses Tutorial ist es, Sie auf den richtigen Weg zu bringen. Und der richtige Weg für einen kompletten Web Scraper mit Pyppeteer beinhaltet das Hinzufügen einiger Stealth-Funktionen. Glücklicherweise gibt es, genau wie `puppeteer-extra-plugin-stealth` in Node, auch ein Paket für Python. Und es heißt intuitiv `pyppeteer-stealth`. Um es zu Ihrem Projekt hinzuzufügen, installieren Sie es zunächst mit pip:

~ " python3 -m pip install pyppeteer_stealth

Importieren Sie es dann in Ihr Projekt und fügen Sie einfach eine zusätzliche Codezeile hinzu:

async def goto(self, url: str) -> None:

       self.browser = await launch(options=self.options)

       self.page = await self.browser.newPage()

	  # Unsichtbar machen

       await stealth(self.page)  

       await self.page.setViewport(self.viewPort) if self.viewPort != None else print('[i] Standard-Viewport wird verwendet')

       await self.page.goto(url)

Und hier sehen Sie, wie Sie Ihren Scraper ausführen. Ich habe dem Code einige Kommentare hinzugefügt, um hervorzuheben, was die einzelnen Schritte bewirken:

async def main():

   # Define the launch options dictionary

   launch_options = {

       'options': {

           'headless': False,

           'autoClose': True

       },

       'viewPort': {

           'width': 1600,

           'height': 900

       }

   }

   # Initialize a new scraper

   scraper = Scraper(launch_options)

   # Navigae to your target

   await scraper.goto('https://russmaxdesign.github.io/accessible-forms/accessible-name-input01.html')

   # Type `This is me` inside the input field

   await scraper.type_value(

       '#fish',

       'This is me')

   # Scrape the entire page

   content = await scraper.get_full_content()

   print(content)

   # Scrape one single element

   el = await scraper.extract_one('body > div:nth-child(14) > ul')

   print(el)

   # Scrape multiple elements

   els = await scraper.extract_many('p')

   print(els)

loop = asyncio.get_event_loop()

loop.run_until_complete(main())

Schlussfolgerung

Pyppeteer ist ein erstaunliches Werkzeug für Web Scraping. Es portiert die gesamte Puppeteer-API nach Python und ermöglicht es der Python-Gemeinschaft, diese Technologie zu nutzen, ohne JavaScript lernen zu müssen. Ich glaube nicht, dass es ein Ersatz für Selenium ist, aber es ist sicher eine gute Alternative zu Selenium.

Ich hoffe, dass der heutige Artikel einen Mehrwert für Ihren Lernweg darstellt. Und da ich gerne die Grenzen jedes Einzelnen ausreizen möchte, fordere ich Sie auf, das heute Gelernte zu erweitern. Der Scraper, den wir gemeinsam gebaut haben, ist ein wirklich guter Ausgangspunkt und führt in ein Schlüsselelement der Programmierung ein: OOP. Ich fordere euch also auf, dem `Scraper` weitere Methoden hinzuzufügen und ihn wirklich erstaunlich zu machen.

Über den Autor
Mihnea-Octavian Manolache, Full-Stack-Entwickler bei WebScrapingAPI
Mihnea-Octavian ManolacheFull-Stack-Entwickler

Mihnea-Octavian Manolache ist Full-Stack- und DevOps-Entwickler bei WebScrapingAPI. Er entwickelt Produktfunktionen und sorgt für die Wartung der Infrastruktur, die den reibungslosen Betrieb der Plattform gewährleistet.

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.