Eine Low-Code-Plattform, die die Einfachheit von No-Code mit der Leistung von Full-Code verbindet 🚀
Jetzt kostenlos starten
Debuggen von Puppeteer-Skripten: Vom SlowMo-Modus bis zu fortgeschrittenen Techniken
25. März 2025
10
min lesen

Debuggen von Puppeteer-Skripten: Vom SlowMo-Modus bis zu fortgeschrittenen Techniken

Georgi Miloradowitsch
Forscher, Texter und Usecase-Interviewer
Inhaltsverzeichnis

Fehlerbeseitigung Puppenspieler Skripte können überwältigend sein, aber das Beherrschen einiger wichtiger Techniken kann Ihnen Zeit und Frust ersparen. Hier ist ein kurzer Überblick über das, was Sie lernen werden:

  • Beginnen Sie mit visuellem Debugging: Benutzen slowMo Modus und Headful-Browsermodus, um Ihr Skript in Aktion zu sehen.
  • Fehler erfassen: Hinzufügen try-catch Blöcke und automatisieren Sie Fehler-Screenshots für eine bessere Fehlerbehebung.
  • Nutzen Sie Konsolenprotokolle: Verfolgen Sie Seitenfehler, fehlgeschlagene Anfragen und benutzerdefinierte Nachrichten, um tiefere Einblicke zu erhalten.
  • Griffauswahl und Timing: Verwenden Sie robuste Auswahlstrategien und verwalten Sie Timeouts, um häufige Fehler zu vermeiden.
  • Organisieren Sie Ihren Code: Teilen Sie Skripte in Module für Aktionen, Selektoren und Validierungen auf, um die Wartung zu vereinfachen.

Beispiel für eine schnelle Einrichtung:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100,
    devtools: true
});

Tipps zur Fehlerbehebung:

  1. Aktiviere das Logging: Ausführen mit DEBUG="puppeteer:*" für detaillierte Protokolle.
  2. Verwenden Sie Screenshots: Erfassen Sie Seitenzustände, um zu sehen, was schiefgelaufen ist.
  3. Ressourcen verwalten: Bereinigen Sie immer Browser- und Seiteninstanzen, um Abstürze zu vermeiden.

Durch die Kombination dieser Techniken optimieren Sie Ihren Debugging-Prozess und verbessern die Zuverlässigkeit Ihrer Puppeteer-Skripte.

Einrichten der Debug-Umgebung

Grundlegende Debug-Einstellungen

Richten Sie Puppeteer mit diesen Startoptionen zum Debuggen ein:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 20,
    devtools: true
});

Um eine detaillierte Protokollierung zu aktivieren, führen Sie Ihr Skript mit dem folgenden Befehl aus:

DEBUG="puppeteer:*" node script.js

Verwenden Sie nach der Konfiguration Debugging-Tools, um das Verhalten Ihres Skripts zu analysieren und zu verfeinern.

Erforderliche Debug-Tools

Hier sind einige Tools, die Ihnen dabei helfen, Probleme effektiv zu lösen:

Werkzeug Sinn Hauptmerkmal
Chrome DevTools Skripte prüfen Konsolen- und Netzwerktools
VS-Code Debugger Haltepunkte verwalten Schrittweise Ausführung
Screenshot-Dienstprogramm Visuelle Fehlerbehebung Seitenzustände erfassen

Sie können Ihrem Code zur besseren Sichtbarkeit auch Prüfpunkte hinzufügen:

await page.screenshot({ path: 'before_click.png' });
await page.click('#button');
await page.screenshot({ path: 'after_click.png' });

Skriptorganisation

Eine gute Organisation ist genauso wichtig wie die verwendeten Tools. Teilen Sie Ihr Skript in logische Module auf und integrieren Sie eine Fehlerbehandlung für ein reibungsloseres Debugging:

try {
    await page.waitForSelector('#target-element');
    await page.click('#target-element');
} catch (error) {
    console.error(`Navigation failed: ${error.message}`);
    await page.screenshot({ path: 'error-state.png' });
}

Um die Wahrscheinlichkeit einer Bot-Erkennung zu verringern, integrieren Sie das Stealth-Plugin:

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

Stellen Sie abschließend eine ordnungsgemäße Ressourcenverwaltung sicher, indem Sie Bereinigungsverfahren implementieren:

async function cleanup() {
    if (page) await page.close();
    if (browser) await browser.close();
}

Dieses Setup bietet eine solide Grundlage für das visuelle und Konsolen-Debugging in Ihren Projekten.

Puppenspieler - 3 Ansätze, die beim Debuggen zu berücksichtigen sind

Puppenspieler

Visuelle Debugmethoden

Das Beobachten Ihrer Skripte in Aktion kann Probleme aufdecken, die bei herkömmlicher Codeanalyse möglicherweise übersehen werden. Diese Methoden erweitern Ihre Debugging-Optionen über Konsolenprotokolle und Fehlerverfolgung hinaus.

Anleitung zum SlowMo-Modus

SlowMo führt eine Verzögerung zwischen den Aktionen des Puppeteers ein, sodass Sie leichter verfolgen können, was passiert:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 250,
    devtools: true
});

Das slowMo Der Wert (in Millisekunden) steuert die Verzögerung zwischen Aktionen. Passen Sie ihn je nach Test an:

Operationstyp Empfohlene Zeitlupe (ms) Luftüberwachung
Einfache Klicks 100-250 Grundlegende Navigationsschritte
Formular ausfüllen 250-500 Testen der Eingabevalidierung
Dynamischer Inhalt 500-1000 Ladezustände prüfen

Nachdem Sie SlowMo eingerichtet haben, koppeln Sie es mit dem Browser-Ansichtsmodus, um zu überwachen, wie sich die Benutzeroberfläche während der Skriptausführung verhält.

Browser-Ansichtsmodus

Im Browser-Ansichtsmodus können Sie die Ausführung Ihres Skripts in einem sichtbaren Browserfenster sehen, was besonders beim Debuggen dynamischer Inhalte und komplexer Interaktionen hilfreich ist.

const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1700, height: 800 },
    args: ['--start-maximized']
});

Zum Beispiel Acme CorpDas QA-Team von nutzte diesen Modus im Juni 2024 zur Fehlerbehebung bei einem Web-Scraping-Skript. Es entdeckte fehlerhafte Selektoren und korrigierte diese, wodurch sich die Debugging-Zeit um 40 % verkürzte.

Ergänzend dazu können Sie Screenshots wichtiger visueller Zustände zur weiteren Analyse erstellen.

Visuelle Aufzeichnung

Screenshots und Videos können eine klare Aufzeichnung der Ausführung Ihres Skripts erstellen und so das Debuggen erleichtern:

// Screenshot of a specific element
await page.screenshot({
    path: 'element-state.png',
    clip: {
        x: 0,
        y: 0,
        width: 500,
        height: 300
    }
});

// Full-page screenshot
await page.screenshot({
    path: 'full-page.png',
    fullPage: true
});

Aktivieren Sie zunächst den Browser-Ansichtsmodus, nutzen Sie SlowMo für detailliertes Tracking und dokumentieren Sie wichtige Momente mit Screenshots. Zusammen ergeben diese Schritte einen umfassenden visuellen Debugging-Prozess.

Konsolen-Debugmethoden

Konsolenmethoden bieten eine einfache Möglichkeit, textbasierte Einblicke in das Verhalten Ihrer Skripte zu erhalten. Diese Ausgaben arbeiten mit visuellem Debugging zusammen und liefern Ihnen präzise Details zur Skriptausführung.

Konsolennachrichtenverfolgung

Puppeteer erleichtert das Erfassen von Browsernachrichten mit Ereignishandlern wie diesen:

page.on('console', msg => {
    console.log('PAGE LOG:', msg.text());
});

