Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To automate a browser with Python, choose Playwright for a new end-to-end project that benefits from a modern synchronous or asynchronous API, or choose Selenium when you need an established WebDriver workflow and its broad browser/platform integrations. Neither tool is a proven universal speed or reliability winner. Your decision should follow the browsers, operating systems, test runner, async requirements, and existing infrastructure your project actually has.

What Python browser automation does

A browser-automation library starts a real browser (or a browser configured for headless operation), opens pages, finds elements, performs actions, reads results, and can capture evidence such as screenshots or PDFs. Typical uses include end-to-end tests, regression checks, form workflows, scraping of pages you are permitted to access, and internal operations.

Automation is not the same as sending HTTP requests. JavaScript execution, cookies, storage, navigation, popups, permissions, and browser rendering all matter. That is why your script must manage browser processes and should clean them up even when a test fails.

Choose Playwright or Selenium

Question Playwright Selenium
Primary model Python library for web-application automation, explicitly created for end-to-end testing. Python bindings that automate browsers through WebDriver.
Python interfaces Both synchronous and asynchronous APIs. Use the WebDriver API; select the integration style that fits your application and test runner.
Documented browsers Chromium, Firefox and WebKit; branded Chrome and Edge channels are also documented, subject to environment and enterprise-policy caveats. Chrome, Edge, Firefox, Safari, WebKitGTK and WPEWebKit are listed in the current Python API documentation.
Operating systems Windows, Linux and macOS are documented. Support depends on the selected browser, driver and platform; consult the current API and browser documentation.
Best starting point New end-to-end suites, especially when your code already uses asyncio or you want Playwright’s pytest plugin. Projects with existing WebDriver infrastructure, Selenium Grid conventions, or teams already invested in Selenium tooling.

Playwright’s Python documentation says, “Playwright was created specifically to accommodate the needs of end-to-end testing.” It also describes the library as a general-purpose browser-automation tool with powerful APIs for both sync and async Python. Selenium’s current documentation lists Python 3.10+ and says Selenium Manager handles driver installation in modern versions for most supported browsers and platforms.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • List every browser engine and operating system your release must cover.
  • Decide whether branded Chrome or Edge, rather than bundled browser binaries, is required.
  • Check whether the application already uses asyncio.
  • Identify your test runner. Playwright recommends its pytest plugin for end-to-end tests written with pytest.
  • Preserve existing WebDriver infrastructure unless there is a concrete reason to replace it.

Install Playwright on Python

Use an isolated virtual environment, then install the package and the browser binaries as separate steps:

  1. python -m venv .venv
  2. Activate it: .venv\Scripts\activate on Windows, or source .venv/bin/activate on Linux and macOS.
  3. python -m pip install --upgrade pip
  4. pip install playwright
  5. playwright install

The last command downloads the browser versions expected by the installed Playwright release. Playwright browser versions track library releases, so after upgrading the package you may need to run playwright install again. In locked-down environments, proxy, certificate, cache and permission settings can prevent that download; solve those deployment constraints rather than copying an old browser directory blindly.

Playwright: a complete synchronous example

This script opens a page, waits for a heading, fills a form, saves a screenshot and closes the browser in a finally block. Replace selectors with those from your application.

from pathlib import Path
from playwright.sync_api import sync_playwright

URL = "https://example.com/login"

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page(viewport={"width": 1440, "height": 900})
    try:
        page.goto(URL, wait_until="domcontentloaded", timeout=30_000)
        page.get_by_role("heading", name="Sign in").wait_for()
        page.get_by_label("Email").fill("[email protected]")
        page.get_by_label("Password").fill("use-a-test-secret")
        page.get_by_role("button", name="Sign in").click()
        page.wait_for_url("**/dashboard", timeout=30_000)
        page.screenshot(path="artifacts/dashboard.png", full_page=True)
        print(page.title())
    finally:
        browser.close()

