Best practices

  • Choose CSS selectors that are both specific and stable to avoid selecting the wrong elements. Target IDs, data attributes, or uniquely structured paths whenever possible.

  • Prefer text selectors for buttons and links to make tests more readable and maintainable, as they mimic user interactions.

  • Utilize XPath for navigating complex DOM structures or when needing to perform more advanced element searches.

  • Combine CSS, text, or role-based selectors to fine-tune element targeting – especially helpful on dynamic pages where content or structure can shift frequently.

from playwright.sync_api import sync_playwright

# Start Playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()

# Navigate to the target page
page.goto('https://sandbox.oxylabs.io/products')

# Using CSS selectors
product_name = page.locator('css=.product-name').text_content()
print('Product Name:', product_name)

# Using text selectors
add_to_cart_button = page.locator('text=Add to Cart').click()

# Using XPath selectors
price = page.locator('xpath=//div[@class="price"]').text_content()
print('Price:', price)

# Combining selectors
description = page.locator('.description >> text=More Info').text_content()
print('Description:', description)

# Close browser
browser.close()

Common issues

  • Ensure that Playwright locators are updated if the structure of the web page changes, as stale selectors can cause tests to fail.

  • Always verify that a locator matches only one element unless your test logic expects multiple. Selecting multiple unintended elements can cause test failures or flaky behavior.

  • Use Playwright's auto-wait feature by default to handle elements that might take time to appear or become interactable, avoiding flaky tests.

  • The Playwright Inspector is an invaluable tool for troubleshooting. Use it to explore the page structure, validate selectors, and try out locators interactively in the browser.

# Incorrect: Using a non-unique selector that might match multiple elements
button = page.locator('button').click()

# Correct: Using a unique selector to ensure the correct element is targeted
button = page.locator('button#submit').click()

# Incorrect: Assuming element is immediately available without waiting
product_details = page.locator('div.product-details').text_content()

# Correct: Using auto-wait to ensure element is loaded and interactable
product_details = page.locator('div.product-details').wait_for(state='visible').text_content()

# Incorrect: Using a hardcoded XPath that is brittle and likely to break with UI changes
login_button = page.locator('xpath=/html/body/div[2]/div[1]/button').click()

# Correct: Using a more robust and readable CSS selector or relative XPath
login_button = page.locator('css=button.login').click()

# Incorrect: Not checking if the locator matches any element, leading to potential errors
price = page.locator('div.price').text_content()

# Correct: First check if the locator finds any element before proceeding
if page.locator('div.price').count() > 0:
price = page.locator('div.price').text_content()
else:
print("Price element not found")

Try Oyxlabs' Proxies & Scraper API

Residential Proxies

Self-Service

Human-like scraping without IP blocking

From

8

Datacenter Proxies

Self-Service

Fast and reliable proxies for cost-efficient scraping

From

1.2

Web scraper API

Self-Service

Public data delivery from a majority of websites

From

49

Useful resources

Get the latest news from data gathering world

I'm interested