page.on('pageerror', err => {
    console.error('PAGE ERROR:', err.message);
});

page.on('requestfailed', request => {
    console.error('REQUEST FAILED:', request.url());
});

Dieses Setup erstellt ein Protokollierungssystem, das Konsolenmeldungen, Seitenfehler und fehlgeschlagene Anfragen erfasst. Zur besseren Übersichtlichkeit können Sie die Meldungen nach Typ kategorisieren:

Nachrichtentyp Sinn Beispielausgabe
Log Allgemeine Hinweise Standardausführungsablauf
Fehler Große Probleme Fehlgeschlagene Operationen
Warnung Mögliche Bedenken Leistungseinbußen
Info Status Updates Aufgabe abgeschlossen

Bewährte Methoden für Console.log

Die richtigen console.log Die sinnvolle Verwendung erleichtert das Debuggen erheblich. Platzieren Sie Protokolle strategisch, um den Fortschritt zu verfolgen und Probleme zu identifizieren:

// Log before attempting to find an element
console.log(`Looking for element: ${selector}`);
const element = await page.$(selector);
// Log after confirming the element exists
console.log(`Element found: ${!!element}`);

// Log form data before filling it out
console.log(`Form data: ${JSON.stringify(formData)}`);
await page.type('#email', formData.email);

Erweiterte Protokollierungsmethoden

Bei komplexeren Problemen können erweiterte Protokollierungstechniken entscheidende Vorteile bieten:

// Enable detailed debugging for Puppeteer
process.env.DEBUG = 'puppeteer:*';
process.env.DEBUG_MAX_STRING_LENGTH = null;

// Monitor pending protocol calls
const browser = await puppeteer.launch({
    dumpio: true
});
console.log(browser.debugInfo.pendingProtocolErrors);

Ein Team konnte nach der Einführung einer detaillierten Protokollierung einen Rückgang der Testfehler um 40 % verzeichnen.

// Filter out specific network domain messages
// Command: DEBUG="puppeteer:*" DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'

Diese Methoden fügen Ihrem Debugging-Prozess eine textbasierte Ebene hinzu und helfen Ihnen, Probleme effektiver zu erkennen und zu lösen.

sbb-itb-23997f1

Erweiterte Debug-Methoden

Das Debuggen komplexer Puppeteer-Skripte erfordert die Verwendung effektiver Fehlerbehandlungsstrategien und fortschrittlicher Techniken, um einen reibungslosen Ablauf der Skripte zu gewährleisten.

Try-Catch zur Fehlerbehandlung

Wasser Try-Catch-Blöcke um Fehler effektiv zu verwalten und Ihr Skript am Laufen zu halten:

async function navigateAndScreenshot(url, selector) {
    try {
        await page.goto(url, { waitUntil: 'networkidle0' });
        const element = await page.waitForSelector(selector, { timeout: 5000 });
        await element.screenshot({ path: 'element.png' });
    } catch (error) {
        if (error instanceof TimeoutError) {
            console.error(`Element ${selector} not found within timeout`);
            // Add recovery logic if needed
            await page.reload();
        } else {
            console.error(`Navigation failed: ${error.message}`);
            throw error; // Re-throw unexpected errors
        }
    }
}

Sie können die Fehlerbehandlung verbessern, indem Sie Try-Catch-Blöcke mit benutzerdefinierten Fehlerklassen kombinieren, um eine bessere Kategorisierung und Reaktion zu erzielen.

Benutzerdefinierte Fehlerklassen

Durch das Erstellen benutzerdefinierter Fehlerklassen können Sie Probleme effizienter lokalisieren und klassifizieren:

class PuppeteerScriptError extends Error {
    constructor(message, details = {}) {
        super(message);
        this.name = 'PuppeteerScriptError';
        this.details = details;
        this.timestamp = new Date().toISOString();
    }
}

