> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zenrows.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scraping Browser Practical Use Cases

> Practical Scraping Browser examples including screenshots, form filling, infinite scroll, network interception, and JavaScript execution.

Discover common automation patterns and real-world scenarios when using ZenRows' Scraping Browser with Puppeteer and Playwright. These practical examples demonstrate how to leverage browser automation for various data extraction and interaction tasks.

The Scraping Browser excels at handling complex scenarios that traditional HTTP-based scraping cannot address. From capturing visual content to executing custom JavaScript, these use cases showcase the full potential of browser-based automation for your scraping projects.

<Note>**Websites often change their structure or update CSS class names and HTML tags.** This means the selectors you use for scraping (like `.product`, `.products`, or specific element tags) might stop working if the site layout changes. To keep your scraper reliable, regularly check and update your selectors as needed.</Note>

## Navigation and Page Content Extraction

Extract complete page content and metadata by navigating to target websites. This fundamental pattern forms the foundation for most scraping workflows and demonstrates how to retrieve both visible content and underlying HTML structure.

<Tabs>
  <Tab title="Puppeteer">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const puppeteer = require('puppeteer-core');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const scraper = async () => {
          const browser = await puppeteer.connect({ browserWSEndpoint: connectionURL });
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/', { 
                  waitUntil: 'domcontentloaded' 
              });
              
              // Extract page metadata
              const title = await page.title();
              console.log('Page title:', title);
              
              // Get complete HTML content
              console.log('Extracting page content...');
              const html = await page.content();
              
              // Extract specific elements
              const productCount = await page.$$eval('.product', products => products.length);
              console.log(`Found ${productCount} products on the page`);
              
              // Extract text content from specific elements
              const headings = await page.$$eval('h1, h2, h3', elements => 
                  elements.map(el => el.textContent.trim())
              );
              console.log('Page headings:', headings);
              
              return {
                  title,
                  productCount,
                  headings,
                  htmlLength: html.length
              };
          } finally {
              await browser.close();
          }
      };

      scraper().then(result => console.log('Extraction complete:', result));
      ```

      ```python Python theme={null}
      # pip install pyppeteer
      import asyncio
      from pyppeteer import connect

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def scraper():
          browser = await connect(browserWSEndpoint=connection_url)
          page = await browser.newPage()
          
          try:
              print('Navigating to target page...')
              await page.goto('https://www.scrapingcourse.com/ecommerce/', {
                  'waitUntil': 'domcontentloaded'
              })
              
              # Extract page metadata
              title = await page.title()
              print(f'Page title: {title}')
              
              # Get complete HTML content
              print('Extracting page content...')
              html = await page.content()
              
              # Extract specific elements
              product_count = await page.querySelectorAllEval('.product', 'products => products.length')
              print(f'Found {product_count} products on the page')
              
              # Extract text content from specific elements
              headings = await page.querySelectorAllEval('h1, h2, h3', '''elements => 
                  elements.map(el => el.textContent.trim())
              ''')
              print(f'Page headings: {headings}')
              
              return {
                  'title': title,
                  'product_count': product_count,
                  'headings': headings,
                  'html_length': len(html)
              }
          finally:
              await page.close()
              await browser.disconnect()

      if __name__ == "__main__":
          result = asyncio.run(scraper())
          print('Extraction complete:', result)
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Playwright">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const { chromium } = require('playwright');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const scraper = async () => {
          const browser = await chromium.connectOverCDP(connectionURL);
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/');
              
              // Extract page metadata
              const title = await page.title();
              console.log('Page title:', title);
              
              // Get complete HTML content
              console.log('Extracting page content...');
              const html = await page.content();
              
              // Extract specific elements
              const products = await page.locator('.product').count();
              console.log(`Found ${products} products on the page`);
              
              // Extract text content from headings
              const headings = await page.locator('h1, h2, h3').allTextContents();
              console.log('Page headings:', headings);
              
              return {
                  title,
                  productCount: products,
                  headings,
                  htmlLength: html.length
              };
          } finally {
              await browser.close();
          }
      };

      scraper().then(result => console.log('Extraction complete:', result));
      ```

      ```python Python theme={null}
      import asyncio
      from playwright.async_api import async_playwright

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def scraper():
          async with async_playwright() as p:
              browser = await p.chromium.connect_over_cdp(connection_url)
              page = await browser.new_page()
              
              try:
                  print('Navigating to target page...')
                  await page.goto('https://www.scrapingcourse.com/ecommerce/')
                  
                  # Extract page metadata
                  title = await page.title()
                  print(f'Page title: {title}')
                  
                  # Get complete HTML content
                  print('Extracting page content...')
                  html = await page.content()
                  
                  # Extract specific elements
                  products = await page.locator('.product').count()
                  print(f'Found {products} products on the page')
                  
                  # Extract text content from headings
                  headings = await page.locator('h1, h2, h3').all_text_contents()
                  print(f'Page headings: {headings}')
                  
                  return {
                      'title': title,
                      'product_count': products,
                      'headings': headings,
                      'html_length': len(html)
                  }
              finally:
                  await browser.close()

      if __name__ == "__main__":
          result = asyncio.run(scraper())
          print('Extraction complete:', result)
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### Key Benefits

