undetected-playwright
Usage
-
Download PyPi package
pip install -U undetected-playwright
-
Donload dependencies
playwright install --with-deps
-
Quick started
import webbrowser
from datetime import datetime
from pathlib import Path
from playwright.sync_api import sync_playwright, Page
from undetected_playwright import Tarnished
def cache_screenshot(page: Page):
_now = datetime.now().strftime("%Y-%m-%d")
_suffix = f"-view-new-{datetime.now().strftime('%H%M%S')}"
path = f"result/{_now}/sannysoft{_suffix}.png"
page.screenshot(path=path, full_page=True)
webbrowser.open(f"file://{Path(path).resolve()}")
def main():
args = ["--headless=new", "--dump-dom"]
with sync_playwright() as p:
browser = p.chromium.launch(args=args)
context = browser.new_context(locale="en-US")
Tarnished.apply_stealth(context)
page = context.new_page()
page.goto("https://bot.sannysoft.com/", wait_until="networkidle")
cache_screenshot(page)
browser.close()
if __name__ == "__main__":
main()
Demo: SyncPlaywright Sannysoft
import logging
import sys
from datetime import datetime
from enum import Enum
from playwright.sync_api import sync_playwright, Page, Route
from undetected_playwright import Tarnished
logging.basicConfig(
level=logging.DEBUG, stream=sys.stdout, format="%(asctime)s - %(levelname)s - %(message)s"
)
class ViewMode(str, Enum):
new = "new"
headless = "headless"
headful = "headful"
def _hijacker(route: Route):
logging.debug(f"{route.request.method} {route.request.url}")
route.continue_()
def worker(page: Page, view_mode: ViewMode | None = None):
logging.info(f"Worker started - {view_mode=}")
page.route("**/*", _hijacker)
page.goto("https://bot.sannysoft.com/", wait_until="networkidle")
_now = datetime.now().strftime("%Y-%m-%d")
if view_mode:
_suffix = f"-view-{view_mode}"
else:
_suffix = f"-view-{datetime.now().strftime('%H%M%S')}"
page.screenshot(path=f"result/{_now}/sannysoft{_suffix}.png", full_page=True)
logging.info(f"Worker finished - {view_mode=}")
def bytedance(view_mode: ViewMode):
with sync_playwright() as p:
match view_mode:
case "new":
args = ["--headless=new", "--dump-dom"]
browser = p.chromium.launch(args=args)
case "headless":
browser = p.chromium.launch(headless=True)
case _:
browser = p.chromium.launch(headless=False)
context = browser.new_context(locale="en-US")
Tarnished.apply_stealth(context)
page = context.new_page()
worker(page, view_mode)
browser.close()
def main():
bytedance(ViewMode.new)
bytedance(ViewMode.headful)
bytedance(ViewMode.headless)
if __name__ == "__main__":
main()
Demo: AsyncPlaywright CloudFlare
import asyncio
import logging
import sys
from datetime import datetime
from enum import Enum
from playwright.async_api import async_playwright, Page, Route
from undetected_playwright import Malenia
logging.basicConfig(
level=logging.DEBUG, stream=sys.stdout, format="%(asctime)s - %(levelname)s - %(message)s"
)
class ViewMode(str, Enum):
new = "new"
headless = "headless"
headful = "headful"
async def _hijacker(route: Route):
logging.debug(f"{route.request.method} {route.request.url}")
await route.continue_()
async def worker(page: Page, view_mode: ViewMode | None = None):
logging.info(f"Worker started - {view_mode=}")
await page.route("**/*", _hijacker)
await page.goto("https://www.nowsecure.nl", wait_until="networkidle")
await page.wait_for_timeout(8000)
_now = datetime.now().strftime("%Y-%m-%d")
if view_mode:
_suffix = f"-view-{view_mode}"
else:
_suffix = f"-view-{datetime.now().strftime('%H%M%S')}"
await page.screenshot(path=f"result/{_now}/cloudflare{_suffix}.png", full_page=True)
logging.info(f"Worker finished - {view_mode=}")
async def bytedance(view_mode: ViewMode):
async with async_playwright() as p:
match view_mode:
case "new":
args = ["--headless=new", "--dump-dom"]
browser = await p.chromium.launch(args=args)
case "headless":
browser = await p.chromium.launch(headless=True)
case _:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(locale="en-US")
await Malenia.apply_stealth(context)
page = await context.new_page()
await worker(page, view_mode)
await browser.close()
async def main():
await bytedance(ViewMode.new)
await bytedance(ViewMode.headful)
await bytedance(ViewMode.headless)
if __name__ == "__main__":
asyncio.run(main())
Reference