page.evaluate() ist eine zentrale Methode von Puppeteer, mit der Sie JavaScript direkt im Browser-Kontext ausführen können. Sie verbindet Node.js mit dem Browser und ermöglicht Aufgaben wie DOM-Manipulation, Datenextraktion und die Automatisierung dynamischer Webseiten. Das sollten Sie wissen:
- Was sie macht: Führt JavaScript im Browser aus, als würden Sie die Browser-Konsole verwenden.
- So funktioniert sie: Wandelt eine Funktion in einen String um, sendet sie an den Browser, führt sie aus und gibt das Ergebnis zurück.
- Wichtige Anwendungsfälle:
- Daten von Webseiten extrahieren, etwa Texte, Tabellen oder JSON.
- Formularübermittlungen und Benutzerinteraktionen automatisieren.
- Dynamische Inhalte wie Infinite Scrolling oder AJAX-Aktualisierungen verarbeiten.
- Einschränkungen: Funktionen müssen JSON-serialisierbar sein, und Node.js-Variablen sind im Browser-Kontext nicht direkt zugänglich.
Kurzes Beispiel:
const title = await page.evaluate(() => document.title);
Damit wird der Seitentitel direkt aus dem Browser abgerufen.
Vergleich: Node.js vs. Browser-Kontext
| Merkmal | Node.js-Kontext | Browser-Kontext |
|---|---|---|
| Globale Objekte | process, require | window, document |
| Speicherort des Skripts | Lokaler Rechner | Zielwebseite |
| API-Zugriff | Node.js-APIs | Browser-Web-APIs |
Verwenden Sie page.evaluate() für präzise und effiziente Automatisierungsaufgaben, insbesondere bei JavaScript-intensiven Webseiten.
NodeJS : Nodejs/Puppeteer – So verwenden Sie page.evaluate
Erklärung des Seitenkontexts
Bei der Webautomatisierung mit Puppeteer ist es entscheidend, den Unterschied zwischen dem Node.js-Kontext und dem Browser-Kontext zu verstehen. Diese beiden Umgebungen sind voneinander isoliert und verfügen jeweils über eigene Regeln für die Codeausführung und den Datenaustausch.
Vergleich von Node.js- und Browser-Kontexten
Puppeteer arbeitet über zwei Umgebungen hinweg: den Node.js-Kontext, in dem Ihr Hauptskript ausgeführt wird, und den Browser-Kontext, in dem Interaktionen mit der Webseite stattfinden. Dabei handelt es sich um getrennte Prozesse mit jeweils eigener virtueller Maschine [3].
Hier ist ein schneller Vergleich ihrer wichtigsten Merkmale:
| Merkmal | Node.js-Kontext | Browser-Kontext |
|---|---|---|
| Globale Objekte | process, require, __dirname | window, document, localStorage |
| Speicherort des Skripts | Lokaler Rechner | Zielwebseite |
| Variablenbereich | Bereich des Puppeteer-Skripts | Bereich des Seitenkontexts |
| API-Zugriff | Node.js-APIs | Browser-Web-APIs |
| Speicherbereich | Separater Prozess | Browser-Prozess |
So funktioniert die Kommunikation zwischen Kontexten
Der Datenaustausch zwischen diesen Kontexten umfasst mehrere Schritte und basiert stark auf Serialisierung:
- Die Funktion wird mit
Function.prototype.toString()in einen String umgewandelt [1]. - Dieser String wird über das Chrome DevTools Protocol an den Browser gesendet [1].
- Der Browser wertet die Funktion innerhalb seiner Umgebung aus.
- Die Ergebnisse werden in JSON serialisiert und an den Node.js-Kontext zurückgesendet [1].
Wichtige Einschränkungen: Funktionen im Browser-Kontext können nicht direkt auf Variablen aus dem Node.js-Bereich zugreifen. Puppeteer bietet spezifische Tools, um diese Herausforderungen zu bewältigen:
page.evaluateHandle(): Gibt Referenzen auf Objekte im Browser-Kontext zurück [1].page.exposeFunction(): Ermöglicht dem Browser, Node.js-Funktionen aufzurufen [1].evaluateOnNewDocument(): Führt Code aus, bevor Seitenskripte geladen werden [1].
Die JSON-Serialisierung kann jedoch bestimmte Eigenschaften entfernen, insbesondere bei komplexen Objekten wie DOM-Nodes [2]. Um Probleme zu vermeiden, übergeben Sie Daten als Funktionsargumente, anstatt sich auf Node.js-Variablen zu verlassen [3].
Wenn Sie diese Kommunikationstechniken beherrschen, können Sie page.evaluate effektiv für Automatisierungsaufgaben einsetzen. Als Nächstes betrachten wir praktische Beispiele, um diese Konzepte in Aktion zu sehen.
Erste Schritte mit page.evaluate
Methodenstruktur und Parameter
Syntax:
await page.evaluate(pageFunction, ...args)
| Parameter | Typ | Beschreibung |
|---|---|---|
| pageFunction | Funktion oder String | JavaScript-Code, der im Browser-Kontext ausgeführt wird |
| args | Optionale Parameter | Werte, die von Node.js an den Browser-Kontext übergeben werden |
| Rückgabewert | Promise | Wird mit dem Rückgabewert der Funktion aufgelöst |
Die pageFunction kann eine Funktion oder ein String mit JavaScript-Code sein. Die Verwendung einer Funktion ist in der Regel besser für Debugging und die Kompatibilität mit TypeScript. Nachfolgend finden Sie einige Beispiele, die die Funktionsweise veranschaulichen.
Grundlegende Codebeispiele
Beispiele:
- Text aus dem ersten
<h1>direkt aus dem DOM extrahieren:
const headingText = await page.evaluate(() => {
return document.querySelector('h1').textContent;
});
- Formularübermittlung durch Übergabe von Parametern automatisieren:
await page.evaluate((username, password) => {
document.getElementById('username').value = username;
document.getElementById('password').value = password;
document.querySelector('#login-form').submit();
}, 'myUsername', 'myPassword');
- Das DOM durch Hinzufügen eines neuen Elements manipulieren:
await page.evaluate(() => {
const div = document.createElement('div');
div.textContent = 'Added by Puppeteer';
document.body.appendChild(div);
return div.textContent;
});
Wichtige Hinweise für die Entwicklung
- Funktionen werden isoliert von Ihrem Node.js-Code ausgeführt.
- An die Funktion übergebene Argumente müssen JSON-serialisierbar sein.
- Rückgabewerte werden automatisch in ein Promise eingeschlossen.
- Die Verarbeitung komplexer Objekte wie DOM-Nodes erfordert besondere Sorgfalt.
Debugging-Tipp: Verwenden Sie die folgende Konfiguration, um das Debugging während der Entwicklung zu aktivieren:
const browser = await puppeteer.launch({
headless: false,
slowMo: 100 // Adds a 100ms delay to each operation
});
Als Nächstes beschäftigen wir uns mit Techniken für den Datenaustausch zwischen Node.js- und Browser-Kontexten.
Datenaustausch zwischen Kontexten
Eingabeparameter
Wenn Sie Daten mit page.evaluate übertragen, sollten Sie für Eingabeargumente nur JSON-serialisierbare Werte verwenden.
Hier ist eine schnelle Übersicht über unterstützte Parametertypen:
| Parametertyp | Unterstützt? | Beispiel |
|---|---|---|
| Primitive Werte | ✓ Vollständig | 'text', 42, true |
| Arrays/Objekte | ✓ JSON-kompatibel | { key: 'value' }, [1, 2, 3] |
| Funktionen | ✗ Nicht direkt | Verwenden Sie page.exposeFunction |
| DOM-Elemente | ✓ Über JSHandle | Verwenden Sie page.evaluateHandle |
Sehen wir uns nun an, wie diese Werte aus dem Browser-Kontext zurückgegeben werden.
Verarbeitung der Ausgabe
Bei Verwendung von page.evaluate werden Rückgabewerte automatisch in JSON serialisiert. So funktioniert es:
// Returning a simple value
const pageTitle = await page.evaluate(() => document.title);
// Returning a complex object
const metrics = await page.evaluate(() => ({
viewport: window.innerWidth,
scrollHeight: document.body.scrollHeight,
timestamp: Date.now()
}));
„Als Faustregel gilt: Wenn der Rückgabewert der angegebenen Funktion komplexer als ein JSON-Objekt ist, etwa bei den meisten Klassen, gibt
evaluatewahrscheinlich einen gekürzten Wert oder{}zurück. Das liegt daran, dass nicht der tatsächliche Rückgabewert zurückgegeben wird, sondern eine deserialisierte Version, die durch die Übertragung des Rückgabewerts über ein Protokoll an Puppeteer entsteht.“ [1]
Sobald Sie die Ausgabe abgerufen haben, können Herausforderungen bei der Serialisierung auftreten. So gehen Sie damit um.
Umgang mit Serialisierungsproblemen
Einige häufige Fälle erfordern spezifische Workarounds:
- Arbeiten mit DOM-Elementen
const bodyHandle = await page.$('body');
const html = await page.evaluate(body => body.innerHTML, bodyHandle);
await bodyHandle.dispose(); // Always clean up to avoid memory leaks
- Verwenden von Node.js-Funktionen
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
const hash = await page.evaluate(async () => {
return await window.md5('test-string');
});
- Transpiler-Einstellungen anpassen
Wenn Sie mit TypeScript arbeiten, stellen Sie sicher, dass Ihr Transpiler korrekt eingerichtet ist:
// tsconfig.json
{
"compilerOptions": {
"target": "es2018"
}
}
Diese Strategien helfen Ihnen, den Datenaustausch in unterschiedlichen Kontexten effektiv zu verarbeiten.
sbb-itb-23997f1
Praktische Beispiele
So können Sie page.evaluate in realen Szenarien einsetzen – einschließlich praktischer Code-Snippets.
Daten extrahieren
Beispiel: Produktdetails scrapen
Dieses Skript sammelt Informationen wie Titel, Preis, Bewertung und Lagerstatus aus Produktkarten auf einer Webseite:
const productData = await page.evaluate(() => {
const products = Array.from(document.querySelectorAll('.product-card'));
return products.map(product => ({
title: product.querySelector('.title').textContent.trim(),
price: product.querySelector('.price').textContent.trim(),
rating: parseFloat(product.querySelector('.rating').dataset.value),
inStock: product.querySelector('.stock').textContent.includes('Available')
}));
});
Beispiel: Tabellendaten extrahieren
Dieser Ansatz ruft Daten aus einer Tabelle ab, indem er ihre Zeilen und Spalten durchläuft:
const tableData = await page.evaluate(() => {
const rows = Array.from(document.querySelectorAll('table tr'));
return rows.map(row => {
const columns = row.querySelectorAll('td');
return Array.from(columns, column => column.innerText);
});
});
Formulare automatisieren
Grundlegende Formularautomatisierung
So füllen Sie Formularfelder aus, lösen Events aus und übermitteln das Formular:
await page.evaluate(() => {
// Fill form fields
document.querySelector('#username').value = 'testuser';
document.querySelector('#password').value = 'secretpass';
// Trigger input events for dynamic forms
const event = new Event('input', { bubbles: true });
document.querySelector('#username').dispatchEvent(event);
// Submit form
document.querySelector('form').submit();
});
Komplexe Formulare verarbeiten
Für Aufgaben wie die Auswahl von Dropdown-Optionen oder das Aktivieren von Optionsfeldern:
await page.evaluate(() => {
// Select dropdown option
const select = document.querySelector('#country');
select.value = 'US';
select.dispatchEvent(new Event('change', { bubbles: true }));
// Check radio button
const radio = document.querySelector('input[value="express"]');
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
});
Dynamische Elemente verwalten
Beispiel: Infinite Scrolling
Dieses Skript scrollt durch eine Seite, bis es mindestens 100 Elemente gesammelt hat:
const items = await page.evaluate(async () => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const items = new Set();
while (items.size < 100) {
// Scroll to bottom
window.scrollTo(0, document.body.scrollHeight);
// Wait for new content
await delay(1000);
// Collect items
document.querySelectorAll('.item').forEach(item =>
items.add(item.textContent.trim())
);
}
return Array.from(items);
});
Beispiel: AJAX-Inhalte verarbeiten
Um dynamisch weitere Inhalte zu laden, klickt dieses Skript auf die Schaltfläche „Mehr laden“ und wartet darauf, dass neue Elemente erscheinen:
await page.evaluate(async () => {
// Click load more button
document.querySelector('#loadMore').click();
// Wait for content update
await new Promise(resolve => {
const observer = new MutationObserver((mutations, obs) => {
if (document.querySelectorAll('.item').length > 10) {
obs.disconnect();
resolve();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
});
});
Diese Beispiele zeigen, wie Sie unterschiedliche Fälle wie Scraping, Formularautomatisierung und dynamische Inhalte verarbeiten können. Je nach spezifischer Struktur und Verhalten der Webseite, mit der Sie arbeiten, sind Anpassungen möglich.
Verwendung von page.evaluate in Latenode
Latenode integriert die Kernfunktionen von Puppeteer in seine Automatisierungs-Workflows und erleichtert so die direkte Ausführung von JavaScript im Browser. Mit page.evaluate können Nutzer das DOM manipulieren und Daten effizient extrahieren. Dieser Ansatz ermöglicht die nahtlose Integration erweiterter Datenverarbeitung und DOM-Operationen in Latenodes Automatisierungsumgebung.
Browser-Skripte in Latenode
Das Browserautomatisierungsmodul von Latenode nutzt page.evaluate, um Aufgaben von einfachen DOM-Operationen bis hin zu komplexerer JavaScript-Ausführung abzuwickeln. So funktioniert es in unterschiedlichen Fällen:
// Basic DOM interaction
await page.evaluate(() => {
const loginButton = document.querySelector('#login');
loginButton.click();
// Trigger a custom event
loginButton.dispatchEvent(new Event('customClick'));
});
// Processing data with exposed functions
await page.exposeFunction('processData', async (data) => {
// Process data in Node.js context
return transformedData;
});
await page.evaluate(async () => {
const rawData = document.querySelector('#data').textContent;
const processed = await window.processData(rawData);
return processed;
});
Latenode führt außerdem ein Protokoll der Ausführungshistorie, wodurch sich Skripte leichter debuggen lassen.
Automatisierungsbeispiele
Latenode ist bestens dafür geeignet, dynamische Inhalte und komplexe Automatisierungsaufgaben zu verarbeiten. Hier ist ein Beispiel für die Verarbeitung dynamischer Inhalte auf einer Seite:
const extractProductData = await page.evaluate(async () => {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Wait for dynamic content to load
while (!document.querySelector('.product-grid')) {
await delay(100);
}
return Array.from(document.querySelectorAll('.product'))
.map(product => ({
name: product.querySelector('.name').textContent,
price: product.querySelector('.price').textContent,
availability: product.querySelector('.stock').dataset.status
}));
});
Für weiterführende Operationen ermöglicht page.exposeFunction eine nahtlose Interaktion zwischen Node.js und dem Browser:
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
const processedData = await page.evaluate(async () => {
const sensitiveData = document.querySelector('#secure-data').value;
return await window.md5(sensitiveData);
});
Um Referenzen auf DOM-Elemente über mehrere Schritte hinweg beizubehalten, verwendet Latenode page.evaluateHandle:
const elementHandle = await page.evaluateHandle(() => {
return document.querySelector('.dynamic-content');
});
await page.evaluate(element => {
element.scrollIntoView();
}, elementHandle);
Diese Techniken stellen sicher, dass Latenode dynamische Inhalte effektiv verarbeiten und zugleich eine zuverlässige Performance gewährleisten kann. Für Nutzer des Prime-Tarifs unterstützt die Plattform bis zu 1,5 Millionen Workflow-Ausführungen pro Monat und bietet damit umfangreiche Automatisierungsmöglichkeiten.
Leitfaden zur Fehlerbehebung
Bei der Arbeit mit page.evaluate in der Browserautomatisierung können verschiedene Probleme auftreten. Hier finden Sie praktische Lösungen, um diese zu beheben und eine reibungslosere Ausführung sicherzustellen.
Kontextfehler beheben
Konfigurieren Sie Ihre TypeScript-Einstellungen korrekt, um Probleme durch Transpilation zu vermeiden. Zum Beispiel:
// Use direct, non-transpiled functions
await page.evaluate(() => {
document.querySelector('#button').click();
});
await page.evaluate(`(async () => {
document.querySelector('#button').click();
})()`);
Vermeiden Sie es, DOM-Elemente direkt aus page.evaluate zurückzugeben. Verwenden Sie stattdessen ElementHandle für eine bessere Verarbeitung:
// Incorrect: Returning a DOM element
const element = await page.evaluate(() => {
return document.querySelector('.dynamic-element');
});
// Correct: Using ElementHandle
const element = await page.evaluateHandle(() => {
return document.querySelector('.dynamic-element');
});
Timing-Probleme lösen
Skripte können ausgeführt werden, bevor die Seite vollständig geladen ist, was zu Timing-Fehlern führt. Verwenden Sie diese Strategien für solche Fälle:
// Wait for navigation after an action
await Promise.all([
page.waitForNavigation(),
page.click('#submit-button')
]);
// Wait for a specific condition
await page.waitForFunction(() => {
const element = document.querySelector('.lazy-loaded');
return element && element.dataset.loaded === 'true';
}, { timeout: 5000 });
Bei dynamischen Webseiten sollten Sie gezieltere Warteverfahren einsetzen:
// Wait for specific network requests
await page.waitForResponse(
response => response.url().includes('/api/data')
);
// Ensure elements are both present and visible
await page.waitForSelector('.dynamic-content', {
visible: true,
timeout: 3000
});
DOM-Referenzen verwalten
Um Speicherlecks zu verhindern, sollten Sie DOM-Referenzen sorgfältig verwalten. So geht es:
// Use and dispose ElementHandles
const handle = await page.evaluateHandle(() => {
return document.querySelector('.temporary-element');
});
await handle.evaluate(element => {
// Perform operations
});
await handle.dispose(); // Dispose of handle after use
Bei der Arbeit mit mehreren Elementen sollten Sie Daten sicher zwischen Kontexten übertragen:
// Extract data from the DOM
const selector = '.product-price';
const price = await page.evaluate((sel) => {
const element = document.querySelector(sel);
return element ? element.textContent.trim() : null;
}, selector);
Stellen Sie bei Event-Listenern eine ordnungsgemäße Bereinigung sicher, um zurückbleibende Handler zu vermeiden:
await page.evaluate(() => {
const handler = () => console.log('clicked');
const button = document.querySelector('#button');
button.addEventListener('click', handler);
// Store cleanup references
window._cleanupHandlers = window._cleanupHandlers || [];
window._cleanupHandlers.push(() => {
button.removeEventListener('click', handler);
});
});
Implementierungsrichtlinien
Um mit page.evaluate optimale Ergebnisse zu erzielen, müssen Sie sich auf die Performance-Optimierung, die Reduzierung unnötiger Kontextwechsel und die Sicherheit konzentrieren. So können Sie Ihre Browserautomatisierungs-Workflows optimieren.
Performance-Optimierung
Eine effiziente Codeausführung im Seitenkontext spart Zeit und Systemressourcen. Nachfolgend finden Sie einige Techniken, mit denen Sie Ihre Skripte beschleunigen können:
// Block unnecessary resources like images and stylesheets
await page.setRequestInterception(true);
page.on('request', request => {
if (['image', 'stylesheet'].includes(request.resourceType())) {
request.abort();
} else {
request.continue();
}
});
// Batch operations to reduce overhead
await page.evaluate(() => {
const results = [];
document.querySelectorAll('.product-item').forEach(item => {
results.push({
title: item.querySelector('.title').textContent,
price: item.querySelector('.price').textContent,
stock: item.querySelector('.stock').dataset.value
});
});
return results;
});
Die Wahl der richtigen Selektoren spielt ebenfalls eine wichtige Rolle für die Performance:
| Selektortyp | Geschwindigkeit | Beispiel |
|---|---|---|
| ID | Am schnellsten | #main-content |
| Klasse | Schnell | .product-item |
| Tag | Mittel | div > span |
| Komplexes XPath | Am langsamsten | //div[@class='wrapper']//span |
Verwaltung von Kontextwechseln
Kontextwechsel zwischen Node.js und der Browser-Umgebung können die Ausführung verlangsamen. So minimieren Sie sie:
// Example of inefficient context switching
for (const item of items) {
await page.evaluate((i) => {
document.querySelector(`#item-${i}`).click();
}, item);
}
// Better: Batch operations in a single context switch
await page.evaluate((itemsList) => {
itemsList.forEach(i => {
document.querySelector(`#item-${i}`).click();
});
}, items);
Wenn Sie Daten in Node.js verarbeiten und an den Browser zurückgeben müssen, stellen Sie Funktionen bereit, statt wiederholt zwischen Kontexten zu wechseln:
await page.exposeFunction('processData', async (data) => {
// Process data in Node.js
return transformedData;
});
await page.evaluate(async () => {
const result = await window.processData(documentData);
// Use the processed data in the browser
});
Sicherheitsrichtlinien
Sobald Performance und Kontextwechsel optimiert sind, sollten Sie sich auf die Sicherheit Ihrer Skripte konzentrieren. Hier sind einige Best Practices:
// Always sanitize inputs before using them
const sanitizedInput = sanitizeHtml(userInput);
await page.evaluate((input) => {
document.querySelector('#search').value = input;
}, sanitizedInput);
// Use error handling for critical operations
try {
await page.evaluate(() => {
if (!window.__securityCheck) {
throw new Error('Security check failed');
}
// Continue with the operation
});
} catch (error) {
console.error('Security violation:', error);
}
Berücksichtigen Sie für Latenode-Workflows diese zusätzlichen Tipps:
- Verwenden Sie
userDataDir, um Ressourcen zwischen Sitzungen im Cache zu speichern und die Performance zu verbessern. - Schließen Sie ungenutzte Seiten und Browser-Instanzen, um Speicher zu sparen.
- Verarbeiten Sie Screenshots mit Buffern, statt sich auf Dateisystemoperationen zu verlassen.
- Implementieren Sie robuste Fehlerbehandlung und umfassende Sicherheitsprüfungen.
Zusammenfassung
Überblick über die wichtigsten Punkte
Die Methode page.evaluate verbindet Node.js- und Browser-Kontexte, indem sie eine als String übergebene JavaScript-Funktion zur Ausführung an den Browser sendet. Diese Funktion arbeitet unabhängig von der Node.js-Umgebung, daher müssen Sie die Datenübertragung sorgfältig behandeln.
Hier ist ein typisches Beispiel für die Datenextraktion:
const data = await page.evaluate(async () => {
const results = document.querySelectorAll('.data-item');
return Array.from(results, item => ({
id: item.dataset.id,
value: item.textContent.trim()
}));
});
Das sollten Sie beachten:
- Argumente müssen JSON-serialisierbar sein.
- Rückgabewerte werden automatisch deserialisiert.
- Browser-APIs sind nur innerhalb des
evaluate-Kontexts verfügbar. - Node.js-Variablen sind im Browser-Kontext nicht zugänglich.
Diese Grundlagen schaffen die Basis für den effektiven Einsatz von Puppeteer. Zusätzliche Tools können Ihre Automatisierungsaufgaben weiter vereinfachen.
Zusätzliche Puppeteer-Tools
Puppeteer bietet mehrere Tools, um die Funktionen von page.evaluate zu erweitern:
| Tool | Zweck | Bester Anwendungsfall |
|---|---|---|
| page.evaluateHandle | Gibt Objektreferenzen zurück | Direkte Interaktion mit DOM-Elementen |
| page.exposeFunction | Macht Node.js-Funktionen im Browser nutzbar | Verwaltung komplexer serverseitiger Logik |
| page.evaluateOnNewDocument | Führt Skripte vor dem Laden einer Seite aus | Browser-Umgebung im Voraus vorbereiten |
So kann beispielsweise das Bereitstellen von Node.js-Funktionen für den Browser die erweiterte Datenverarbeitung in Workflows wie denen von Latenode vereinfachen. Während page.evaluate gut für primitive Datentypen und JSON-serialisierbare Objekte geeignet ist, ist page.evaluateHandle für die Verarbeitung komplexer Browser-Objekte unerlässlich, die nicht serialisiert werden können.


