Zurück zum Blog
Anleitungen
Gabriel CiociLast updated on May 1, 202615 min read

Web Scrape mit Puppeteer und NodeJS 2026 Anleitung

Web Scrape mit Puppeteer und NodeJS 2026 Anleitung
Kurzfassung: Mit Puppeteer haben Sie von Node.js aus die volle Kontrolle über eine Headless-Chrome-Instanz, was es zum Werkzeug der Wahl für das Scraping von JavaScript-gerenderten Seiten macht. Dieser Leitfaden führt Sie durch die Installation, die selektorbasierte Extraktion, Infinite Scroll, die Anmeldung über Formulare, das Abfangen von Anfragen, Stealth-Plugins, den Export strukturierter Daten und die Bereitstellung mit Docker, damit Sie von einem einfachen Testskript zu einem Scraper für den produktiven Einsatz gelangen.

Web-Scraping ist die Praxis, Daten programmgesteuert von Websites zu extrahieren, und wenn diese Websites auf clientseitiges JavaScript zurückgreifen, um ihre Inhalte darzustellen, reicht eine einfache HTTP-Anfrage nicht aus. Sie benötigen einen echten Browser oder zumindest etwas, das sich wie einer verhält. Genau dieses Problem sollte Puppeteer lösen.

Puppeteer ist eine Node.js-Bibliothek, mit der Sie Web-Scraping mit Puppeteer und Node.js durchführen können, indem Sie eine headless (oder headful) Chrome-Instanz über das Chrome DevTools-Protokoll steuern. Es kann auf Schaltflächen klicken, Formulare ausfüllen, Seiten scrollen und beliebiges JavaScript im Seitenkontext auswerten und die Ergebnisse dann an Ihr Skript zurückgeben. Für Entwickler, die bereits mit JavaScript vertraut sind, ist dies einer der natürlichsten Wege in die JavaScript-Workflows für Headless-Browser-Scraping.

In diesem Tutorial lernen Sie, wie Sie ein Puppeteer-Projekt von Grund auf einrichten, Daten aus statischen und dynamischen Seiten extrahieren, mit Paginierung und unendlichem Scrollen umgehen, versteckte API-Aufrufe abfangen, Bot-Erkennung vermeiden, Ihre Ergebnisse in JSON und CSV exportieren und das Ganze in einem Docker-Container bereitstellen. Alle Code-Beispiele sind für Node.js 18 oder höher ausgelegt, und wir beziehen uns durchgehend auf die Puppeteer v24-API. Ganz gleich, ob Sie einen Preis-Tracker, eine Pipeline zur Lead-Generierung oder ein akademisches Forschungstool entwickeln – die Muster in diesem Leitfaden bringen Sie schneller in die Produktion.

Wie Puppeteer unter der Haube funktioniert

Wenn Sie puppeteer.launch(), startet die Bibliothek einen Chromium- (oder Chrome-)Prozess und verbindet sich über das Chrome DevTools Protocol (CDP) damit. CDP ist eine WebSocket-basierte Schnittstelle, die nahezu alle Browserfunktionen bereitstellt: DOM-Inspektion, Netzwerküberwachung, Eingabesimulation und mehr. Ihr Node.js-Skript sendet Befehle über diesen Socket, und Chromium antwortet mit den Ergebnissen.

Diese Architektur bedeutet, dass Puppeteer kein vereinfachter Browsersimulator ist. Es führt echtes V8-JavaScript, eine echte Rendering-Engine und einen echten Netzwerkstack aus. Seiten, die auf fetch, Web Workers oder Shadow DOM verhalten sich genauso wie im Browser eines Benutzers. Das macht es zu einer so zuverlässigen Wahl, wenn Sie mit Puppeteer und NodeJS Web-Scraping auf Websites durchführen möchten, die Inhalte dynamisch rendern.

Puppeteer unterstützt sowohl den Headless-Modus (kein sichtbares Fenster, schneller, ideal für Server) als auch den Headful-Modus (ein sichtbares Browserfenster, nützlich für die Fehlersuche). Standardmäßig werden aktuelle Puppeteer-Versionen mit einer gebündelten Chromium-Binärdatei ausgeliefert, sodass Sie keinen Browser separat installieren müssen. Wenn Sie genauer verstehen möchten, was ein Headless-Browser ist, gibt es hervorragende Ressourcen, die die Architektur und gängige Anwendungsfälle erläutern.

Einrichten Ihres Node.js-Projekts und Installieren von Puppeteer