class SelectorError extends PuppeteerScriptError {
    constructor(selector, context) {
        super(`Failed to find selector: ${selector}`, {
            selector,
            context,
            type: 'SELECTOR_ERROR'
        });
        this.name = 'SelectorError';
    }
}

Mit diesen Klassen können Sie asynchrone Vorgänge klarer verfolgen und debuggen.

Debuggen von asynchronem Code

Asynchroner Code führt häufig zu Zeitproblemen und uneingelösten Versprechen. Bewältigen Sie diese Probleme mit den folgenden Techniken:

// Enable detailed debugging for protocol calls
const browser = await puppeteer.launch({
    dumpio: true
});

// Monitor unresolved promises periodically
setInterval(() => {
    const pending = browser.debugInfo.pendingProtocolErrors;
    if (pending.length > 0) {
        console.log('Pending protocol calls:', pending);
    }
}, 5000);

// Handle async errors with a timeout mechanism
async function safeExecute(promiseFn) {
    try {
        return await Promise.race([
            promiseFn(),
            new Promise((_, reject) => 
                setTimeout(() => reject(new Error('Operation timed out')), 30000)
            )
        ]);
    } catch (error) {
        console.error(`Operation failed: ${error.message}`);
        throw new PuppeteerScriptError('Execution timeout', {
            originalError: error,
            operation: promiseFn.name
        });
    }
}

Durch die Verwendung der debugInfo Schnittstelle können Sie ausstehende Rückrufe überwachen und nicht eingelöste Versprechen während der Browserprotokollkommunikation identifizieren.

Debug-Ebene Sinn Umsetzung
Basic Behandeln häufiger Fehler Standardmäßige Try-Catch-Blöcke
Aufbauend Fehler klassifizieren Benutzerdefinierte Fehlerklassenhierarchie
Erweitert Protokollprobleme verfolgen Debug-Schnittstellenüberwachung

Lösungen für häufige Probleme

In diesem Abschnitt werden häufige Probleme mit Puppeteer behandelt und klare Lösungen bereitgestellt, damit Ihre Automatisierungsskripte reibungslos funktionieren.

Selektorprobleme

Selektorprobleme können die Skriptausführung oft unterbrechen. So beheben Sie sie effektiv:

async function findElement(page) {
  try {
    const element = await page.waitForSelector('[data-testid="target"]', {
      timeout: 5000
    });
    return element;
  } catch {
    return page.waitForSelector('.target-class', {
      timeout: 5000
    });
  }
}

Für Elemente innerhalb von iframes oder Schatten DOM, verwenden Sie diese Ansätze:

// Access iframe content
const frame = await page.frames().find(f => f.name() === 'content-frame');
const button = await frame.$('button[data-hook="create"]');

// Handle Shadow DOM elements
await page.evaluateHandle(selector => {
  const element = document.querySelector('parent-element')
    .shadowRoot
    .querySelector(selector);
  return element;
}, 'target-selector');

Durch die ordnungsgemäße Handhabung von Selektoren wird sichergestellt, dass Ihre Skripte Elemente zuverlässig finden.

Timing-Probleme

Sobald die Selektoren stabil sind, ist die Verwaltung des Timings für eine reibungslose Ausführung von entscheidender Bedeutung:

await page.setDefaultNavigationTimeout(30000);
await page.setDefaultTimeout(10000);

async function waitForContent(page) {
  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
    page.click('#load-more-button')
  ]);
}

Hier ist eine Kurzreferenz für Zeitsteuerungen:

Timing-Problem Die Lösung Umsetzung
Laden der Seite waitForNavigation Warten Sie, bis das Netzwerk inaktiv ist
Dynamischer Inhalt warteAufAuswahl Mit entsprechendem Timeout verwenden
AJAX-Aktualisierungen warteAufAntwort Überwachen Sie bestimmte Netzwerkanforderungen

Diese Strategien helfen dabei, das Timing Ihres Skripts an das Seitenverhalten anzupassen.

Fehlerbehebungen für Browserabstürze

