Patchright Tutorial installation + basic code async, sync
Patchright provides a stealth-focused (websites cannot easily detect that a bot (like Playwright/Selenium)) browser automation solution that maintains full API compatibility with Playwright.
Use: web scraping of protected sites, automated testing against security systems, and browser automation tasks where avoiding detection is critical.
simply change `from playwright.sync_api` to `from patchright.sync_api` (or the async equivalent).
1. Create virtual Enviorment (optional)
pip install virtualenv
virtualenv venv
venv\Scripts\activate
2. install patchright
pip install patchright
3. install browser
patchright install chrome
#or
patchright install chromium
4. make file abc.py SYNC
from patchright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
channel="chrome",
headless=False
)
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
browser.close()
OR ASYNC
import asyncio
import os
from patchright.async_api import async_playwright
async def main():
async with async_playwright() as p:
# Define where to store browser data (cookies, cache, etc.)
user_data_dir = os.path.join(os.getcwd(), "chrome_profile")
# Best Practice: Launching a persistent context with Chrome
# This bypasses standard fingerprinting by using a real browser channel
context = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome", # Uses the actual Chrome browser installed on your system
headless=False, # Headful is generally harder to detect
no_viewport=True, # Allows the window to dictate size, preventing scaling mismatches
# Avoid adding custom user_agent or extra_headers here to maintain a clean fingerprint
)
# In a persistent context, a page is usually opened automatically
page = context.pages[0] if context.pages else await context.new_page()
# Navigate and perform actions
await page.goto('https://playwright.dev')
print(f"Title: {await page.title()}")
# Take the screenshot
await page.screenshot(path=f'example-chrome-stealth.png')
# Close the context properly
await context.close()
if __name__ == "__main__":
asyncio.run(main())
with async:
1. open multiple pages
import asyncio
import os
from patchright.async_api import async_playwright
urls = [
"https://example.com",
"https://example.org",
"https://example.net"
]
async def open_page(context, url):
page = await context.new_page()
await page.goto(url)
print(f"{url} → {await page.title()}")
async def main():
async with async_playwright() as p:
user_data_dir = os.path.join(os.getcwd(), "chrome_profile")
context = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome",
headless=False,
no_viewport=True,
)
# ???? PARALLEL execution, * unpack list, gather accept list
await asyncio.gather(*[
open_page(context, url) for url in urls
])
await context.close()
asyncio.run(main())
2. auto google search
import asyncio
import os
from patchright.async_api import async_playwright
async def main():
async with async_playwright() as p:
user_data_dir = os.path.join(os.getcwd(), "chrome_profile")
context = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome", # Uses the actual Chrome browser installed on your system
headless=False, # Headful is generally harder to detect
no_viewport=True, # Allows the window to dictate size, preventing scaling mismatches
)
page = context.pages[0] if context.pages else await context.new_page()
await page.goto("https://www.google.com")
await page.wait_for_timeout(2000)
await page.fill("textarea[name='q']", "Patchright tutorial")
await page.wait_for_timeout(1000)
await page.keyboard.press("Enter")
await page.wait_for_timeout(3000)
print("Searched:", "Patchright tutorial"-)
if __name__ == "__main__":
asyncio.run(main())
3. login attempt
import asyncio
import os
from patchright.async_api import async_playwright
async def login(page):
await page.goto("https://practicetestautomation.com/practice-test-login/")
await page.fill("#username", "student")
await page.fill("#password", "Password123")
await page.click("#submit")
await page.wait_for_timeout(3000)
print("Login attempted")
async def main():
async with async_playwright() as p:
user_data_dir = os.path.join(os.getcwd(), "chrome_profile")
context = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome", # Uses the actual Chrome browser installed on your system
headless=False, # Headful is generally harder to detect
no_viewport=True, # Allows the window to dictate size, preventing scaling mismatches
)
page = context.pages[0] if context.pages else await context.new_page()
await login(page)
if __name__ == "__main__":
asyncio.run(main())
4. data scraping
import asyncio
import os
from patchright.async_api import async_playwright
async def scrape_titles(page):
await page.goto("https://news.ycombinator.com")
titles = await page.locator(".titleline > a").evaluate_all(
"els => els.map(el => el.textContent)"
)
for t in titles:
print("Title:", t)
async def main():
async with async_playwright() as p:
user_data_dir = os.path.join(os.getcwd(), "chrome_profile")
context = await p.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome", # Uses the actual Chrome browser installed on your system
headless=False, # Headful is generally harder to detect
no_viewport=True, # Allows the window to dictate size, preventing scaling mismatches
)
page = context.pages[0] if context.pages else await context.new_page()
await scrape_titles(page)
if __name__ == "__main__":
asyncio.run(main())