Bevor Sie Scraping-Code schreiben, vergewissern Sie sich, dass Sie Node.js 18 oder höher installiert haben. Zum Zeitpunkt der Erstellung dieses Artikels erfordert Puppeteer v24 mindestens Node.js 18.0.

node --version   # should print v18.x or higher
mkdir puppeteer-scraper && cd puppeteer-scraper
npm init -y
npm install puppeteer

Durch das Ausführen npm install puppeteer lädt die Bibliothek sowie eine kompatible Chromium-Binärdatei herunter (ca. 170 MB). Wenn Sie bereits über eine eigene Chrome-Installation verfügen oder eine schlankere Installation wünschen, können Sie stattdessen puppeteer-core verwenden, wodurch der Download des mitgelieferten Browsers übersprungen wird. Dies ist in Docker- und CI-Umgebungen üblich, in denen Sie Chromium über den System-Paketmanager installieren.

Ihr Projektordner sollte nun ein node_modules Verzeichnis und eine package.json , in dem Puppeteer als Abhängigkeit aufgeführt ist. Erstellen Sie eine Datei namens scraper.js (oder scraper.mjs , wenn Sie ES-Module bevorzugen), und schon können Sie Ihr erstes Node.js-Web-Scraper-Projekt mit Puppeteer erstellen.

Ein kurzer Hinweis: Das Puppeteer-Team aktualisiert das gebündelte Chromium mit jeder neuen Version, daher hilft das Fixieren einer bestimmten Version (zum Beispiel npm install puppeteer@24.26.1) hilft dabei, Ihre CI-Builds über verschiedene Umgebungen hinweg reproduzierbar zu halten.

Ihr erster Scraper: Starten, navigieren und HTML extrahieren

Das klassische Einstiegsziel für das Web-Scraping mit Puppeteer ist „Quotes to Scrape“, eine Sandbox-Website, die speziell zum Üben von Extraktionstechniken erstellt wurde.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto('https://quotes.toscrape.com', {
    waitUntil: 'domcontentloaded',
  });

  const html = await page.content();
  console.log(html.substring(0, 500));

  await browser.close();
})();

Hier ist der Ablauf Schritt für Schritt:

  1. puppeteer.launch() startet einen headless Chromium-Prozess.
  2. browser.newPage() Öffnet einen leeren Tab.
  3. page.goto() navigiert zur Ziel-URL. Die waitUntil Option teilt Puppeteer mit, wann die Navigation als abgeschlossen gilt. Die Verwendung von domcontentloaded ist schneller als networkidle0 , kann jedoch verzögert geladene Inhalte übersehen.
  4. page.content() gibt den vollständig gerenderten HTML-Code der Seite zurück.
  5. browser.close() beendet den Browserprozess und gibt Ressourcen frei.

Dieses Grundgerüst bildet die Basis für jeden Puppeteer-Scraper, den Sie erstellen werden. Das Muster bleibt gleich: starten, navigieren, extrahieren, schließen. Was sich ändert, ist die Extraktionslogik in der Mitte, auf die wir in den folgenden Abschnitten näher eingehen werden.

Führen Sie das Skript mit node scraper.js und Sie sollten rohen HTML-Code in Ihrem Terminal sehen. Wenn Sie unter Linux Fehlermeldungen wegen fehlender gemeinsam genutzter Bibliotheken erhalten, springen Sie zum Abschnitt „Bereitstellung“, um die Lösung zu finden.

Für eine vollständige Übersicht über Browser- und Seitenmethoden ist die offizielle Puppeteer-API-Dokumentation die zuverlässigste Quelle.

Warten auf dynamische Inhalte und Parsen von Elementen

Statische Seiten sind der einfache Fall. Dynamische Websites laden Inhalte nach der anfänglichen HTML-Antwort, manchmal über XHR-Aufrufe, manchmal über clientseitige Rendering-Frameworks. Puppeteer bietet mehrere Wartestrategien, um dies zu handhaben, wenn du mit Puppeteer und NodeJS moderne Single-Page-Anwendungen webscrapest.

Der zuverlässigste Ansatz ist page.waitForSelector(), der die Ausführung pausiert, bis ein bestimmter CSS-Selektor im DOM erscheint:

await page.goto('https://quotes.toscrape.com');
await page.waitForSelector('.quote');

Sobald die Elemente vorhanden sind, verwenden Sie page.evaluate() , um JavaScript im Browserkontext auszuführen und Daten zurück an Node.js zu übermitteln:

const quotes = await page.evaluate(() => {
  const items = document.querySelectorAll('.quote');
  return Array.from(items).map(item => ({
    text: item.querySelector('.text').innerText,
    author: item.querySelector('.author').innerText,
    tags: Array.from(item.querySelectorAll('.tag')).map(t => t.innerText),
  }));
});

console.log(quotes);

Ein paar Dinge, die du bei page.evaluate():

  • Der Callback wird im Browser ausgeführt, nicht in Node.js. Sie können darin nicht auf Node.js-Variablen oder -Module verweisen.
  • Der Rückgabewert muss serialisierbar sein (einfache Objekte, Arrays, Strings, Zahlen). Sie können keine DOM-Elemente direkt zurückgeben.
  • Wenn ein Selektor keine Übereinstimmung findet, querySelector gibt null, was einen Fehler auslöst, wenn Sie versuchen, .innerText. Das Umschließen des Zugriffs in eine optionale Verkettung (?.) oder eine Nullprüfung verhindert stille Abstürze in der Produktion.

Bei Seiten, die Inhalte eher über einen Timer als über ein DOM-Ereignis laden, page.waitForTimeout() fungiert als Fallback, aber bevorzugen Sie nach Möglichkeit selektorbasierte Wartezeiten, da diese schneller und deterministischer sind. Wenn Sie sich zwischen einer vollständigen Browser-Automatisierungsbibliothek und einem leichteren Parser entscheiden müssen, können Ihnen Leitfäden, die Cheerio und Puppeteer vergleichen, dabei helfen, das richtige Werkzeug für die Aufgabe auszuwählen.

Scraping gängiger dynamischer Muster

Die meisten realen Scraping-Ziele stellen nicht alle ihre Daten beim Laden einer einzigen Seite bereit. Sie werden auf Paginierung, unendliches Scrollen, Login-Wände und andere interaktive Muster stoßen. Im Folgenden finden Sie die drei häufigsten Muster, mit denen Sie umgehen müssen, wenn Sie mit Puppeteer und NodeJS Produktionswebsites scrapen.

Paginierte Inhalte und Crawling mehrerer Seiten

Paginierung ist das häufigste Muster, auf das Sie stoßen werden. Die Strategie ist einfach: Extrahieren Sie Daten von der aktuellen Seite, suchen Sie den „Weiter“-Link, navigieren Sie dorthin und wiederholen Sie den Vorgang, bis keine Seiten mehr vorhanden sind.

let currentPage = 1;
const allQuotes = [];

while (true) {
  await page.waitForSelector('.quote');
  const pageQuotes = await page.evaluate(() =>
    Array.from(document.querySelectorAll('.quote')).map(q => ({
      text: q.querySelector('.text').innerText,
      author: q.querySelector('.author').innerText,
    }))
  );
  allQuotes.push(...pageQuotes);

  const nextButton = await page.$('li.next > a');
  if (!nextButton) break;

  await Promise.all([
    page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
    nextButton.click(),
  ]);
  currentPage++;
}

console.log(`Scraped ${allQuotes.length} quotes across ${currentPage} pages.`);

Das entscheidende Detail ist das Einfügen von click() und waitForNavigation() innerhalb Promise.allein. Wenn Sie zuerst klicken und dann warten, könnte Puppeteer das Navigationsereignis verpassen, da es bereits ausgelöst wurde. Diese Race-Condition-Absicherung ist für zuverlässiges Crawling mehrseitiger Inhalte unerlässlich.

Durch Hinzufügen einer Wiederholungslogik wird dieses Muster produktionsreif. Umschließen Sie die Navigation mit einem try/catch, legen Sie ein Timeout für waitForNavigationund wiederholen Sie den Versuch bis zu dreimal, bevor Sie den Fehler protokollieren und fortfahren. Diese Art der Fehlerbehandlung unterscheidet Puppeteer-Scraping-Beispiele in Blogbeiträgen von Scrapern, die über Nacht unbeaufsichtigt laufen.

Seiten mit unendlichem Scrollen

Infinite Scroll ersetzt die Paginierung durch einen „Load More“-Trigger, der durch das Scrollen zum Ende der Seite ausgelöst wird. Social-Media-Feeds und Produktlistenseiten verwenden dieses Muster häufig. Um eine dynamische Website mit Puppeteer zu scrapen, scrollen Sie programmgesteuert und warten darauf, dass neue Inhalte erscheinen.