Auch mit soliden Selektor- und Timing-Strategien kann es zu Browserabstürzen kommen. So minimieren und beheben Sie diese:

const browser = await puppeteer.launch({
  args: [
    '--disable-dev-shm-usage',
    '--enable-gpu',
    '--no-first-run',
    '--disable-extensions'
  ]
});

Zur Wiederherstellung nach einem Absturz:

let browser;
try {
  browser = await puppeteer.launch();
  const page = await browser.newPage();

  page.on('error', err => {
    console.error('Page crashed:', err);
  });

  await page.goto('https://example.com');
} catch (error) {
  console.error('Browser error:', error);
} finally {
  if (browser) {
    await browser.close();
  }
}

Wenn Sie unter Linux arbeiten, prüfen Sie, ob Abhängigkeiten fehlen:

ldd chrome | grep not

Um die Ressourcennutzung zu optimieren, passen Sie die Browser-Flags an:

const browser = await puppeteer.launch({
  args: [
    '--disable-dev-shm-usage',
    '--disable-accelerated-2d-canvas',
    '--disable-gpu'
  ]
});

Richten Sie die automatische Wiederherstellung für zusätzliche Ausfallsicherheit ein:

async function checkAndRecoverPage(page) {
  if (!page.isClosed()) {
    try {
      await page.reload();
    } catch {
      page = await browser.newPage();
    }
  }
  return page;
}

Skript-Debug-Optimierung

Verbessern Sie Ihre Skripte für eine einfachere Wartung und schnellere Fehlerbehebung, indem Sie auf bewährten Debugging-Techniken aufbauen.

Code-Klarheit

Sorgen Sie dafür, dass Ihr Code lesbar bleibt, indem Sie Konfigurationen gruppieren und klare, beschreibende Namen verwenden:

// Group related configurations
const browserConfig = {
  headless: false,
  defaultViewport: { width: 1920, height: 1080 },
  args: ['--no-sandbox', '--disable-setuid-sandbox']
};

// Use descriptive function names
async function validatePageContent(page) {
  const pageTitle = await page.title();
  console.log(`Validating content for page: ${pageTitle}`);

  const contentExists = await page.evaluate(() => {
    const mainContent = document.querySelector('.main-content');
    return {
      hasHeader: !!document.querySelector('header'),
      hasContent: !!mainContent,
      contentLength: mainContent?.textContent.length || 0
    };
  });

  return contentExists;
}

Modulorganisation

Teilen Sie Ihre Skripte in separate Module auf, um das Debuggen zu vereinfachen. Dieser Ansatz isoliert Selektoren, Aktionen und Validierungen und erleichtert so das Auffinden und Beheben von Fehlern.

// selectors.js
export const SELECTORS = {
  loginForm: '#login-form',
  submitButton: '[data-testid="submit-btn"]',
  errorMessage: '.error-notification'
};

// actions.js
export async function performLogin(page, credentials) {
  await page.type(SELECTORS.loginForm + ' input[name="username"]', credentials.username);
  await page.type(SELECTORS.loginForm + ' input[name="password"]', credentials.password);
  await Promise.all([
    page.waitForNavigation(),
    page.click(SELECTORS.submitButton)
  ]);
}

// validators.js
export async function checkLoginStatus(page) {
  const errorElement = await page.$(SELECTORS.errorMessage);
  if (errorElement) {
    throw new Error('Login failed: ' + await page.evaluate(el => el.textContent, errorElement));
  }
}

Diese modulare Struktur organisiert nicht nur Ihren Code, sondern trägt auch zur Optimierung der Fehlerverfolgung bei.

Fehlerverfolgungs-Setup

Richten Sie eine Fehlerverfolgung ein, um Probleme schnell zu identifizieren und einen detaillierten Kontext für die Fehlerbehebung bereitzustellen:

class PuppeteerError extends Error {
  constructor(message, action, selector) {
    super(message);
    this.name = 'PuppeteerError';
    this.action = action;
    this.selector = selector;
    this.timestamp = new Date().toISOString();
  }
}