* **Complete content access:** Retrieve both rendered content and raw HTML source
* **Metadata extraction:** Access page titles, descriptions, and other document properties
* **Element counting:** Quickly assess page structure and content volume
* **Structured data collection:** Extract specific elements using CSS selectors

## Taking Screenshots

Capture visual representations of web pages for monitoring, documentation, or visual verification purposes. Screenshots prove invaluable for debugging scraping workflows and creating visual records of dynamic content.

<Tabs>
  <Tab title="Puppeteer">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const puppeteer = require('puppeteer-core');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const screenshotScraper = async () => {
          const browser = await puppeteer.connect({ browserWSEndpoint: connectionURL });
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/', { 
                  waitUntil: 'domcontentloaded' 
              });
              
              console.log('Page loaded:', await page.title());
              
              // Take full page screenshot
              console.log('Capturing full page screenshot...');
              await page.screenshot({ 
                  path: 'full-page-screenshot.png',
                  fullPage: true 
              });
              
              // Take viewport screenshot (uses default 1920x1080 viewport)
              console.log('Capturing viewport screenshot...');
              await page.screenshot({ 
                  path: 'viewport-screenshot.png' 
              });
              
              // Take screenshot of specific element
              console.log('Capturing product grid screenshot...');
              const productGrid = await page.$('.products');
              if (productGrid) {
                  await productGrid.screenshot({ 
                      path: 'product-grid-screenshot.png' 
                  });
              }
              
              // Take screenshot with custom clipping (alternative to viewport resizing)
              console.log('Capturing custom-sized screenshot...');
              await page.screenshot({
                  path: 'custom-size-screenshot.png',
                  type: 'jpeg',
                  quality: 100,
                  clip: { x: 0, y: 0, width: 1200, height: 800 }
              });
              
              console.log('All screenshots saved successfully');
              
          } finally {
              await browser.close();
          }
      };

      screenshotScraper();
      ```

      ```python Python theme={null}
      # pip install pyppeteer
      import asyncio
      from pyppeteer import connect

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def screenshot_scraper():
          browser = await connect(browserWSEndpoint=connection_url)
          page = await browser.newPage()
          
          try:
              print('Navigating to target page...')
              await page.goto('https://www.scrapingcourse.com/ecommerce/', {
                  'waitUntil': 'domcontentloaded'
              })
              
              print(f'Page loaded: {await page.title()}')
              
              # Take full page screenshot
              print('Capturing full page screenshot...')
              await page.screenshot({
                  'path': 'full-page-screenshot.png',
                  'fullPage': True
              })
              
              # Take viewport screenshot (uses default 1920x1080 viewport)
              print('Capturing viewport screenshot...')
              await page.screenshot({
                  'path': 'viewport-screenshot.png'
              })
              
              # Take screenshot of specific element
              print('Capturing product grid screenshot...')
              product_grid = await page.querySelector('.products')
              if product_grid:
                  await product_grid.screenshot({
                      'path': 'product-grid-screenshot.png'
                  })
              
              # Take high-quality JPEG screenshot
              print('Capturing high-quality JPEG screenshot...')
              await page.screenshot({
                  'path': 'high-quality-screenshot.jpg',
                  'type': 'jpeg',
                  'quality': 90,
                  'fullPage': True
              })
              
              # Take screenshot with custom clipping (alternative to viewport resizing)
              print('Capturing custom-sized screenshot...')
              await page.screenshot({
                  'path': 'custom-size-screenshot.png',
                  'type': 'png',
                  'fullPage': True,
                  'clip': {'x': 0, 'y': 0, 'width': 1200, 'height': 800}
              })
              
              print('All screenshots saved successfully')
              
          finally:
              await page.close()
              await browser.disconnect()

      if __name__ == "__main__":
          asyncio.run(screenshot_scraper())
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Playwright">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const { chromium } = require('playwright');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const screenshotScraper = async () => {
          const browser = await chromium.connectOverCDP(connectionURL);
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/', {
                  waitUntil: 'domcontentloaded'
              });
              
              // Wait for page to be fully loaded
              await page.waitForSelector('body', { timeout: 10000 });
              
              console.log('Page loaded:', await page.title());
              
              // Take full page screenshot
              console.log('Capturing full page screenshot...');
              await page.screenshot({ 
                  path: 'full-page-screenshot.png',
                  fullPage: true 
              });
              
              // Take viewport screenshot (uses default 1920x1080 viewport)
              console.log('Capturing viewport screenshot...');
              await page.screenshot({ 
                  path: 'viewport-screenshot.png' 
              });
              
              // Take screenshot of specific element (with error handling)
              console.log('Capturing product grid screenshot...');
              try {
                  await page.waitForSelector('.products', { timeout: 5000 });
                  await page.locator('.products').screenshot({ 
                      path: 'product-grid-screenshot.png' 
                  });
              } catch (error) {
                  console.log('Product grid not found, skipping element screenshot');
              }
              
              // Take high-quality JPEG screenshot
              console.log('Capturing high-quality JPEG screenshot...');
              await page.screenshot({
                  path: 'high-quality-screenshot.jpg',
                  type: 'jpeg',
                  quality: 90,
                  fullPage: true
              });
              
              // Take screenshot with custom clipping (alternative to viewport resizing)
              console.log('Capturing custom-sized screenshot...');
              await page.screenshot({
                  path: 'custom-size-screenshot.png',
                  type: 'png',
                  clip: { x: 0, y: 0, width: 1200, height: 800 }
              });
              
              console.log('All screenshots saved successfully');
              
          } catch (error) {
              console.error('Screenshot scraper error:', error.message);
              
              // Take emergency screenshot if navigation fails
              try {
                  await page.screenshot({ path: 'error-screenshot.png' });
                  console.log('Emergency screenshot saved');
              } catch (screenshotError) {
                  console.error('Could not take emergency screenshot:', screenshotError.message);
              }
          } finally {
              await browser.close();
          }
      };

      screenshotScraper();
      ```

      ```python Python theme={null}
      import asyncio
      from playwright.async_api import async_playwright

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def screenshot_scraper():
          async with async_playwright() as p:
              browser = await p.chromium.connect_over_cdp(connection_url)
              page = await browser.new_page()
              
              try:
                  print('Navigating to target page...')
                  await page.goto('https://www.scrapingcourse.com/ecommerce/', 
                      wait_until='domcontentloaded'
                  )
                  
                  # Wait for page to be fully loaded
                  await page.wait_for_selector('body', timeout=10000)
                  
                  print(f'Page loaded: {await page.title()}')
                  
                  # Take full page screenshot
                  print('Capturing full page screenshot...')
                  await page.screenshot(path='full-page-screenshot.png', full_page=True)
                  
                  # Take viewport screenshot (uses default 1920x1080 viewport)
                  print('Capturing viewport screenshot...')
                  await page.screenshot(path='viewport-screenshot.png')
                  
                  # Take screenshot of specific element (with error handling)
                  print('Capturing product grid screenshot...')
                  try:
                      await page.wait_for_selector('.products', timeout=5000)
                      await page.locator('.products').screenshot(path='product-grid-screenshot.png')
                  except Exception:
                      print('Product grid not found, skipping element screenshot')
                  
                  # Take high-quality JPEG screenshot
                  print('Capturing high-quality JPEG screenshot...')
                  await page.screenshot(
                      path='high-quality-screenshot.jpg',
                      type='jpeg',
                      quality=90,
                      full_page=True
                  )
                  
                  # Take screenshot with custom clipping (alternative to viewport resizing)
                  print('Capturing custom-sized screenshot...')
                  await page.screenshot(
                      path='custom-size-screenshot.png',
                      type='png',
                      clip={'x': 0, 'y': 0, 'width': 1200, 'height': 800}
                  )
                  
                  print('All screenshots saved successfully')
                  
              except Exception as error:
                  print(f'Screenshot scraper error: {error}')
                  
                  # Take emergency screenshot if navigation fails
                  try:
                      await page.screenshot(path='error-screenshot.png')
                      print('Emergency screenshot saved')
                  except Exception as screenshot_error:
                      print(f'Could not take emergency screenshot: {screenshot_error}')
              finally:
                  await browser.close()

      if __name__ == "__main__":
          asyncio.run(screenshot_scraper())
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### Screenshot Options