async function autoScroll(page, maxScrolls = 10) {
  let previousHeight = 0;
  let scrollCount = 0;

  while (scrollCount < maxScrolls) {
    previousHeight = await page.evaluate(() => document.body.scrollHeight);
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    await new Promise(r => setTimeout(r, 1500));

    const newHeight = await page.evaluate(() => document.body.scrollHeight);
    if (newHeight === previousHeight) break;
    scrollCount++;
  }
}

Die Funktion vergleicht scrollHeight vor und nach jedem Scrollvorgang. Wenn sich die Höhe nicht mehr ändert, sind entweder alle Inhalte geladen oder es muss auf eine Schaltfläche „Mehr anzeigen“ geklickt werden. Fügen Sie eine maxScrolls Obergrenze hinzu, um Endlosschleifen auf Seiten mit wirklich endlosen Feeds zu vermeiden. Du kannst auch die Anzahl der Elemente auf der Seite (über querySelectorAll) als sekundäres Beendigungssignal verfolgen, das Fälle erfasst, in denen neue Inhalte geladen werden, ohne die Gesamthöhe der Seite zu verändern.

Schaltflächen anklicken, Formulare ausfüllen und einloggen

Das Scraping hinter einer Login-Barriere erfordert die Interaktion mit Formularen. Puppeteers page.type() simuliert das Tippen Tastenanschlag für Tastenanschlag, und page.click() löst echte Mausereignisse aus, was wichtig ist, da einige Websites auf Eingabeereignisse achten, anstatt nur Feldwerte zu überprüfen.

await page.goto('https://quotes.toscrape.com/login');
await page.type('#username', 'testuser');
await page.type('#password', 'testpass');
await Promise.all([
  page.waitForNavigation(),
  page.click('input[type="submit"]'),
]);

Nach der Anmeldung behält die Browsersitzung Cookies automatisch für die weitere Navigation bei. Sie können während dieser Sitzung weiterhin auf authentifizierte Seiten zugreifen, ohne Ihre Anmeldedaten erneut eingeben zu müssen. Wenn die Website zunächst ein Cookie-Einwilligungsbanner anzeigt, klicken Sie auf die Schaltfläche „Akzeptieren“, bevor Sie mit dem Anmeldeformular interagieren.

Für komplexere Formularabläufe (mehrstufige Assistenten, Datei-Uploads, Dropdown-Auswahlen) bietet Puppeteer Methoden wie page.select() für <select> Elemente und elementHandle.uploadFile() für Dateieingaben. Sie können das Absenden von Formularen mit Puppeteer in speziellen Anleitungen erkunden, die diese fortgeschrittenen Interaktionen behandeln.

Netzwerkanfragen abfangen und versteckte APIs erfassen

Hier ist eine Technik, die in den meisten Tutorials zum Web-Scraping mit Puppeteer komplett übersprungen wird: Anstatt das DOM zu parsen, fangen Sie die Netzwerkanfragen der Seite ab und extrahieren die strukturierten JSON-Nutzdaten direkt aus den API-Aufrufen der Website.

Viele moderne Websites rufen ihre Daten über XHR- oder Fetch-Anfragen ab und rendern sie clientseitig. Wenn Sie diese Payloads erfassen können, umgehen Sie den heiklen Umgang mit CSS-Selektoren gänzlich.

await page.setRequestInterception(true);

page.on('response', async (response) => {
  const url = response.url();
  if (url.includes('/api/products') && response.status() === 200) {
    try {
      const data = await response.json();
      console.log('Captured API response:', data);
    } catch (e) {
      // Not a JSON response, skip
    }
  }
});

page.on('request', (request) => {
  const blocked = ['image', 'font', 'stylesheet'];
  if (blocked.includes(request.resourceType())) {
    request.abort();
  } else {
    request.continue();
  }
});

await page.goto('https://example-spa.com');

Dieser Ansatz ist aus zwei Gründen leistungsstark. Erstens ist die Antwort bereits strukturiertes JSON, sodass Sie überhaupt keine Selektoren schreiben müssen. Zweitens ist er im Laufe der Zeit tendenziell stabiler, da sich API-Verträge seltener ändern als UI-Markup.

Um herauszufinden, welche Endpunkte eine Seite aufruft, öffnen Sie den DevTools-Tab „Netzwerk“ Ihres Browsers auf der Zielseite, filtern Sie nach „Fetch/XHR“ und suchen Sie nach Antworten, die die benötigten Daten enthalten. Filtern Sie dann in Ihrem Interception-Handler nach diesen URL-Mustern. Diese Technik zum Erfassen versteckter APIs ist eines der stärksten Alleinstellungsmerkmale, die Sie Ihrem Puppeteer-Node.js-Scraping-Toolkit hinzufügen können. Sie ermöglicht es Ihnen, mit Puppeteer und NodeJS effizienter zu scrapen, indem Sie das DOM-Parsing für API-gestützte Seiten vollständig vermeiden.

Leistungsoptimierung und paralleles Scraping

Eine einzelne Puppeteer-Seite verarbeitet Anfragen nacheinander. Wenn Sie Tausende von URLs scrapen müssen, wird dieser serielle Ansatz zu einem Engpass. Hier sind die beiden wirkungsvollsten Optimierungen zur Skalierung Ihres Node.js-Web-Scraper-Puppeteer-Workflows.

Blockieren Sie unnötige Ressourcen. Bilder, Schriftarten, Stylesheets und Mediendateien verbrauchen Bandbreite und verlangsamen das Laden von Seiten, ohne scrapbare Daten beizusteuern. Das Deaktivieren des Ladens von Bildern und Videos ist eine der effektivsten Methoden, um Puppeteer-Scraper zu beschleunigen, und es verursacht keinen Datenverlust, da diese Ressourcen im DOM-Markup weiterhin zugänglich bleiben. Verwenden Sie Request Interception, um diese Ressourcentypen abzubrechen (wie im vorherigen Abschnitt gezeigt). Diese einzelne Änderung kann die Ladezeiten von Seiten auf medienintensiven Websites um die Hälfte reduzieren.

Führen Sie mehrere Seiten gleichzeitig aus. Puppeteer ist von Natur aus asynchron, und Node.js bewältigt Parallelität gut durch Promise.all. Anstatt URLs nacheinander zu verarbeiten, öffnen Sie mehrere Seiten und scrapen Sie diese parallel:

const urls = ['https://example.com/1', 'https://example.com/2', 'https://example.com/3'];
const browser = await puppeteer.launch({ headless: true });

const scrape = async (url) => {
  const page = await browser.newPage();
  try {
    await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 15000 });
    const title = await page.evaluate(() => document.title);
    return { url, title };
  } catch (err) {
    return { url, error: err.message };
  } finally {
    await page.close();
  }
};

const results = await Promise.all(urls.map(scrape));
console.log(results);

Beachten Sie den try/catch/finally Block. In der Produktion kommt es gelegentlich zu Zeitüberschreitungen oder Fehlern bei einzelnen Seiten. Das Umschließen jeder Aufgabe stellt sicher, dass eine fehlerhafte URL nicht den gesamten Stapel zum Absturz bringt. Der finally Block garantiert, dass die Seite auch bei einem Fehler geschlossen wird, wodurch Speicherlecks verhindert werden.

Eine praktische Obergrenze für die Parallelität liegt bei 5 bis 10 Seiten pro Browserinstanz, abhängig vom Arbeitsspeicher Ihres Rechners. Darüber hinaus sollten Sie in Erwägung ziehen, mehrere Browserinstanzen zu starten oder URLs in aufeinanderfolgende Blöcke zu gruppieren. Jede Chromium-Seite verbraucht etwa 30 bis 80 MB Speicher, und das summiert sich schnell, wenn Sie Dutzende von Tabs gleichzeitig ausführen. Für wirklich groß angelegte Aufgaben sollten Sie vielleicht auf eine verwaltete Browser-Cloud umsteigen, anstatt Chrome lokal zu hosten.

Bot-Erkennung vermeiden: Proxys und Stealth-Plugins

Auch wenn Puppeteer einen echten Browser ausführt, können Websites automatisierten Datenverkehr dennoch durch JavaScript-Fingerprinting, Header-Analyse und Verhaltensheuristiken erkennen. Wenn Sie schon einmal erlebt haben, dass ein Scraper bei 20 Anfragen einwandfrei funktioniert und dann plötzlich CAPTCHAs zurückgibt, ist die Bot-Erkennung der Grund dafür.

Stealth-Plugins sind die erste Verteidigungslinie. Das Paket „puppeteer-extra-plugin-stealth“ patcht mehrere bekannte Erkennungsvektoren: das navigator.webdriver Flag, Chrome-Plugin-Arrays, WebGL-Renderer-Strings und mehr. Überprüfen Sie zum Zeitpunkt der Erstellung dieses Artikels, ob die von Ihnen installierte Stealth-Plugin-Version mit Ihrer Puppeteer-Version kompatibel ist, da die beiden Bibliotheken nach größeren Releases nicht mehr synchron sein können.

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());

const browser = await puppeteer.launch({ headless: true });

