Transplanted from puppeteer-extra-plugin-stealth, with some improvements. Don't expect this to bypass anything but the simplest of bot detection methods. Consider this a proof-of-concept starting point.
This is a WIP fork, with the goal of replacing the out-of-date upstream.
$ pip install git+https://github.com/Mattwmaster58/playwright_stealth
import asyncio
from playwright.async_api import async_playwright
from playwright_stealth import Stealth
async def main():
# This is the recommended usage. All pages created will have stealth applied:
async with Stealth().use_async(async_playwright()) as p:
browser = await p.chromium.launch()
page = await browser.new_page()
print("from new_page: ", await page.evaluate("navigator.webdriver"))
different_context = await browser.new_context()
page_from_different_context = await different_context.new_page()
print("from new_context: ", await page_from_different_context.evaluate("navigator.webdriver"))
# Specifying config options and applying evasions manually to an entire context:
custom_languages = ["fr-FR", "fr"]
stealth = Stealth(
navigator_languages_override=custom_languages,
init_scripts_only=True
)
async with async_playwright() as p:
browser = await p.chromium.launch()
context = await browser.new_context()
await stealth.apply_stealth_async(context)
page_1 = await context.new_page()
concurrency_on_page_1_mocked = await page_1.evaluate("navigator.languages") == custom_languages
print("manually applied stealth applied to page 1:", concurrency_on_page_1_mocked)
page_2 = await context.new_page()
concurrency_on_page_2_mocked = await page_2.evaluate("navigator.languages") == custom_languages
print("manually applied stealth applied to page 2:", concurrency_on_page_2_mocked)
asyncio.run(main())
A set of