* **Full page capture:** Include content below the fold with `fullPage: true`
* **Element-specific screenshots:** Target individual components or sections
* **Custom clipping:** Focus on specific page areas using coordinate-based clipping
* **Format options:** PNG (lossless) or JPEG (with quality control from 0-100)
* **Default viewport:** Screenshots use the standard 1920x1080 viewport size

<Note>Screenshots are captured from the cloud browser and automatically transferred to your local environment. Large full-page screenshots may take additional time to process and download.</Note>

## Running Custom JavaScript Code

Execute custom JavaScript within the browser context to manipulate pages, extract computed values, or perform complex data transformations. This powerful capability enables sophisticated automation scenarios beyond standard element selection.

<Tabs>
  <Tab title="Puppeteer">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const puppeteer = require('puppeteer-core');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const customJavaScriptScraper = async () => {
          const browser = await puppeteer.connect({ browserWSEndpoint: connectionURL });
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/', { 
                  waitUntil: 'domcontentloaded' 
              });
              
              // Extract page title using custom JavaScript
              const pageTitle = await page.evaluate(() => {
                  return document.title;
              });
              console.log('Page title via JavaScript:', pageTitle);
              
              // Get page statistics
              const pageStats = await page.evaluate(() => {
                  return {
                      totalLinks: document.querySelectorAll('a').length,
                      totalImages: document.querySelectorAll('img').length,
                      totalForms: document.querySelectorAll('form').length,
                      pageHeight: document.body.scrollHeight,
                      viewportHeight: window.innerHeight,
                      currentURL: window.location.href,
                      userAgent: navigator.userAgent
                  };
              });
              console.log('Page statistics:', pageStats);
              
              // Extract product data with custom processing
              const productData = await page.evaluate(() => {
                  const products = Array.from(document.querySelectorAll('.product'));
                  return products.map((product, index) => {
                      const name = product.querySelector('.product-name')?.textContent?.trim();
                      const priceText = product.querySelector('.price')?.textContent?.trim();
                      
                      // Custom price processing
                      const priceMatch = priceText?.match(/\$(\d+(?:\.\d{2})?)/);
                      const priceNumber = priceMatch ? parseFloat(priceMatch[1]) : null;
                      
                      return {
                          id: index + 1,
                          name: name || 'Unknown Product',
                          originalPrice: priceText || 'Price not available',
                          numericPrice: priceNumber,
                          isOnSale: product.querySelector('.sale-badge') !== null,
                          position: index + 1
                      };
                  });
              });
              console.log('Processed product data:', productData);
              
              // Scroll and capture dynamic content
              const scrollResults = await page.evaluate(async () => {
                  // Scroll to bottom of page
                  window.scrollTo(0, document.body.scrollHeight);
                  
                  // Wait for any lazy-loaded content
                  await new Promise(resolve => setTimeout(resolve, 2000));
                  
                  return {
                      finalScrollPosition: window.pageYOffset,
                      totalHeight: document.body.scrollHeight,
                      lazyImagesLoaded: document.querySelectorAll('img[data-src]').length
                  };
              });
              console.log('Scroll results:', scrollResults);
              
              // Inject custom CSS and modify page appearance
              await page.evaluate(() => {
                  const style = document.createElement('style');
                  style.textContent = `
                      .product { border: 2px solid red !important; }
                      .price { background-color: yellow !important; }
                  `;
                  document.head.appendChild(style);
              });
              
              console.log('Custom styles applied');
              
          } finally {
              await browser.close();
          }
      };

      customJavaScriptScraper();
      ```

      ```python Python theme={null}
      # pip install pyppeteer
      import asyncio
      from pyppeteer import connect

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def custom_javascript_scraper():
          browser = await connect(browserWSEndpoint=connection_url)
          page = await browser.newPage()
          
          try:
              print('Navigating to target page...')
              await page.goto('https://www.scrapingcourse.com/ecommerce/', {
                  'waitUntil': 'domcontentloaded',
                  'timeout': 60000
              })
              
              # Extract page title using custom JavaScript
              page_title = await page.evaluate('() => document.title')
              print(f'Page title via JavaScript: {page_title}')
              
              # Get page statistics
              page_stats = await page.evaluate('''() => ({
                  totalLinks: document.querySelectorAll('a').length,
                  totalImages: document.querySelectorAll('img').length,
                  totalForms: document.querySelectorAll('form').length,
                  pageHeight: document.body.scrollHeight,
                  viewportHeight: window.innerHeight,
                  currentURL: window.location.href,
                  userAgent: navigator.userAgent
              })''')
              print(f'Page statistics: {page_stats}')
              
              # Extract and process product data
              product_data = await page.evaluate('''() => {
                  const products = Array.from(document.querySelectorAll('.product'));
                  return products.map((product, index) => {
                      const name = product.querySelector('.product-name')?.textContent?.trim();
                      const priceText = product.querySelector('.price')?.textContent?.trim();
                      
                      // Custom price processing
                      const priceMatch = priceText?.match(/\\$([0-9]+(?:\\.[0-9]{2})?)/);
                      const priceNumber = priceMatch ? parseFloat(priceMatch[1]) : null;
                      
                      return {
                          id: index + 1,
                          name: name || 'Unknown Product',
                          originalPrice: priceText || 'Price not available',
                          numericPrice: priceNumber,
                          isOnSale: product.querySelector('.sale-badge') !== null,
                          position: index + 1
                      };
                  });
              }''')
              print(f'Processed product data: {product_data}')
              
              # Scroll and capture dynamic content
              scroll_results = await page.evaluate('''async () => {
                  // Scroll to bottom of page
                  window.scrollTo(0, document.body.scrollHeight);
                  
                  // Wait for any lazy-loaded content
                  await new Promise(resolve => setTimeout(resolve, 2000));
                  
                  return {
                      finalScrollPosition: window.pageYOffset,
                      totalHeight: document.body.scrollHeight,
                      lazyImagesLoaded: document.querySelectorAll('img[data-src]').length
                  };
              }''')
              print(f'Scroll results: {scroll_results}')
              
              # Inject custom CSS and modify page appearance
              await page.evaluate('''() => {
                  const style = document.createElement('style');
                  style.textContent = `
                      .product { border: 2px solid red !important; }
                      .price { background-color: yellow !important; }
                  `;
                  document.head.appendChild(style);
              }''')
              
              print('Custom styles applied')
              
          except Exception as error:
              print(f'Custom JavaScript scraper error: {error}')
          finally:
              await page.close()
              await browser.disconnect()

      if __name__ == "__main__":
          asyncio.run(custom_javascript_scraper())
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Playwright">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const { chromium } = require('playwright');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const customJavaScriptScraper = async () => {
          const browser = await chromium.connectOverCDP(connectionURL);
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/');
              
              // Extract page title using custom JavaScript
              const pageTitle = await page.evaluate(() => document.title);
              console.log('Page title via JavaScript:', pageTitle);
              
              // Get page statistics
              const pageStats = await page.evaluate(() => ({
                  totalLinks: document.querySelectorAll('a').length,
                  totalImages: document.querySelectorAll('img').length,
                  totalForms: document.querySelectorAll('form').length,
                  pageHeight: document.body.scrollHeight,
                  viewportHeight: window.innerHeight,
                  currentURL: window.location.href,
                  userAgent: navigator.userAgent
              }));
              console.log('Page statistics:', pageStats);
              
              // Extract and process product data
              const productData = await page.evaluate(() => {
                  const products = Array.from(document.querySelectorAll('.product'));
                  return products.map((product, index) => {
                      const name = product.querySelector('.product-name')?.textContent?.trim();
                      const priceText = product.querySelector('.price')?.textContent?.trim();
                      
                      // Custom price processing
                      const priceMatch = priceText?.match(/\$(\d+(?:\.\d{2})?)/);
                      const priceNumber = priceMatch ? parseFloat(priceMatch[1]) : null;
                      
                      return {
                          id: index + 1,
                          name: name || 'Unknown Product',
                          originalPrice: priceText || 'Price not available',
                          numericPrice: priceNumber,
                          isOnSale: product.querySelector('.sale-badge') !== null,
                          position: index + 1
                      };
                  });
              });
              console.log('Processed product data:', productData);
              
              // Scroll and capture dynamic content
              await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
              await page.waitForTimeout(2000);
              
              const scrollResults = await page.evaluate(() => ({
                  finalScrollPosition: window.pageYOffset,
                  totalHeight: document.body.scrollHeight,
                  lazyImagesLoaded: document.querySelectorAll('img[data-src]').length
              }));
              console.log('Scroll results:', scrollResults);
              
              // Inject custom CSS
              await page.addStyleTag({
                  content: `
                      .product { border: 2px solid red !important; }
                      .price { background-color: yellow !important; }
                  `
              });
              
              console.log('Custom styles applied');
              
          } finally {
              await browser.close();
          }
      };

      customJavaScriptScraper();
      ```

      ```python Python theme={null}
      import asyncio
      from playwright.async_api import async_playwright

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def custom_javascript_scraper():
          async with async_playwright() as p:
              browser = await p.chromium.connect_over_cdp(connection_url)
              page = await browser.new_page()
              
              try:
                  print('Navigating to target page...')
                  await page.goto('https://www.scrapingcourse.com/ecommerce/')
                  
                  # Extract page title using custom JavaScript
                  page_title = await page.evaluate('() => document.title')
                  print(f'Page title via JavaScript: {page_title}')
                  
                  # Get page statistics
                  page_stats = await page.evaluate('''() => ({
                      totalLinks: document.querySelectorAll('a').length,
                      totalImages: document.querySelectorAll('img').length,
                      totalForms: document.querySelectorAll('form').length,
                      pageHeight: document.body.scrollHeight,
                      viewportHeight: window.innerHeight,
                      currentURL: window.location.href,
                      userAgent: navigator.userAgent
                  })''')
                  print(f'Page statistics: {page_stats}')
                  
                  # Extract and process product data
                  product_data = await page.evaluate('''() => {
                      const products = Array.from(document.querySelectorAll('.product'));
                      return products.map((product, index) => {
                          const name = product.querySelector('.product-name')?.textContent?.trim();
                          const priceText = product.querySelector('.price')?.textContent?.trim();
                          
                          // Custom price processing
                          const priceMatch = priceText?.match(/\\$([0-9]+(?:\\.[0-9]{2})?)/);
                          const priceNumber = priceMatch ? parseFloat(priceMatch[1]) : null;
                          
                          return {
                              id: index + 1,
                              name: name || 'Unknown Product',
                              originalPrice: priceText || 'Price not available',
                              numericPrice: priceNumber,
                              isOnSale: product.querySelector('.sale-badge') !== null,
                              position: index + 1
                          };
                      });
                  }''')
                  print(f'Processed product data: {product_data}')
                  
                  # Scroll and capture dynamic content
                  await page.evaluate('() => window.scrollTo(0, document.body.scrollHeight)')
                  await page.wait_for_timeout(2000)
                  
                  scroll_results = await page.evaluate('''() => ({
                      finalScrollPosition: window.pageYOffset,
                      totalHeight: document.body.scrollHeight,
                      lazyImagesLoaded: document.querySelectorAll('img[data-src]').length
                  })''')
                  print(f'Scroll results: {scroll_results}')
                  
                  # Inject custom CSS
                  await page.add_style_tag(content='''
                      .product { border: 2px solid red !important; }
                      .price { background-color: yellow !important; }
                  ''')
                  
                  print('Custom styles applied')
                  
              finally:
                  await browser.close()

      if __name__ == "__main__":
          asyncio.run(custom_javascript_scraper())
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### JavaScript Execution Capabilities