Die Proxy-Rotation ist die zweite Verteidigungsschicht. Durch die Rotation Ihrer ausgehenden IP-Adresse bei den Anfragen wird es für eine Website wesentlich schwieriger, Ihren Datenverkehr zuzuordnen und zu blockieren. Sie können bei der Einrichtung Ihres Puppeteer-Stealth-Scrapings beim Start einen Proxy übergeben:

const browser = await puppeteer.launch({
  args: ['--proxy-server=http://proxy-address:port'],
});

Eine Einschränkung, die Sie beachten sollten: Die native API von Puppeteer unterstützt keinen Proxy-Wechsel pro Anfrage. Der Proxy wird auf Browserebene festgelegt, sodass eine Änderung einen Neustart der Browserinstanz erfordert. Für eine Proxy-Rotation mit hohem Datenvolumen in Puppeteer ist dies ohne eine externe Proxy-Verwaltungsschicht oder einen dedizierten Residential-Proxy-Pool unpraktisch.

Über technische Maßnahmen hinaus sollten Sie auch angemessene Verzögerungen zwischen den Anfragen einfügen und die robots.txt . Ein verantwortungsbewusstes Verhalten verringert das Risiko einer IP-Sperre und sorgt dafür, dass Ihr Scraper länger läuft. Eine umfassende Sammlung praktischer Strategien finden Sie in den Tipps zur Vermeidung von Sperren beim Web-Scraping.

Exportieren von gescrapten Daten in JSON und CSV

Das Protokollieren der Ergebnisse in der Konsole ist für die Fehlersuche in Ordnung, aber Produktions-Scraper benötigen eine strukturierte Dateiausgabe. Node.js macht dies mit dem integrierten fs Modul.

JSON-Export:

const fs = require('fs');
const data = [{ text: 'Example quote', author: 'Author' }];
fs.writeFileSync('quotes.json', JSON.stringify(data, null, 2), 'utf-8');

CSV-Export:

const header = 'text,author\n';
const rows = data.map(d => `"${d.text}","${d.author}"`).join('\n');
fs.writeFileSync('quotes.csv', header + rows, 'utf-8');

Für eine robustere CSV-Generierung (Umgang mit Kommas innerhalb von Werten, Sonderzeichen und großen Datensätzen) sollten Sie eine Bibliothek wie csv-stringify oder fast-csvin Betracht. Diese bewältigen Sonderfälle wie eingebettete Anführungszeichen und mehrzeilige Felder, die bei einem einfachen Template-Literal-Ansatz übersehen werden.

Wählen Sie JSON, wenn die nachgelagerten Verbraucher andere Programme oder APIs sind. Wählen Sie CSV, wenn die Daten für Tabellenkalkulationen, Datenbanken mit CSV-Import oder nicht-technische Stakeholder bestimmt sind, die die Datei in Excel öffnen möchten. Unabhängig davon, für welches Format Sie sich entscheiden, ist es bei lang laufenden Jobs, die unterwegs abstürzen könnten, entscheidend, die Daten während des Webscrapings mit Puppeteer und NodeJS schrittweise auf die Festplatte zu schreiben (anstatt alles im Speicher anzuhäufen).

Bereitstellung von Puppeteer auf Servern und in Docker

Puppeteer-Scraper, die unter macOS einwandfrei funktionieren, fallen oft aus, sobald man sie auf einem Linux-Server bereitstellt. Der Headless-Chrome-Browser übernimmt Betriebssystempakete, und Linux-Servern fehlen in der Regel die GUI-bezogenen gemeinsam genutzten Bibliotheken, die Chromium erwartet.

Installieren Sie für Debian- oder Ubuntu-Server die fehlenden Abhängigkeiten:

apt-get update && apt-get install -y \
  ca-certificates fonts-liberation libasound2 libatk1.0-0 \
  libcups2 libdbus-1-3 libgdk-pixbuf2.0-0 libnspr4 libnss3 \
  libx11-xcb1 libxcomposite1 libxrandr2 xdg-utils

Für Docker-Bereitstellungen sieht eine minimale Dockerfile-Datei wie folgt aus:

FROM node:18-slim
RUN apt-get update && apt-get install -y chromium
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["node", "scraper.js"]

Zwei wichtige Startflags für containerisierte Umgebungen:

puppeteer.launch({
  headless: true,
  args: ['--no-sandbox', '--disable-setuid-sandbox'],
});