Prefer accessible locators such as role, label and text over brittle CSS paths. A locator is resolved when an action runs, which helps with dynamic pages. Use an explicit URL wait, a selector wait, or a meaningful state assertion instead of arbitrary sleeps.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Playwright with asyncio

Use the asynchronous API when the rest of your service is already asynchronous or when you need to coordinate browser work with other async tasks.

Rank #2
Sale
Automate the Boring Stuff with Python, 2nd Edition: Practical Programming for Total Beginners
  • Language: english
  • Book - automate the boring stuff with python, 2nd edition: practical programming for total beginners
  • It is made up of premium quality material.
import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        page = await browser.new_page()
        try:
            await page.goto("https://example.com", wait_until="networkidle")
            await page.screenshot(path="example.webp")
            print(await page.title())
        finally:
            await browser.close()

if __name__ == "__main__":
    asyncio.run(main())

networkidle can be inappropriate for pages with continuous analytics or streaming requests. In those cases, wait for the specific element that proves the page is ready.

Use Playwright with pytest

For a pytest end-to-end suite, install Playwright’s pytest plugin and use its fixtures. A minimal test looks like this:

def test_homepage_title(page):
    page.goto("https://example.com")
    assert "Example" in page.title()

The plugin manages a browser context and page fixture for you. Keep test data isolated, avoid sharing mutable state between tests, and store traces, screenshots or videos only when a failure requires them so continuous-integration artifacts remain manageable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Selenium on Python

Create a virtual environment and install the current Python package:

  1. python -m venv .venv
  2. Activate the environment for your operating system.
  3. python -m pip install --upgrade pip
  4. pip install selenium

Modern Selenium uses Selenium Manager to locate or obtain the driver needed by most supported browser and platform combinations. A driver still interfaces with the browser, so the browser must be installed and executable in the execution environment. Enterprise policies, custom browser locations, restricted networks and unusual platforms may require explicit configuration.

Selenium: a complete Python example

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

URL = "https://example.com/login"

options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
options.add_argument("--window-size=1440,900")

driver = webdriver.Chrome(options=options)
try:
    driver.get(URL)
    wait = WebDriverWait(driver, 30)
    wait.until(EC.visibility_of_element_located((By.NAME, "email"))).send_keys("[email protected]")
    driver.find_element(By.NAME, "password").send_keys("use-a-test-secret")
    driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()
    wait.until(EC.url_contains("/dashboard"))
    Path("artifacts").mkdir(exist_ok=True)
    driver.save_screenshot("artifacts/dashboard.png")
    print(driver.title)
finally:
    driver.quit()

Use explicit waits for observable conditions. Implicit waits and fixed sleeps can obscure the real cause of a failure and make a suite slower. Choose stable attributes such as accessible names or dedicated test IDs, and keep browser options in configuration rather than scattering them through tests.

Browser, context and environment decisions

Headless versus headed

Headless mode is efficient for CI. Run headed locally when diagnosing layout, permissions, downloads or authentication. The two modes can expose different timing and rendering behavior, so reproduce an important failure in the same mode used by CI.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Bundled engines versus branded browsers

Playwright documents Chromium, Firefox and WebKit binaries and also documents branded Chrome and Edge channels. Channel availability and enterprise policies are environment-sensitive. Selenium uses the browser you configure, with the listed browser and platform support varying by version.

Isolation and credentials

  • Create a fresh Playwright browser context or Selenium profile for tests that must not share cookies or local storage.
  • Inject secrets through environment variables or your CI secret store; never commit passwords or tokens.
  • Use a test account and test data. Do not automate accounts or pages without authorization.
  • Set timeouts deliberately and collect a URL, console output and screenshot when a failure occurs.

Common failures and fixes

