Vollständige Next.js 15 Portfolio-Website mit: - Blog-System mit 100+ Artikeln - Supabase-Integration - Responsive Design mit Tailwind CSS - TypeScript-Konfiguration - Testing-Setup mit Vitest und Playwright Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
480 lines
13 KiB
Markdown
480 lines
13 KiB
Markdown
# Puppeteer: Browser Automation mit Chrome DevTools Protocol
|
|
|
|
**Meta-Description:** Puppeteer für Browser Automation. Chrome DevTools Protocol, Headless Mode, Screenshots, PDF Generation und Testing.
|
|
|
|
**Keywords:** Puppeteer, Browser Automation, Chrome DevTools Protocol, Headless Chrome, Screenshot, PDF, Web Testing
|
|
|
|
---
|
|
|
|
## Einführung
|
|
|
|
Puppeteer ist die **offizielle Node.js Library von Google** für Chrome/Firefox Automation. Über das Chrome DevTools Protocol (CDP) bietet es direkten Zugang zu Browser-Funktionen, die über normale APIs nicht erreichbar sind.
|
|
|
|
---
|
|
|
|
## 2026 Updates
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ PUPPETEER 2026 │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Neue Features: │
|
|
│ ├── WebDriver BiDi Protocol Support │
|
|
│ ├── Firefox vollständig unterstützt │
|
|
│ ├── Neuer Headless Mode (schwerer zu detecten) │
|
|
│ ├── Verbesserte Locator API │
|
|
│ └── 15-20% weniger Memory Usage │
|
|
│ │
|
|
│ DevTools Protocol: │
|
|
│ ├── Network Interception │
|
|
│ ├── Performance Metrics │
|
|
│ ├── Coverage Reports │
|
|
│ ├── Console Logs │
|
|
│ └── Security/Certificate Handling │
|
|
│ │
|
|
│ Use Cases: │
|
|
│ ├── Web Scraping │
|
|
│ ├── Automated Testing │
|
|
│ ├── PDF Generation │
|
|
│ ├── Screenshot Services │
|
|
│ └── Performance Auditing │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
# Mit Chrome Download
|
|
npm install puppeteer
|
|
|
|
# Ohne Chrome (für eigene Installation)
|
|
npm install puppeteer-core
|
|
```
|
|
|
|
```typescript
|
|
// basic.ts
|
|
import puppeteer from 'puppeteer';
|
|
|
|
async function main() {
|
|
const browser = await puppeteer.launch({
|
|
headless: true, // 'new' Headless Mode ist default
|
|
args: [
|
|
'--no-sandbox',
|
|
'--disable-setuid-sandbox',
|
|
'--disable-dev-shm-usage'
|
|
]
|
|
});
|
|
|
|
const page = await browser.newPage();
|
|
await page.setViewport({ width: 1920, height: 1080 });
|
|
|
|
await page.goto('https://example.com');
|
|
|
|
const title = await page.title();
|
|
console.log('Title:', title);
|
|
|
|
await browser.close();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Screenshots & PDFs
|
|
|
|
```typescript
|
|
// Screenshot
|
|
async function captureScreenshot(url: string, outputPath: string) {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
|
|
await page.setViewport({ width: 1920, height: 1080 });
|
|
await page.goto(url, { waitUntil: 'networkidle0' });
|
|
|
|
// Full Page Screenshot
|
|
await page.screenshot({
|
|
path: outputPath,
|
|
fullPage: true,
|
|
type: 'png'
|
|
});
|
|
|
|
// Specific Element
|
|
const element = await page.$('.hero-section');
|
|
if (element) {
|
|
await element.screenshot({ path: 'hero.png' });
|
|
}
|
|
|
|
// Mit Clip (Ausschnitt)
|
|
await page.screenshot({
|
|
path: 'clip.png',
|
|
clip: {
|
|
x: 0,
|
|
y: 0,
|
|
width: 800,
|
|
height: 600
|
|
}
|
|
});
|
|
|
|
await browser.close();
|
|
}
|
|
|
|
// PDF Generation
|
|
async function generatePDF(url: string, outputPath: string) {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
|
|
await page.goto(url, { waitUntil: 'networkidle0' });
|
|
|
|
// Print-Styles laden
|
|
await page.emulateMediaType('print');
|
|
|
|
await page.pdf({
|
|
path: outputPath,
|
|
format: 'A4',
|
|
printBackground: true,
|
|
margin: {
|
|
top: '20mm',
|
|
right: '20mm',
|
|
bottom: '20mm',
|
|
left: '20mm'
|
|
},
|
|
displayHeaderFooter: true,
|
|
headerTemplate: '<div style="font-size:10px; text-align:center; width:100%;">Header</div>',
|
|
footerTemplate: '<div style="font-size:10px; text-align:center; width:100%;"><span class="pageNumber"></span>/<span class="totalPages"></span></div>'
|
|
});
|
|
|
|
await browser.close();
|
|
}
|
|
|
|
// Invoice PDF aus HTML
|
|
async function generateInvoicePDF(html: string): Promise<Buffer> {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
|
|
await page.setContent(html, { waitUntil: 'networkidle0' });
|
|
|
|
const pdf = await page.pdf({
|
|
format: 'A4',
|
|
printBackground: true
|
|
});
|
|
|
|
await browser.close();
|
|
return pdf;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Form Handling & Interaction
|
|
|
|
```typescript
|
|
async function fillAndSubmitForm(page: Page) {
|
|
// Text Input
|
|
await page.type('#email', 'user@example.com', { delay: 50 });
|
|
await page.type('#password', 'secretpassword', { delay: 50 });
|
|
|
|
// Checkbox
|
|
await page.click('#terms');
|
|
|
|
// Select Dropdown
|
|
await page.select('#country', 'DE');
|
|
|
|
// Radio Button
|
|
await page.click('input[name="plan"][value="premium"]');
|
|
|
|
// File Upload
|
|
const fileInput = await page.$('input[type="file"]');
|
|
await fileInput?.uploadFile('./document.pdf');
|
|
|
|
// Submit
|
|
await Promise.all([
|
|
page.waitForNavigation(),
|
|
page.click('button[type="submit"]')
|
|
]);
|
|
}
|
|
|
|
// Keyboard & Mouse
|
|
async function advancedInteraction(page: Page) {
|
|
// Keyboard
|
|
await page.keyboard.press('Tab');
|
|
await page.keyboard.type('Hello World');
|
|
await page.keyboard.down('Shift');
|
|
await page.keyboard.press('ArrowLeft');
|
|
await page.keyboard.up('Shift');
|
|
await page.keyboard.press('Backspace');
|
|
|
|
// Mouse
|
|
await page.mouse.move(100, 200);
|
|
await page.mouse.click(100, 200);
|
|
await page.mouse.wheel({ deltaY: 500 });
|
|
|
|
// Drag & Drop
|
|
const source = await page.$('#drag-source');
|
|
const target = await page.$('#drop-target');
|
|
|
|
if (source && target) {
|
|
const sourceBox = await source.boundingBox();
|
|
const targetBox = await target.boundingBox();
|
|
|
|
if (sourceBox && targetBox) {
|
|
await page.mouse.move(
|
|
sourceBox.x + sourceBox.width / 2,
|
|
sourceBox.y + sourceBox.height / 2
|
|
);
|
|
await page.mouse.down();
|
|
await page.mouse.move(
|
|
targetBox.x + targetBox.width / 2,
|
|
targetBox.y + targetBox.height / 2
|
|
);
|
|
await page.mouse.up();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Network Interception
|
|
|
|
```typescript
|
|
import { Page, HTTPRequest } from 'puppeteer';
|
|
|
|
async function interceptNetwork(page: Page) {
|
|
await page.setRequestInterception(true);
|
|
|
|
page.on('request', (request: HTTPRequest) => {
|
|
const resourceType = request.resourceType();
|
|
const url = request.url();
|
|
|
|
// Block Images, CSS, Fonts
|
|
if (['image', 'stylesheet', 'font'].includes(resourceType)) {
|
|
request.abort();
|
|
return;
|
|
}
|
|
|
|
// Block Tracking
|
|
if (url.includes('analytics') || url.includes('tracking')) {
|
|
request.abort();
|
|
return;
|
|
}
|
|
|
|
// Modify Headers
|
|
const headers = {
|
|
...request.headers(),
|
|
'X-Custom-Header': 'value'
|
|
};
|
|
|
|
request.continue({ headers });
|
|
});
|
|
|
|
// Response Interception
|
|
page.on('response', async (response) => {
|
|
if (response.url().includes('/api/')) {
|
|
try {
|
|
const json = await response.json();
|
|
console.log('API Response:', json);
|
|
} catch {}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Mock API Responses
|
|
async function mockApi(page: Page) {
|
|
await page.setRequestInterception(true);
|
|
|
|
page.on('request', (request) => {
|
|
if (request.url().includes('/api/users')) {
|
|
request.respond({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify([
|
|
{ id: 1, name: 'Mock User' }
|
|
])
|
|
});
|
|
} else {
|
|
request.continue();
|
|
}
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Chrome DevTools Protocol Direct Access
|
|
|
|
```typescript
|
|
async function cdpAccess(page: Page) {
|
|
const client = await page.target().createCDPSession();
|
|
|
|
// Network Conditions (Throttling)
|
|
await client.send('Network.emulateNetworkConditions', {
|
|
offline: false,
|
|
downloadThroughput: 1.5 * 1024 * 1024 / 8, // 1.5 Mbps
|
|
uploadThroughput: 750 * 1024 / 8, // 750 Kbps
|
|
latency: 40 // 40ms
|
|
});
|
|
|
|
// CPU Throttling
|
|
await client.send('Emulation.setCPUThrottlingRate', { rate: 4 });
|
|
|
|
// Performance Metrics
|
|
await client.send('Performance.enable');
|
|
const metrics = await client.send('Performance.getMetrics');
|
|
console.log('Performance Metrics:', metrics);
|
|
|
|
// Coverage (CSS/JS Usage)
|
|
await client.send('CSS.startRuleUsageTracking');
|
|
// ... navigate and interact
|
|
const coverage = await client.send('CSS.stopRuleUsageTracking');
|
|
console.log('CSS Coverage:', coverage);
|
|
|
|
// Clear Browser Data
|
|
await client.send('Network.clearBrowserCache');
|
|
await client.send('Network.clearBrowserCookies');
|
|
|
|
// Console Messages
|
|
client.on('Runtime.consoleAPICalled', (event) => {
|
|
console.log('Console:', event.type, event.args);
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Testing
|
|
|
|
```typescript
|
|
async function measurePerformance(url: string) {
|
|
const browser = await puppeteer.launch();
|
|
const page = await browser.newPage();
|
|
|
|
// Performance Observer
|
|
await page.evaluateOnNewDocument(() => {
|
|
window.performanceEntries = [];
|
|
|
|
const observer = new PerformanceObserver((list) => {
|
|
window.performanceEntries.push(...list.getEntries());
|
|
});
|
|
|
|
observer.observe({ entryTypes: ['navigation', 'resource', 'paint', 'largest-contentful-paint'] });
|
|
});
|
|
|
|
await page.goto(url, { waitUntil: 'networkidle0' });
|
|
|
|
// Metrics abrufen
|
|
const metrics = await page.metrics();
|
|
console.log('Puppeteer Metrics:', {
|
|
JSHeapUsedSize: metrics.JSHeapUsedSize,
|
|
LayoutCount: metrics.LayoutCount,
|
|
RecalcStyleCount: metrics.RecalcStyleCount
|
|
});
|
|
|
|
// Performance Timing
|
|
const timing = await page.evaluate(() => {
|
|
const t = performance.timing;
|
|
return {
|
|
dns: t.domainLookupEnd - t.domainLookupStart,
|
|
tcp: t.connectEnd - t.connectStart,
|
|
ttfb: t.responseStart - t.requestStart,
|
|
download: t.responseEnd - t.responseStart,
|
|
domInteractive: t.domInteractive - t.navigationStart,
|
|
domComplete: t.domComplete - t.navigationStart,
|
|
load: t.loadEventEnd - t.navigationStart
|
|
};
|
|
});
|
|
|
|
console.log('Timing:', timing);
|
|
|
|
// Core Web Vitals
|
|
const cwv = await page.evaluate(() => {
|
|
return (window as any).performanceEntries.filter(
|
|
e => ['largest-contentful-paint', 'first-input', 'layout-shift'].includes(e.entryType)
|
|
);
|
|
});
|
|
|
|
await browser.close();
|
|
return { metrics, timing, cwv };
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Stealth Mode
|
|
|
|
```typescript
|
|
import puppeteer from 'puppeteer-extra';
|
|
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
|
|
puppeteer.use(StealthPlugin());
|
|
|
|
async function stealthBrowse() {
|
|
const browser = await puppeteer.launch({
|
|
headless: true,
|
|
args: [
|
|
'--disable-blink-features=AutomationControlled',
|
|
'--no-sandbox'
|
|
]
|
|
});
|
|
|
|
const page = await browser.newPage();
|
|
|
|
// Additional Stealth
|
|
await page.evaluateOnNewDocument(() => {
|
|
// Chrome Runtime
|
|
Object.defineProperty(navigator, 'webdriver', {
|
|
get: () => false
|
|
});
|
|
|
|
// Permissions
|
|
const originalQuery = window.navigator.permissions.query;
|
|
window.navigator.permissions.query = (parameters: any) =>
|
|
parameters.name === 'notifications'
|
|
? Promise.resolve({ state: 'denied' } as PermissionStatus)
|
|
: originalQuery(parameters);
|
|
|
|
// Plugins
|
|
Object.defineProperty(navigator, 'plugins', {
|
|
get: () => [1, 2, 3, 4, 5]
|
|
});
|
|
});
|
|
|
|
await page.goto('https://bot.sannysoft.com');
|
|
await page.screenshot({ path: 'stealth-test.png', fullPage: true });
|
|
|
|
await browser.close();
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Fazit
|
|
|
|
Puppeteer 2026 bietet:
|
|
|
|
1. **CDP Direct Access**: Volle Browser-Kontrolle
|
|
2. **Multi-Browser**: Chrome + Firefox (WebDriver BiDi)
|
|
3. **New Headless**: Schwerer zu detecten
|
|
4. **Performance Tools**: Metrics, Coverage, Auditing
|
|
|
|
Ideal für Testing, PDF-Generation und Chrome-spezifische Features.
|
|
|
|
---
|
|
|
|
## Bildprompts
|
|
|
|
1. "Puppet master controlling browser strings, automation concept"
|
|
2. "Chrome DevTools with code connections, developer tools visualization"
|
|
3. "PDF documents being generated from web pages, document automation"
|
|
|
|
---
|
|
|
|
## Quellen
|
|
|
|
- [Puppeteer Documentation](https://pptr.dev/)
|
|
- [Puppeteer GitHub](https://github.com/puppeteer/puppeteer)
|
|
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)
|
|
- [Puppeteer Web Scraping 2026](https://roundproxies.com/blog/puppeteer-web-scraping/)
|