Ohne --no-sandboxweigert sich Chromium in den meisten Docker-Containern zu starten. Diese Flags sind in einem containerisierten Scraper sicher, in dem Sie die Eingabe-URLs kontrollieren, vermeiden Sie sie jedoch in Umgebungen, die nicht vertrauenswürdige Inhalte verarbeiten. Das Hinzufügen Ihres Docker-bereitgestellten Scrapers zu einer CI-Pipeline (GitHub Actions, GitLab CI) ist unkompliziert, sobald der Container korrekt erstellt wird und läuft. Bei diesem Bereitstellungsschritt stoßen viele Entwickler auf Hindernisse. Planen Sie daher von Anfang an, Web-Scraping mit Puppeteer und NodeJS in einer containerisierten Umgebung durchzuführen, wenn Sie wissen, dass Sie eine Serverbereitstellung benötigen.

Web-Scraping mit Puppeteer und NodeJS im Vergleich zur Verwendung von Playwright

Wenn Sie Tools für das Headless-Browser-Scraping evaluieren, ist Ihnen wahrscheinlich auch Playwright begegnet. Beide Bibliotheken haben gemeinsame Wurzeln (Playwright wurde von ehemaligen Puppeteer-Maintainern entwickelt), zielen jedoch auf unterschiedliche Anforderungen ab.

Funktion

Puppeteer

Playwright

Browser-Unterstützung

Chromium, Firefox (experimentell)

Chromium, Firefox, WebKit

Sprach-SDKs

JavaScript/TypeScript

JS/TS, Python, Java, C#

Automatischer Warte-Mechanismus

Manuell (waitForSelector, waitForNavigation)

Integrierte automatische Wartefunktion bei den meisten Aktionen

Community-Plugins

Großes Ökosystem (puppeteer-extra, stealth)

Kleineres Plugin-Ökosystem

Am besten geeignet für

Chrome-orientiertes Scraping, bestehende JS-Codebasen

Browserübergreifende Tests, mehrsprachige Teams

Wenn Ihre Scraping-Ziele nur Chromium erfordern und Ihr Team bereits mit JavaScript arbeitet, ist Puppeteer die einfachere, ausgereiftere Wahl mit einem größeren Plugin-Ökosystem. Playwright glänzt, wenn Sie Multi-Browser-Unterstützung benötigen oder in einer anderen Sprache als JavaScript arbeiten. Für einen umfassenderen Überblick über die Optionen können Sie sich andere Puppeteer-Alternativen ansehen, um das Tool zu finden, das Ihren Projektanforderungen am besten entspricht.

Unabhängig davon, für welche Bibliothek Sie sich entscheiden, lassen sich die in diesem Leitfaden behandelten Kernkonzepte (Wartestrategien, Abfangen von Anfragen, Maßnahmen zur Tarnung, Fehlerbehandlung) mit nur geringfügigen API-Unterschieden direkt auf Playwright übertragen.

Wichtige Erkenntnisse

  • Puppeteer steuert einen echten Chromium-Browser über das DevTools-Protokoll an und eignet sich daher ideal zum Scrapen von JavaScript-gerenderten Seiten, die einfache HTTP-Clients nicht verarbeiten können.
  • Verwenden Sie immer waitForSelector anstelle von festen Timeouts, verpacken Sie Navigationsklicks in Promise.allund fügen Sie try/catch Blöcke um Seitenoperationen, um robuste Scraper zu erstellen.
  • Fangen Sie Netzwerkanfragen ab, um versteckte API-JSON-Nutzdaten direkt zu erfassen, und umgehen Sie dabei instabile DOM-Selektoren vollständig.
  • Kombinieren Sie Stealth-Plugins und Proxy-Rotation, um das Risiko der Bot-Erkennung zu verringern, und setzen Sie diese zusammen mit „polite scraping“-Praktiken wie Ratenbegrenzung und Einhaltung der robots.txt-Richtlinien ein.
  • Exportieren Sie strukturierte Daten in JSON oder CSV, stellen Sie sie in Docker mit den richtigen Sandbox-Flags bereit und verarbeiten Sie mehrere Seiten gleichzeitig, um über Skripte mit einer einzigen URL hinaus zu skalieren.

FAQ

Warum verhält sich mein Puppeteer-Scraper bei der Bereitstellung auf einem Linux-Server anders als auf meinem lokalen Rechner?

Auf Linux-Servern fehlen in der Regel GUI-bezogene gemeinsam genutzte Bibliotheken, auf die Chromium angewiesen ist, wie z. B. libx11-xcb, libnss3und Schriftartenpakete. Installieren Sie diese mit apt-get oder verwenden Sie ein Docker-Basisimage, das diese enthält. Außerdem führt die Ausführung ohne das --no-sandbox Flag führt auf den meisten Linux-Hosts zum Absturz von Chrome, da die Kernel-Sandboxing-Umgebung erweiterte Berechtigungen erfordert, die von Containern normalerweise eingeschränkt werden.

