Patchright
Patchright is an undetected Python version of the Playwright testing and automation library (version 1.58.2). It serves as a drop-in replacement for Playwright, specifically designed to bypass modern anti-bot detection systems by patching Chrome DevTools Protocol (CDP) leaks and browser fingerprinting issues. The library is actively maintained and receives updates to combat evolving detection techniques.
Warnings
- breaking Patchright exclusively supports Chromium-based browsers (like Google Chrome, Microsoft Edge, Opera). Firefox and WebKit-based browsers are not supported, as the patching techniques are specific to the Blink engine.
- gotcha The Console API is completely disabled in Patchright to prevent detection via `Console.enable` leaks. `console.log()` and other console functionalities will not work.
- gotcha For maximum undetectability, avoid running Patchright in headless mode (`headless=True`) and refrain from adding custom user agents or extra HTTP headers in your launch options. Patchright applies specific tweaks to these by default.
- gotcha Patchright's use of Playwright Routes to inject JavaScript for InitScripts (to avoid `Runtime.enable` leaks) *may* cause unexpected bugs in other parts of your code that rely on Playwright Routes functionality.
Install
-
pip install patchright -
patchright install chrome
Imports
- sync_playwright
from patchright.sync_api import sync_playwright
- async_playwright
from patchright.async_api import async_playwright
Quickstart
import os
import asyncio
from patchright.sync_api import sync_playwright
def run_sync_example():
with sync_playwright() as p:
# Recommended configuration for maximum undetectability:
# Use launch_persistent_context with channel='chrome' and headless=False
# viewport=null (or no_viewport=True) prevents setting a fixed viewport, aiding stealth.
# user_data_dir is crucial for persisting cookies/session info if solving captchas manually.
user_data_dir = os.environ.get('PATCHRIGHT_USER_DATA_DIR', '/tmp/patchright_profile')
browser = p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome",
headless=False,
viewport=None, # equivalent to no_viewport=True
# Do NOT add custom browser headers or user_agent here, Patchright handles it.
)
page = browser.new_page()
try:
print(f"Navigating to example.com with {p.chromium.name}...")
page.goto("https://example.com")
print(f"Page title: {page.title()}")
# Example interaction: get text from an element
text = page.locator('h1').inner_text()
print(f"H1 text: {text}")
page.screenshot(path=f"example-{p.chromium.name}.png")
print("Screenshot saved.")
finally:
browser.close()
print("Browser closed.")
async def run_async_example():
async with async_playwright() as p:
user_data_dir = os.environ.get('PATCHRIGHT_USER_DATA_DIR_ASYNC', '/tmp/patchright_profile_async')
browser = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome",
headless=False,
viewport=None
)
page = await browser.new_page()
try:
print(f"Navigating to example.com (async) with {p.chromium.name}...")
await page.goto("https://example.com")
print(f"Page title (async): {await page.title()}")
text = await page.locator('h1').inner_text()
print(f"H1 text (async): {text}")
await page.screenshot(path=f"example-async-{p.chromium.name}.png")
print("Screenshot saved (async).")
finally:
await browser.close()
print("Browser closed (async).")
if __name__ == "__main__":
print("--- Running Synchronous Example ---")
run_sync_example()
print("\n--- Running Asynchronous Example ---")
# Make sure to install browsers: `patchright install chrome`
asyncio.run(run_async_example())