async function executeWithTracking(page, action, description) {
  try {
    await action();
  } catch (error) {
    const screenshot = await page.screenshot({
      path: `error-${Date.now()}.png`,
      fullPage: true
    });

    throw new PuppeteerError(
      `Failed to ${description}`,
      error.message,
      error.selector
    );
  }
}

Sie können die Protokollierung von Konsolenfehlern und -warnungen auch automatisieren:

page.on('console', message => {
  const type = message.type();
  const text = message.text();

  if (type === 'error' || type === 'warning') {
    console.log(`[${type.toUpperCase()}] ${text}`);

    // Log to external service or file
    logger.log({
      level: type,
      message: text,
      timestamp: new Date().toISOString(),
      url: page.url()
    });
  }
});

Validierung für kritische Vorgänge

Fügen Sie Validierungsprüfungen hinzu, um sicherzustellen, dass kritische Vorgänge erfolgreich abgeschlossen werden:

async function validateOperation(page, action) {
  const beforeState = await page.evaluate(() => ({
    url: window.location.href,
    elements: document.querySelectorAll('*').length
  }));

  await action();

  const afterState = await page.evaluate(() => ({
    url: window.location.href,
    elements: document.querySelectorAll('*').length
  }));

  return {
    urlChanged: beforeState.url !== afterState.url,
    elementsDelta: afterState.elements - beforeState.elements
  };
}

Diese Techniken helfen Ihnen in Kombination mit früheren Debugging-Methoden dabei, Probleme schnell zu identifizieren und zu beheben und gleichzeitig die Wartbarkeit Ihrer Skripte aufrechtzuerhalten.

Schlussfolgerung

Wichtige Debugging-Techniken

Verwenden des visuellen Debuggens im Headful-Modus mit slowMo ermöglicht sofortiges Feedback zu Skripten und präzise Zeitanpassungen. Für detailliertere Szenarien bietet das DevTools-Protokoll schrittweises Debugging und Zugriff auf Prozessprotokolle für tiefere Einblicke.

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100,
    devtools: true,
    dumpio: true
});

Um Ihren Arbeitsablauf zu verbessern, sollten Sie neben diesen Debugging-Methoden auch kontinuierliche Überwachungs- und Ressourcenverwaltungspraktiken integrieren.

Nächste Schritte

Nachdem Sie nun über solide Grundlagen in Debugging-Techniken verfügen, erfahren Sie hier, wie Sie Ihre Puppeteer-Skripte optimieren und warten können:

  • Leistungsüberwachung: Verwenden Sie detaillierte Protokollierung, um Ausführungszeiten und Ressourcennutzung zu verfolgen. Dies hilft, Engpässe zu identifizieren und das Debuggen effizienter zu gestalten.
  • Fehlervermeidung: Ergänzen Sie die puppeteer-extra-plugin-stealth Plugin zur Minimierung der Automatisierungserkennung und Reduzierung von Skriptfehlern.
  • Ressourcenmanagement: Konzentrieren Sie sich auf eine effiziente Speichernutzung und implementieren Sie Bereinigungsroutinen, damit Ihre Skripte reibungslos laufen.

Hier ist ein Beispiel für eine Bereinigungsfunktion zur effektiven Verwaltung von Ressourcen:

async function cleanupResources(page) {
    await page.evaluate(() => {
        if (window.performance.memory) {
            console.log(`Heap size limit: ${(window.performance.memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2)} MB`);
        }
    });
    await page.close();
}

Bleiben Sie auf dem Laufenden, indem Sie das Puppeteer GitHub-Repository regelmäßig auf Updates, neue Funktionen und Best Practices überprüfen. Wenn Sie Ihr Toolkit aktuell halten, bleiben Ihre Skripte auch bei sich ändernden Webtechnologien effizient und anpassungsfähig.

Zusammenhängende Artikel

Verwandte Blogs

Anwendungsfall

Unterstützt von