Wie kann ich Cookies und Sitzungsdaten über mehrere Puppeteer-Scraping-Läufe hinweg beibehalten?

Verwenden Sie page.cookies() , um die aktuellen Sitzungs-Cookies als JSON-Array zu exportieren, und speichern Sie sie dann mit fs.writeFileSync. Laden Sie bei nachfolgenden Durchläufen die Datei und rufen Sie page.setCookie(...cookies) , bevor Sie zur Zielseite navigieren. Dadurch bleiben Anmeldesitzungen, Einstellungen und CSRF-Token erhalten, ohne dass bei jeder Ausführung eine erneute Authentifizierung erforderlich ist.

Die Rechtmäßigkeit hängt von der jeweiligen Rechtsordnung und den Nutzungsbedingungen der Zielseite ab. Im Allgemeinen ist das Scraping öffentlich zugänglicher Daten in vielen Regionen erlaubt, doch ein Verstoß gegen die Nutzungsbedingungen einer Seite kann rechtliche Risiken mit sich bringen. Überprüfen Sie stets die robots.txt (in der Regel unter https://domain.com/robots.txt) und beachten Sie deren Disallow Anweisungen. Fügen Sie Verzögerungen zwischen den Anfragen ein und vermeiden Sie eine Überlastung der Server durch zu schnellen Datenverkehr.

Wie gehe ich beim Scraping mit Puppeteer mit CAPTCHAs um?

CAPTCHAs sind speziell darauf ausgelegt, Automatisierung zu blockieren. Stealth-Plugins können ihr Erscheinen verzögern, indem sie Browser-Fingerabdrücke maskieren, aber sobald ein CAPTCHA angezeigt wird, kann Puppeteer es nicht alleine lösen. Sie können CAPTCHA-Lösungsdienste von Drittanbietern über deren APIs integrieren oder Ihren Scraper so umgestalten, dass Erkennungssignale reduziert werden (langsamere Anfrageraten, private IP-Adressen, zufällige Viewport-Größen), damit CAPTCHAs seltener ausgelöst werden.

Fazit

Puppeteer bleibt eines der leistungsfähigsten Tools zum Scraping dynamischer, JavaScript-lastiger Websites aus einer Node.js-Umgebung. In diesem Leitfaden haben Sie gelernt, wie Sie ein Projekt einrichten, Inhalte mit Selektoren extrahieren und page.evaluate(), mit Paginierung und unendlichem Scrollen umzugehen, versteckte API-Antworten abzufangen, Maßnahmen zur Tarnung anzuwenden, strukturierte Daten zu exportieren und Ihren Scraper in Docker bereitzustellen.

Die wichtigste Erkenntnis ist, dass der Übergang von einem funktionierenden Prototyp zu einem produktionsreifen Scraper nicht nur DOM-Traversal erfordert, sondern auch die Beachtung von Fehlerbehandlung, Parallelität und Anti-Erkennung. Das Einbinden von Seiten in try/catch, das Batching paralleler Anfragen und die Proxy-Rotation sind die Muster, die Skripte, die nach 50 Anfragen abstürzen, von solchen unterscheiden, die auch im großen Maßstab zuverlässig laufen.

Wenn Sie feststellen, dass Sie mehr Zeit damit verbringen, Blockierungen, CAPTCHAs und die Proxy-Infrastruktur zu bekämpfen, als Extraktionslogik zu schreiben, ist das in der Regel ein Signal dafür, die Anforderungsschicht auszulagern. Die Scraper-API von WebScrapingAPI übernimmt die Proxy-Rotation, die Verwaltung von Browser-Fingerabdrücken und das Lösen von CAPTCHAs hinter einem einzigen Endpunkt, sodass Sie Ihren Puppeteer-Parsing-Code beibehalten und lediglich die Netzwerkschicht austauschen können, ohne den Rest Ihres Scrapers neu zu strukturieren.

Über den Autor
Gabriel Cioci, Full-Stack-Entwickler @ WebScrapingAPI
Gabriel CiociFull-Stack-Entwickler

Gabriel Cioci ist Full-Stack-Entwickler bei WebScrapingAPI und verantwortlich für die Entwicklung und Wartung der Websites, des Benutzerportals sowie der wichtigsten benutzerseitigen Komponenten der Plattform.

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.