* **Data extraction and processing:** Transform raw data within the browser context
* **Page statistics collection:** Gather comprehensive page metrics and analytics
* **Dynamic content interaction:** Trigger JavaScript events and handle dynamic updates
* **Custom styling injection:** Modify page appearance for testing or visual enhancement
* **Scroll automation:** Navigate through infinite scroll or lazy-loaded content
* **Complex calculations:** Perform mathematical operations on extracted data

<Tip>Custom JavaScript execution runs within the browser's security context, providing access to all DOM APIs and browser features available to the target website.</Tip>

## PDF Generation and Document Export

Generate PDF documents from web pages for archival, reporting, or documentation purposes. This capability proves valuable for creating snapshots of dynamic content or generating reports from scraped data.

<Tabs>
  <Tab title="Puppeteer">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const puppeteer = require('puppeteer-core');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const pdfGenerationScraper = async () => {
          const browser = await puppeteer.connect({ browserWSEndpoint: connectionURL });
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/', { 
                  waitUntil: 'domcontentloaded' 
              });
              
              console.log('Page loaded:', await page.title());
              
              // Generate basic PDF
              console.log('Generating basic PDF...');
              await page.pdf({
                  path: 'basic-page.pdf',
                  format: 'A4',
                  printBackground: true
              });
              
              // Generate custom PDF with options
              console.log('Generating custom PDF...');
              await page.pdf({
                  path: 'custom-page.pdf',
                  format: 'A4',
                  printBackground: true,
                  margin: {
                      top: '20mm',
                      bottom: '20mm',
                      left: '20mm',
                      right: '20mm'
                  },
                  displayHeaderFooter: true,
                  headerTemplate: '<div style="font-size: 10px; text-align: center; width: 100%;">E-commerce Scraping Report</div>',
                  footerTemplate: '<div style="font-size: 10px; text-align: center; width: 100%;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'
              });
              
              // Generate PDF of specific content area
              console.log('Generating product grid PDF...');
              const productGrid = await page.$('.products');
              if (productGrid) {
                  const boundingBox = await productGrid.boundingBox();
                  await page.pdf({
                      path: 'product-grid.pdf',
                      format: 'A4',
                      printBackground: true,
                      clip: boundingBox
                  });
              }
              
              // Generate landscape PDF
              console.log('Generating landscape PDF...');
              await page.pdf({
                  path: 'landscape-page.pdf',
                  format: 'A4',
                  landscape: true,
                  printBackground: true,
                  scale: 0.8
              });
              
              console.log('All PDFs generated successfully');
              
          } finally {
              await browser.close();
          }
      };

      pdfGenerationScraper();
      ```

      ```python Python theme={null}
      # pip install pyppeteer
      import asyncio
      from pyppeteer import connect

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def pdf_generation_scraper():
          browser = await connect(browserWSEndpoint=connection_url)
          page = await browser.newPage()
          
          try:
              print('Navigating to target page...')
              await page.goto('https://www.scrapingcourse.com/ecommerce/', 
                          {'waitUntil': 'domcontentloaded'})
              
              print(f'Page loaded: {await page.title()}')
              
              # Generate basic PDF
              print('Generating basic PDF...')
              await page.pdf({
                  'path': 'basic-page.pdf',
                  'format': 'A4',
                  'printBackground': True
              })
              
              # Generate custom PDF with options
              print('Generating custom PDF...')
              await page.pdf({
                  'path': 'custom-page.pdf',
                  'format': 'A4',
                  'printBackground': True,
                  'margin': {
                      'top': '20mm',
                      'bottom': '20mm',
                      'left': '20mm',
                      'right': '20mm'
                  },
                  'displayHeaderFooter': True,
                  'headerTemplate': '<div style="font-size: 10px; text-align: center; width: 100%;">E-commerce Scraping Report</div>',
                  'footerTemplate': '<div style="font-size: 10px; text-align: center; width: 100%;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'
              })
              
              # Generate landscape PDF
              print('Generating landscape PDF...')
              await page.pdf({
                  'path': 'landscape-page.pdf',
                  'format': 'A4',
                  'landscape': True,
                  'printBackground': True,
                  'scale': 0.8
              })
              
              print('All PDFs generated successfully')
              
          finally:
              await page.close()
              await browser.disconnect()

      if __name__ == "__main__":
          asyncio.run(pdf_generation_scraper())
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Playwright">
    <CodeGroup>
      ```javascript Node.js theme={null}
      const { chromium } = require('playwright');
      const connectionURL = 'wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY';

      const pdfGenerationScraper = async () => {
          const browser = await chromium.connectOverCDP(connectionURL);
          const page = await browser.newPage();
          
          try {
              console.log('Navigating to target page...');
              await page.goto('https://www.scrapingcourse.com/ecommerce/');
              
              console.log('Page loaded:', await page.title());
              
              // Generate basic PDF
              console.log('Generating basic PDF...');
              await page.pdf({
                  path: 'basic-page.pdf',
                  format: 'A4',
                  printBackground: true
              });
              
              // Generate custom PDF with options
              console.log('Generating custom PDF...');
              await page.pdf({
                  path: 'custom-page.pdf',
                  format: 'A4',
                  printBackground: true,
                  margin: {
                      top: '20mm',
                      bottom: '20mm',
                      left: '20mm',
                      right: '20mm'
                  },
                  displayHeaderFooter: true,
                  headerTemplate: '<div style="font-size: 10px; text-align: center; width: 100%;">E-commerce Scraping Report</div>',
                  footerTemplate: '<div style="font-size: 10px; text-align: center; width: 100%;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'
              });
              
              // Generate landscape PDF
              console.log('Generating landscape PDF...');
              await page.pdf({
                  path: 'landscape-page.pdf',
                  format: 'A4',
                  landscape: true,
                  printBackground: true,
                  scale: 0.8
              });
              
              console.log('All PDFs generated successfully');
              
          } finally {
              await browser.close();
          }
      };

      pdfGenerationScraper();
      ```

      ```python Python theme={null}
      # pip install playwright
      import asyncio
      from playwright.async_api import async_playwright

      connection_url = "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"

      async def pdf_generation_scraper():
          async with async_playwright() as p:
              browser = await p.chromium.connect_over_cdp(connection_url)
              page = await browser.new_page()
              
              try:
                  print('Navigating to target page...')
                  await page.goto('https://www.scrapingcourse.com/ecommerce/')
                  
                  print(f'Page loaded: {await page.title()}')
                  
                  # Generate basic PDF
                  print('Generating basic PDF...')
                  await page.pdf(
                      path='basic-page.pdf',
                      format='A4',
                      print_background=True
                  )
                  
                  # Generate custom PDF with options
                  print('Generating custom PDF...')
                  await page.pdf(
                      path='custom-page.pdf',
                      format='A4',
                      print_background=True,
                      margin={
                          'top': '20mm',
                          'bottom': '20mm',
                          'left': '20mm',
                          'right': '20mm'
                      },
                      display_header_footer=True,
                      header_template='<div style="font-size: 10px; text-align: center; width: 100%;">E-commerce Scraping Report</div>',
                      footer_template='<div style="font-size: 10px; text-align: center; width: 100%;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'
                  )
                  
                  # Generate landscape PDF
                  print('Generating landscape PDF...')
                  await page.pdf(
                      path='landscape-page.pdf',
                      format='A4',
                      landscape=True,
                      print_background=True,
                      scale=0.8
                  )
                  
                  print('All PDFs generated successfully')
                  
              finally:
                  await browser.close()

      if __name__ == "__main__":
          asyncio.run(pdf_generation_scraper())
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### PDF Generation Features

* **Multiple format support:** Generate A4, Letter, Legal, and custom page sizes
* **Custom headers and footers:** Add branding, page numbers, and metadata
* **Background preservation:** Include CSS backgrounds and styling in PDFs
* **Margin control:** Configure precise spacing and layout
* **Orientation options:** Create portrait or landscape documents
* **Scale adjustment:** Optimize content size for better readability

<Tip>PDF generation works seamlessly with the cloud browser, automatically transferring generated files to your local environment while maintaining high quality and formatting.</Tip>

## Conclusion

ZenRows' Scraping Browser transforms complex web automation challenges into straightforward solutions. These practical use cases demonstrate the platform's versatility in handling everything from basic content extraction to sophisticated browser automation workflows.

## Next Steps for Implementation

Start with the basic navigation and content extraction patterns to establish your foundation, then progressively incorporate advanced features like form interactions and network monitoring as your requirements evolve. The modular nature of these examples allows you to combine techniques for sophisticated automation workflows.

Consider implementing error handling and retry logic around these patterns for production deployments. The Scraping Browser's consistent cloud environment reduces many common failure points, but robust error handling ensures reliable operation at scale.

## Frequently Asked Questions (FAQ)

<Accordion title="Can I combine multiple use cases in a single scraping session?">
  Absolutely! These use cases are designed to work together. For example, you can navigate to a page, take screenshots, extract data, and generate PDFs all within the same browser session. This approach is more efficient and maintains session state across operations.

  ```javascript Node.js theme={null}
  // Example combining multiple use cases
  await page.goto('https://example.com');
  await page.screenshot({ path: 'before.png' });
  await page.fill('input[name="search"]', 'query');
  await page.click('button[type="submit"]');
  await page.screenshot({ path: 'after.png' });
  const data = await page.$$eval('.result', elements => /* extract data */);
  await page.pdf({ path: 'results.pdf' });
  ```
</Accordion>

<Accordion title="How do I handle dynamic content that loads after page navigation?">
  Use explicit waiting mechanisms to ensure content is fully loaded before interaction:

  ```javascript Node.js theme={null}
  // Wait for specific elements
  await page.waitForSelector('.dynamic-content');
  // Wait for network to be idle
  await page.goto(url, { waitUntil: 'domcontentloaded' });

  // Wait for custom conditions
  await page.waitForFunction(() => document.querySelectorAll('.product').length > 0);
  ```

  The Scraping Browser handles JavaScript rendering automatically, making these waiting strategies highly effective.
</Accordion>

<Accordion title="How do I optimize performance when scraping large amounts of data?">
  Several strategies can significantly improve performance:

  * **Block unnecessary resources:** Use request interception to block images, fonts, and other non-essential content
  * **Reuse browser instances:** Keep browsers open for multiple operations instead of creating new connections
  * **Implement concurrent processing:** Use multiple browser instances for parallel scraping
  * **Optimize waiting strategies:** Use specific selectors instead of generic timeouts

  The network monitoring examples demonstrate resource blocking techniques that can improve scraping speed.
</Accordion>

<Accordion title="What's the difference between using the WebSocket URL directly versus the SDK?">
  Both approaches provide identical functionality, but the SDK offers several advantages:

  * **Simplified configuration:** No need to manually construct WebSocket URLs
  * **Better error handling:** Built-in error messages and debugging information
  * **Future compatibility:** Automatic updates to connection protocols
  * **Additional utilities:** Helper methods for common tasks

  For production applications, the SDK is recommended for better maintainability and error handling, while direct WebSocket connections work well for simple scripts and testing.
</Accordion>

<Accordion title="How do I troubleshoot issues when these examples don't work as expected?">
  Follow this systematic troubleshooting approach:

  1. **Verify API key:** Ensure your ZenRows API key is correct and active
  2. **Check element selectors:** Use browser developer tools to verify CSS selectors
  3. **Add debugging output:** Include console.log statements to track execution flow
  4. **Implement error handling:** Wrap operations in try-catch blocks
  5. **Test with simpler examples:** Start with basic navigation before adding complexity

  The network monitoring examples are particularly valuable for debugging, as they reveal exactly what requests are being made and their responses.
</Accordion>
