Playwright's JavaScript evaluation capabilities allow you to execute JavaScript code directly in the browser context, making it essential for interacting with dynamic content, extracting data, and performing complex DOM operations.
Core Methods
page.evaluate()
Executes JavaScript and returns serializable values (strings, numbers, booleans, arrays, plain objects).
page.evaluateHandle()
Executes JavaScript and returns a handle to non-serializable objects (DOM elements, functions).
Basic Examples
Python - Simple Evaluation
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com")
# Get page title
title = page.evaluate("() => document.title")
print(f"Title: {title}")
# Get current URL
url = page.evaluate("() => window.location.href")
print(f"URL: {url}")
browser.close()
JavaScript - Basic Usage
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// Get page title
const title = await page.evaluate(() => document.title);
console.log(`Title: ${title}`);
// Get viewport dimensions
const viewport = await page.evaluate(() => ({
width: window.innerWidth,
height: window.innerHeight
}));
console.log(`Viewport: ${viewport.width}x${viewport.height}`);
await browser.close();
})();
Passing Arguments
You can pass arguments from your script to the evaluated JavaScript:
Python - With Arguments
# Extract text content from multiple elements
selectors = ['h1', 'p', '.highlight']
results = page.evaluate("""
(selectors) => {
const data = {};
selectors.forEach(selector => {
const elements = Array.from(document.querySelectorAll(selector));
data[selector] = elements.map(el => el.textContent.trim());
});
return data;
}
""", selectors)
print(results)
JavaScript - With Arguments
// Get computed styles for elements
const selector = '.main-content';
const properties = ['color', 'font-size', 'background-color'];
const styles = await page.evaluate((sel, props) => {
const element = document.querySelector(sel);
if (!element) return null;
const computedStyle = getComputedStyle(element);
const result = {};
props.forEach(prop => {
result[prop] = computedStyle.getPropertyValue(prop);
});
return result;
}, selector, properties);
console.log(styles);
Advanced Use Cases
Data Extraction
// Extract structured data from a table
const tableData = await page.evaluate(() => {
const table = document.querySelector('table');
if (!table) return [];
const headers = Array.from(table.querySelectorAll('th')).map(th => th.textContent.trim());
const rows = Array.from(table.querySelectorAll('tbody tr')).map(row => {
const cells = Array.from(row.querySelectorAll('td')).map(td => td.textContent.trim());
const rowData = {};
headers.forEach((header, index) => {
rowData[header] = cells[index] || '';
});
return rowData;
});
return rows;
});
Waiting for Dynamic Content
# Wait for dynamic content and extract it
page.goto("https://dynamic-content-site.com")
# Wait for content to load and extract it
result = page.evaluate("""
() => {
return new Promise((resolve) => {
const checkContent = () => {
const element = document.querySelector('.dynamic-content');
if (element && element.textContent.trim()) {
resolve(element.textContent.trim());
} else {
setTimeout(checkContent, 100);
}
};
checkContent();
});
}
""")
print(f"Dynamic content: {result}")
Using evaluateHandle()
for DOM Elements
When you need to work with DOM elements directly:
// Get element handle and interact with it
const elementHandle = await page.evaluateHandle(() =>
document.querySelector('input[type="text"]')
);
if (elementHandle) {
await elementHandle.fill('Hello World');
await elementHandle.press('Enter');
elementHandle.dispose(); // Clean up the handle
}
Error Handling
try:
result = page.evaluate("""
() => {
const element = document.querySelector('.non-existent');
if (!element) {
throw new Error('Element not found');
}
return element.textContent;
}
""")
except Exception as e:
print(f"JavaScript evaluation failed: {e}")
Best Practices
Serialization Limits:
evaluate()
only returns serializable data. UseevaluateHandle()
for DOM elements or functions.Error Handling: Always wrap evaluation code in try-catch blocks, both in JavaScript and your main script.
Performance: Minimize DOM queries by batching operations in a single evaluation.
Security: Never evaluate untrusted user input directly. Validate and sanitize data before evaluation.
Memory Management: Dispose of handles created by
evaluateHandle()
to prevent memory leaks.
// Good: Batch multiple operations
const pageData = await page.evaluate(() => ({
title: document.title,
url: window.location.href,
links: Array.from(document.querySelectorAll('a')).map(a => ({
text: a.textContent.trim(),
href: a.href
})),
meta: Array.from(document.querySelectorAll('meta')).map(meta => ({
name: meta.name || meta.property,
content: meta.content
}))
}));
This comprehensive approach to JavaScript evaluation makes Playwright a powerful tool for web scraping, testing, and automation tasks that require deep interaction with web page content.