乐闻世界logo
搜索文章和话题

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

2月19日 19:40

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