Symptom Likely cause Fix
Playwright says an executable is missing The Python package is installed but browser binaries are not. Run playwright install with the same environment and release you execute.
Browser download fails in CI Proxy, certificate, firewall or cache permissions block the download. Allow the download through your approved network path, configure the environment, or provision the documented browser cache during image creation.
Selenium cannot create a session The browser is absent, incompatible, blocked by policy, or Selenium Manager cannot reach its metadata. Verify the browser executable and version, inspect the full exception, and configure a driver or browser path explicitly when your platform requires it.
Element is not found The page is still loading, the locator is unstable, or content is inside a frame. Wait for a meaningful state, use a stable role/label/test ID, and switch to the correct frame before locating the element.
Click is intercepted A modal, consent banner or overlay covers the target. Handle the overlay as a real user would, wait for it to disappear, then click; do not rely on arbitrary delays.
Tests pass locally but fail in CI Different browser versions, viewport, fonts, CPU limits, permissions or network conditions. Pin compatible package/browser versions, set the viewport explicitly, capture artifacts, and reproduce in the CI image.
Navigation never finishes Long polling, streaming or third-party requests keep the network busy. Wait for the page element your test needs rather than global network idle.

Performance, reliability and cost considerations

The official material reviewed here does not establish a universal speed or reliability winner between Playwright and Selenium. Browser startup is expensive, so reuse a browser process where safe while keeping contexts or profiles isolated. Parallelize only when the machine has enough CPU, memory and browser capacity; otherwise contention creates misleading timeouts. Cache approved browser binaries in CI, but refresh them when the library version changes. Keep screenshots, traces and videos on failure rather than for every successful test unless your retention policy supports the storage cost.

Both approaches drive real browsers and therefore consume compute, display resources and network bandwidth. Budget separately for CI minutes, browser downloads, artifact storage and any remote execution service. A faster test that is flaky or leaks state is not cheaper to maintain.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your immediate task is obtaining a clean screenshot rather than interacting with a browser in Python, ScreenshotNeo provides a website screenshot API and MCP server. One request returns PNG, JPEG, WebP or a PDF. It accepts cookie or consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the API from Python like this (see the ScreenshotNeo documentation for options):

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

The equivalent cURL call is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

And in Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. It supports full-page and selector captures, device presets, custom viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks, hidden selectors, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Its parameter names also accept the names used by other screenshot APIs, easing migration.

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing gives two months free, and every feature is available on every plan. Create a free ScreenshotNeo account.

Frequently asked questions

Can I combine Playwright and Selenium in one project?

Yes, but keep ownership clear. Use separate test modules or services, document why each tool exists, and avoid sharing browser profiles between them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which library should a beginner learn first?

For a new Python end-to-end suite, start with Playwright’s synchronous API unless your application is already asynchronous. Start with Selenium when learning must align with an existing WebDriver-based team or platform.

Do I always need to download a driver for Selenium?

No. Current Selenium uses Selenium Manager for most supported setups. Driver and browser configuration can still be required in restricted or unusual environments.

Are Playwright’s browsers the same as my installed Chrome?

Not by default. Playwright installs browser binaries matched to its release, while branded Chrome or Edge channels are a separately documented option with environment caveats.

Frequently Asked Questions

Can I combine Playwright and Selenium in one project?

Yes, but keep ownership clear. Use separate test modules or services, document why each tool exists, and avoid sharing browser profiles between them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which library should a beginner learn first?

For a new Python end-to-end suite, start with Playwright’s synchronous API unless your application is already asynchronous. Start with Selenium when learning must align with an existing WebDriver-based team or platform.

Do I always need to download a driver for Selenium?

No. Current Selenium uses Selenium Manager for most supported setups. Driver and browser configuration can still be required in restricted or unusual environments.

Are Playwright’s browsers the same as my installed Chrome?

Not by default. Playwright installs browser binaries matched to its release, while branded Chrome or Edge channels are a separately documented option with environment caveats.

The Bottom Line

Choose Playwright for a new Python end-to-end suite or async integration; choose Selenium when WebDriver infrastructure and its browser/platform coverage are already central to your project. Install the browser components, wait on real page states, isolate test data, and make failures observable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.