Table of contents

How to handle errors and exceptions in Playwright?

Error handling in Playwright is essential for building robust web automation scripts. This guide covers common error types, handling strategies, and best practices for both Python and JavaScript.

Common Playwright Error Types

Playwright throws specific errors that you should handle differently:

  • TimeoutError: Element not found within timeout period
  • Error: General navigation, clicking, or interaction failures
  • PlaywrightError: Browser launch or connection issues
  • NetworkError: Network-related failures

Python Error Handling

Basic Exception Handling

from playwright.sync_api import sync_playwright, TimeoutError, Error

def scrape_with_error_handling():
    with sync_playwright() as p:
        browser = None
        try:
            browser = p.chromium.launch()
            page = browser.new_page()
            page.goto("https://example.com", timeout=30000)

            # Handle element interaction errors
            try:
                page.click("#submit-button", timeout=5000)
                print("Button clicked successfully")
            except TimeoutError:
                print("Button not found within timeout")
            except Error as e:
                print(f"Click failed: {e}")

        except Exception as e:
            print(f"Browser error: {e}")
        finally:
            if browser:
                browser.close()

scrape_with_error_handling()

Specific Error Type Handling

from playwright.sync_api import sync_playwright, TimeoutError, Error

def handle_specific_errors():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()

        try:
            # Navigation with error handling
            page.goto("https://example.com")

            # Element selection with multiple fallbacks
            selectors = ["#primary-button", ".submit-btn", "input[type='submit']"]
            button_found = False

            for selector in selectors:
                try:
                    page.click(selector, timeout=2000)
                    button_found = True
                    break
                except TimeoutError:
                    continue
                except Error as e:
                    print(f"Error with selector {selector}: {e}")
                    continue

            if not button_found:
                print("No submit button found with any selector")

        except TimeoutError:
            print("Page load timeout")
        except Error as e:
            print(f"Navigation error: {e}")
        finally:
            browser.close()

handle_specific_errors()

Retry Logic with Exponential Backoff

import time
from playwright.sync_api import sync_playwright, TimeoutError

def retry_with_backoff(func, max_retries=3, base_delay=1):
    for attempt in range(max_retries):
        try:
            return func()
        except TimeoutError as e:
            if attempt == max_retries - 1:
                raise e
            delay = base_delay * (2 ** attempt)
            print(f"Attempt {attempt + 1} failed, retrying in {delay}s...")
            time.sleep(delay)

def scrape_with_retry():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()

        def navigate_and_click():
            page.goto("https://example.com")
            page.click("#dynamic-button")
            return page.text_content("h1")

        try:
            result = retry_with_backoff(navigate_and_click)
            print(f"Success: {result}")
        except Exception as e:
            print(f"All retry attempts failed: {e}")
        finally:
            browser.close()

JavaScript Error Handling

Basic Error Handling

const { chromium } = require('playwright');

async function scrapeWithErrorHandling() {
  let browser;
  try {
    browser = await chromium.launch();
    const context = await browser.newContext();
    const page = await context.newPage();

    await page.goto('https://example.com', { timeout: 30000 });

    // Handle element interaction errors
    try {
      await page.click('#submit-button', { timeout: 5000 });
      console.log('Button clicked successfully');
    } catch (error) {
      if (error.name === 'TimeoutError') {
        console.log('Button not found within timeout');
      } else {
        console.log(`Click failed: ${error.message}`);
      }
    }

  } catch (error) {
    console.error(`Browser error: ${error.message}`);
  } finally {
    if (browser) {
      await browser.close();
    }
  }
}

scrapeWithErrorHandling();

Advanced Error Handling with Custom Functions

const { chromium, TimeoutError } = require('playwright');

class PlaywrightErrorHandler {
  static async withRetry(fn, maxRetries = 3, delay = 1000) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await fn();
      } catch (error) {
        if (attempt === maxRetries) throw error;

        console.log(`Attempt ${attempt} failed: ${error.message}`);
        await new Promise(resolve => setTimeout(resolve, delay * attempt));
      }
    }
  }

  static async safeClick(page, selector, options = {}) {
    const defaultOptions = { timeout: 5000, ...options };

    try {
      await page.waitForSelector(selector, { timeout: defaultOptions.timeout });
      await page.click(selector, defaultOptions);
      return true;
    } catch (error) {
      console.warn(`Failed to click ${selector}: ${error.message}`);
      return false;
    }
  }

  static async safeNavigate(page, url, options = {}) {
    const defaultOptions = { timeout: 30000, waitUntil: 'networkidle', ...options };

    try {
      await page.goto(url, defaultOptions);
      return true;
    } catch (error) {
      console.error(`Navigation to ${url} failed: ${error.message}`);
      return false;
    }
  }
}

async function advancedErrorHandling() {
  const browser = await chromium.launch();
  const page = await browser.newPage();

  try {
    // Safe navigation with retry
    const navigated = await PlaywrightErrorHandler.withRetry(
      () => PlaywrightErrorHandler.safeNavigate(page, 'https://example.com')
    );

    if (!navigated) {
      throw new Error('Failed to navigate after retries');
    }

    // Try multiple selectors
    const selectors = ['#primary-btn', '.submit-button', 'button[type="submit"]'];
    let clicked = false;

    for (const selector of selectors) {
      clicked = await PlaywrightErrorHandler.safeClick(page, selector);
      if (clicked) break;
    }

    if (!clicked) {
      console.log('No clickable button found');
    }

  } catch (error) {
    console.error(`Script failed: ${error.message}`);
  } finally {
    await browser.close();
  }
}

advancedErrorHandling();

Best Practices for Error Handling

1. Always Use Timeouts

Set reasonable timeouts to prevent scripts from hanging indefinitely:

# Python
page.click("#button", timeout=5000)  # 5 second timeout
page.goto("https://example.com", timeout=30000)  # 30 second timeout
// JavaScript
await page.click('#button', { timeout: 5000 });
await page.goto('https://example.com', { timeout: 30000 });

2. Handle Network Errors

Monitor network failures and implement retry logic:

# Python
try:
    page.goto("https://unreliable-site.com")
except Error as e:
    if "net::" in str(e):
        print("Network error detected")
        # Implement retry logic

3. Graceful Resource Cleanup

Always ensure browsers and contexts are properly closed:

// JavaScript - Using try/finally
let browser;
try {
  browser = await chromium.launch();
  // Your automation code
} finally {
  if (browser) await browser.close();
}

4. Log Errors Appropriately

Include context and actionable information in error messages:

# Python
except TimeoutError as e:
    print(f"Timeout waiting for element '{selector}' on page '{page.url}'")
    # Optionally take screenshot for debugging
    page.screenshot(path=f"error_{int(time.time())}.png")

Proper error handling makes your Playwright scripts more reliable and easier to debug. Always anticipate potential failures and implement appropriate recovery strategies.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon