5月28日 07:11

How does Puppeteer handle errors and debugging? What are the common debugging techniques and tools?

Puppeteer provides various error handling and debugging techniques to help developers quickly identify and resolve issues, improving development efficiency.

1. Basic Error Handling

try-catch Pattern:

javascript
const puppeteer = require('puppeteer'); async function safeExecution() { const browser = await puppeteer.launch(); const page = await browser.newPage(); try { await page.goto('https://example.com'); await page.click('#button'); } catch (error) { console.error('Error occurred:', error.message); // Error handling logic } finally { await browser.close(); } } safeExecution();

Timeout Handling:

javascript
try { await page.goto('https://example.com', { timeout: 5000 }); } catch (error) { if (error.name === 'TimeoutError') { console.log('Page load timeout'); } }

2. Debug Mode

Enable Debug Mode:

javascript
// Method 1: Use headless: false const browser = await puppeteer.launch({ headless: false, slowMo: 100 // Slow down operations }); // Method 2: Use devtools const browser = await puppeteer.launch({ headless: false, devtools: true });

Use slowMo:

javascript
const browser = await puppeteer.launch({ headless: false, slowMo: 50 // Delay each operation by 50ms });

3. Logging

Console Logging:

javascript
page.on('console', msg => { console.log('Browser console:', msg.text()); }); // Capture different types of logs page.on('console', msg => { const type = msg.type(); const text = msg.text(); if (type === 'error') { console.error('Browser error:', text); } else if (type === 'warning') { console.warn('Browser warning:', text); } else { console.log('Browser log:', text); } });

Page Error Logging:

javascript
page.on('pageerror', error => { console.error('Page error:', error.message); });

Request Failure Logging:

javascript
page.on('requestfailed', request => { console.log('Request failed:', request.url()); console.log('Failure:', request.failure()); });

4. Screenshots and Video Recording

Screenshot on Error:

javascript
async function withErrorScreenshot(page, operation) { try { await operation(); } catch (error) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); await page.screenshot({ path: `error-${timestamp}.png`, fullPage: true }); throw error; } } // Usage example await withErrorScreenshot(page, async () => { await page.goto('https://example.com'); await page.click('#button'); });

Video Recording:

javascript
const { spawn } = require('child_process'); async function recordVideo(page, outputPath, operation) { // Use ffmpeg to record screen const ffmpeg = spawn('ffmpeg', [ '-f', 'x11grab', '-r', '30', '-s', '1920x1080', '-i', ':99', '-c:v', 'libx264', '-preset', 'ultrafast', outputPath ]); try { await operation(); } finally { ffmpeg.kill('SIGINT'); } }

5. Network Debugging

Monitor Network Requests:

javascript
page.on('request', request => { console.log('Request:', request.url()); }); page.on('response', response => { console.log('Response:', response.url(), response.status()); }); page.on('requestfinished', request => { console.log('Request finished:', request.url()); });

Capture Request and Response Data:

javascript
const requests = []; page.on('request', request => { requests.push({ url: request.url(), method: request.method(), headers: request.headers() }); }); page.on('response', async response => { const request = requests.find(r => r.url === response.url()); if (request) { request.status = response.status(); request.headers = response.headers(); try { request.body = await response.text(); } catch (error) { request.body = null; } } });

6. Performance Tracing

Enable Performance Tracing:

javascript
const client = await page.target().createCDPSession(); await client.send('Performance.enable'); await client.send('Network.enable'); // Get performance metrics const metrics = await client.send('Performance.getMetrics'); console.log('Performance metrics:', metrics);

Trace Timeline:

javascript
await page.tracing.start({ path: 'trace.json' }); // Execute operations await page.goto('https://example.com'); await page.tracing.stop();

7. Element Debugging

Highlight Element:

javascript
async function highlightElement(page, selector) { await page.evaluate(selector => { const element = document.querySelector(selector); if (element) { element.style.border = '3px solid red'; element.style.backgroundColor = 'yellow'; } }, selector); }

Check Element State:

javascript
async function checkElement(page, selector) { const isVisible = await page.isVisible(selector); const isEnabled = await page.isDisabled(selector); const isClickable = await page.isClickable(selector); console.log('Element state:', { selector, isVisible, isEnabled, isClickable }); }

Get Element Position:

javascript
const position = await page.evaluate(selector => { const element = document.querySelector(selector); if (element) { const rect = element.getBoundingClientRect(); return { x: rect.left, y: rect.top, width: rect.width, height: rect.height }; } }, '.element');

8. Debugging Utility Functions

Wait and Debug:

javascript
async function waitForAndDebug(page, selector, options = {}) { console.log(`Waiting for selector: ${selector}`); try { await page.waitForSelector(selector, { timeout: options.timeout || 30000, visible: options.visible !== false }); console.log(`Found selector: ${selector}`); } catch (error) { console.error(`Failed to find selector: ${selector}`); await page.screenshot({ path: 'debug-failed.png' }); throw error; } }

Click and Debug:

javascript
async function clickAndDebug(page, selector) { console.log(`Attempting to click: ${selector}`); try { // Check if element exists const element = await page.$(selector); if (!element) { throw new Error(`Element not found: ${selector}`); } // Check if element is visible const isVisible = await element.isIntersectingViewport(); if (!isVisible) { console.warn('Element is not visible, scrolling to it'); await element.scrollIntoView(); } await element.click(); console.log(`Successfully clicked: ${selector}`); } catch (error) { console.error(`Failed to click: ${selector}`, error); await page.screenshot({ path: 'debug-click-failed.png' }); throw error; } }

9. Common Errors and Solutions

Error 1: Element Not Found

javascript
// Problem: Wrong element selector await page.click('.wrong-selector'); // Solution: Use correct selector await page.click('.correct-selector'); // Or wait for element to appear await page.waitForSelector('.correct-selector'); await page.click('.correct-selector');

Error 2: Element Not Clickable

javascript
// Problem: Element is obscured or not visible await page.click('.hidden-button'); // Solution: Scroll to element await page.evaluate(selector => { document.querySelector(selector).scrollIntoView(); }, '.hidden-button'); await page.click('.hidden-button');

Error 3: Timeout Error

javascript
// Problem: Page load timeout await page.goto('https://slow-website.com'); // Solution: Increase timeout await page.goto('https://slow-website.com', { timeout: 60000 }); // Or use more lenient wait condition await page.goto('https://slow-website.com', { waitUntil: 'domcontentloaded' });

Error 4: Memory Leak

javascript
// Problem: Browser instance not closed const browser = await puppeteer.launch(); // Forgot to close // Solution: Use finally to ensure closure const browser = await puppeteer.launch(); try { // Operations } finally { await browser.close(); }

10. Debugging Best Practices

1. Use Descriptive Logging:

javascript
console.log(`[INFO] Navigating to ${url}`); console.log(`[DEBUG] Found ${elements.length} elements`); console.log(`[ERROR] Failed to click button: ${error.message}`);

2. Save Debug Information:

javascript
const debugInfo = { url: page.url(), timestamp: new Date().toISOString(), screenshot: await page.screenshot({ encoding: 'base64' }), html: await page.content(), cookies: await page.cookies() }; require('fs').writeFileSync('debug.json', JSON.stringify(debugInfo, null, 2));

3. Use Conditional Breakpoints:

javascript
await page.evaluate(() => { debugger; // Pause in browser });

4. Step-by-Step Debugging:

javascript
// Use slowMo to slow down operations const browser = await puppeteer.launch({ slowMo: 100 }); // Or add delays at key steps await new Promise(resolve => setTimeout(resolve, 1000));

5. Use Debugger:

javascript
// Add debugger in code debugger; // Run with Node.js debugger node --inspect-brk script.js

11. Testing and Validation

Unit Test Example:

javascript
const assert = require('assert'); async function testPageLoad() { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); const title = await page.title(); assert.strictEqual(title, 'Example Domain'); await browser.close(); } testPageLoad().catch(console.error);

Integration Test Example:

javascript
async function testUserFlow() { const browser = await puppeteer.launch(); const page = await browser.newPage(); // Test login flow await page.goto('https://example.com/login'); await page.type('#username', 'testuser'); await page.type('#password', 'password'); await page.click('#login-button'); // Verify login success await page.waitForSelector('.user-profile'); const isLoggedIn = await page.$('.user-profile') !== null; assert(isLoggedIn, 'Login failed'); await browser.close(); } testUserFlow().catch(console.error);
标签:Puppeteer