diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..3ceab2b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,13 @@ +# These are supported funding model platforms + +github: Maxxrk # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..3efa093 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,41 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + deploy: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Print commit SHA + run: echo ${{ github.sha }} + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.gitignore b/.gitignore index 102e767..d53b120 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ wheels/ .installed.cfg *.egg MANIFEST +.pypirc # PyInstaller # Usually these files are written by a python script from a template @@ -104,4 +105,4 @@ venv.bak/ .mypy_cache/ .vscode/ -.idea/ \ No newline at end of file +.idea/ diff --git a/README.md b/README.md index 144dd80..145d80b 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,32 @@ # playwright_stealth Transplanted from [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth), **Not perfect**. +Forked from [playwright_stealth](https://github.com/AtuboDad/playwright_stealth) and re-released. ## Install ``` -$ pip install playwright-stealth +$ pip install playwright-sm ``` ## Usage + +Default stealth ### sync ```python - from playwright.sync_api import sync_playwright from playwright_stealth import stealth_sync with sync_playwright() as p: for browser_type in [p.chromium, p.firefox, p.webkit]: - browser = browser_type.launch() + browser = browser_type.launch(headless=False) page = browser.new_page() stealth_sync(page) - page.goto('http://whatsmyuseragent.org/') - page.screenshot(path=f'example-{browser_type.name}.png') + page.goto('https://bot.sannysoft.com/') + page.screenshot(path=f'example-{browser_type.name}.png', full_page=True) browser.close() - ``` + ### async ```python # -*- coding: utf-8 -*- @@ -35,22 +37,81 @@ from playwright_stealth import stealth_async async def main(): async with async_playwright() as p: for browser_type in [p.chromium, p.firefox, p.webkit]: - browser = await browser_type.launch() + browser = await browser_type.launch(headless=False) page = await browser.new_page() await stealth_async(page) - await page.goto('http://whatsmyuseragent.org/') - await page.screenshot(path=f'example-{browser_type.name}.png') + await page.goto('https://bot.sannysoft.com/') + await page.screenshot(path=f'example-{browser_type.name}.png', full_page=True) await browser.close() -asyncio.get_event_loop().run_until_complete(main()) +asyncio.run(main()) ``` -## Test results +Desired stealth argument (as a mobile device) +### sync +```python +from playwright.sync_api import sync_playwright +from playwright_stealth import stealth_sync, StealthConfig -### playwright with stealth +with sync_playwright() as p: + for browser_type in [p.chromium, p.firefox, p.webkit]: + browser = browser_type.launch(headless=False) + context = browser.new_context(**p.devices["Pixel 7"]) + page = context.new_page() + # Setting desired values for navigator properties + stealth_config = StealthConfig( + languages = ['en-US', 'en'], + navigator_plugins = False, # Mimicking real mobile device + navigator_hardware_concurrency = 8, + # nav_vendor = "", # Use only if you need to set empty string value to mimicking Firefox browser + nav_platform= 'Linux armv81', + vendor = 'Google Inc. (Qualcomm)', + renderer = 'ANGLE (Qualcomm, Adreno (TM) 640, OpenGL ES 3.2)', + ) + stealth_sync(page, stealth_config) + page.goto('https://bot.sannysoft.com/') + page.screenshot(path=f'example-{browser_type.name}.png', full_page=True) + browser.close() +``` -![playwright without stealth](./images/example_with_stealth.png) +### async +```python +# -*- coding: utf-8 -*- +import asyncio +from playwright.async_api import async_playwright +from playwright_stealth import stealth_async, StealthConfig + +async def main(): + async with async_playwright() as p: + for browser_type in [p.chromium, p.firefox, p.webkit]: + browser = await browser_type.launch(headless=False) + context = await browser.new_context(**p.devices["Pixel 7"]) + page = await context.new_page() + # Setting desired values for navigator properties + stealth_config = StealthConfig( + languages = ['en-US', 'en'], + navigator_plugins = False, # Mimicking real mobile device + navigator_hardware_concurrency = 8, + # nav_vendor = "", # Use only if you need to set empty string value to mimicking Firefox browser + nav_platform= 'Linux armv81', + vendor = 'Google Inc. (Qualcomm)', + renderer = 'ANGLE (Qualcomm, Adreno (TM) 640, OpenGL ES 3.2)', + ) + await stealth_async(page, stealth_config) + await page.goto('https://bot.sannysoft.com/') + await page.screenshot(path=f'example-{browser_type.name}.png') + await browser.close() + +asyncio.run(main()) +``` + +## Test results +### Playwright with stealth(no passed argument) +![playwright with stealth](./images/example_with_stealth.png) -### playwright without stealth +### Playwright without stealth +![playwright without stealth](./images/example_without_stealth.png) -![playwright with stealth](./images/example_without_stealth.png) +### Playwright with stealth(with passed argument) but as a mobile device +*NB: Mobile device have no plugin unlike desktop* +![playwright stealth with specified arguments](./images/example_with_stealth_passed_arguments.png) diff --git a/images/example_with_stealth_passed_arguments.png b/images/example_with_stealth_passed_arguments.png new file mode 100644 index 0000000..758533d Binary files /dev/null and b/images/example_with_stealth_passed_arguments.png differ diff --git a/playwright_stealth/js/chrome.csi.js b/playwright_stealth/js/chrome.csi.js index 388e39f..1391e39 100644 --- a/playwright_stealth/js/chrome.csi.js +++ b/playwright_stealth/js/chrome.csi.js @@ -14,7 +14,7 @@ if (!window.chrome) { if (!('csi' in window.chrome) && (window.performance || window.performance.timing)) { const {csi_timing} = window.performance - log.info('loading chrome.csi.js') + // log.info('loading chrome.csi.js') window.chrome.csi = function () { return { onloadT: csi_timing.domContentLoadedEventEnd, @@ -24,4 +24,4 @@ if (!('csi' in window.chrome) && (window.performance || window.performance.timin } } utils.patchToString(window.chrome.csi) -} \ No newline at end of file +} diff --git a/playwright_stealth/js/navigator.platform.js b/playwright_stealth/js/navigator.platform.js index f61e32f..6edbca3 100644 --- a/playwright_stealth/js/navigator.platform.js +++ b/playwright_stealth/js/navigator.platform.js @@ -1,5 +1,5 @@ if (opts.navigator_platform) { Object.defineProperty(Object.getPrototypeOf(navigator), 'platform', { - get: () => opts.navigator_plaftorm, + get: () => opts.navigator_platform, }) -} \ No newline at end of file +} diff --git a/playwright_stealth/js/navigator.userAgent.js b/playwright_stealth/js/navigator.userAgent.js index f35f07a..6085d8b 100644 --- a/playwright_stealth/js/navigator.userAgent.js +++ b/playwright_stealth/js/navigator.userAgent.js @@ -1,5 +1,5 @@ // replace Headless references in default useragent const current_ua = navigator.userAgent Object.defineProperty(Object.getPrototypeOf(navigator), 'userAgent', { - get: () => opts.navigator_user_agent || current_ua.replace('HeadlessChrome/', 'Chrome/') + get: () => window.opts.navigator_user_agent || current_ua.replace(/Headless/g, '') }) diff --git a/playwright_stealth/js/navigator.userAgentData.js b/playwright_stealth/js/navigator.userAgentData.js new file mode 100644 index 0000000..a1a0279 --- /dev/null +++ b/playwright_stealth/js/navigator.userAgentData.js @@ -0,0 +1,111 @@ +const ua = navigator.userAgent + +// const uaVersion = ua.includes('Chrome/') +// ? ua.match(/Chrome\/([\d|.]+)/)[1] +// : (await page.browser().version()).match(/\/([\d|.]+)/)[1] +const uaVersion = ua.match(/Chrome\/([\d|.]+)/)[1] + +// Source in C++: https://source.chromium.org/chromium/chromium/src/+/master:components/embedder_support/user_agent_utils.cc;l=55-100 +const _getBrands = () => { + // const seed = uaVersion.split('.')[0] // the major version number of Chrome + const seed = 124 + + const order = [ + [0, 1, 2], + [0, 2, 1], + [1, 0, 2], + [1, 2, 0], + [2, 0, 1], + [2, 1, 0] + ][seed % 6] + const escapedChars = [' ', ' ', ';'] + + const greaseyBrand = `${escapedChars[order[0]]}Not${ + escapedChars[order[1]] + }A${escapedChars[order[2]]}Brand` + + const greasedBrandVersionList = [] + greasedBrandVersionList[order[0]] = { + brand: greaseyBrand, + version: '99' + } + greasedBrandVersionList[order[1]] = { + brand: 'Chromium', + version: seed + } + greasedBrandVersionList[order[2]] = { + brand: 'Google Chrome', + version: seed + } + + return greasedBrandVersionList +} + +const metadata = { + platform: "macOS", + mobile: false, + brands: _getBrands() +} + +const highEntropyValues = { + "architecture": "arm", + "bitness": "64", + "brands": [ + { + "brand": "Chromium", + "version": "124" + }, + { + "brand": "Google Chrome", + "version": "124" + }, + { + "brand": "Not-A.Brand", + "version": "99" + } + ], + "fullVersionList": [ + { + "brand": "Chromium", + "version": "124.0.6367.208" + }, + { + "brand": "Google Chrome", + "version": "124.0.6367.208" + }, + { + "brand": "Not-A.Brand", + "version": "99.0.0.0" + } + ], + "mobile": false, + "model": "", + "platform": "macOS", + "platformVersion": "14.4.1", + "uaFullVersion": "124.0.6367.208" +} + +const userAgentMetadata = { + ...metadata, +} + +Object.defineProperty(userAgentMetadata, 'getHighEntropyValues', { + value: function(hints) { + return new Promise((resolve, reject) => { + let result = {}; + + hints.forEach(hint => { + if (highEntropyValues[hint]) { + result[hint] = highEntropyValues[hint]; + } + }); + + resolve(result); + }); + }, + enumerable: false +}); + +Object.defineProperty(Object.getPrototypeOf(navigator), 'userAgentData', { + get: () => userAgentMetadata +}) diff --git a/playwright_stealth/js/webgl.vendor.js b/playwright_stealth/js/webgl.vendor.js index 6b585a9..b93e00f 100644 --- a/playwright_stealth/js/webgl.vendor.js +++ b/playwright_stealth/js/webgl.vendor.js @@ -1,4 +1,3 @@ -console.log(opts) const getParameterProxyHandler = { apply: function (target, ctx, args) { const param = (args || [])[0] diff --git a/playwright_stealth/js/window.outerdimensions.js b/playwright_stealth/js/window.outerdimensions.js index e9ef868..00e1315 100644 --- a/playwright_stealth/js/window.outerdimensions.js +++ b/playwright_stealth/js/window.outerdimensions.js @@ -4,9 +4,7 @@ try { if (!!window.outerWidth && !!window.outerHeight) { const windowFrame = 85 // probably OS and WM dependent window.outerWidth = window.innerWidth - console.log(`current window outer height ${window.outerHeight}`) window.outerHeight = window.innerHeight + windowFrame - console.log(`new window outer height ${window.outerHeight}`) } } catch (err) { } diff --git a/playwright_stealth/stealth.py b/playwright_stealth/stealth.py index 721e6f4..470b7d7 100644 --- a/playwright_stealth/stealth.py +++ b/playwright_stealth/stealth.py @@ -1,38 +1,41 @@ # -*- coding: utf-8 -*- import json +import os from dataclasses import dataclass from typing import Tuple, Optional, Dict -import pkg_resources from playwright.async_api import Page as AsyncPage from playwright.sync_api import Page as SyncPage -def from_file(name): +def from_file(name) -> str: """Read script from ./js directory""" - return pkg_resources.resource_string('playwright_stealth', f'js/{name}').decode() + filename = os.path.join(os.path.dirname(__file__), "js", name) + with open(filename, encoding="utf-8") as f: + return f.read() SCRIPTS: Dict[str, str] = { - 'chrome_csi': from_file('chrome.csi.js'), - 'chrome_app': from_file('chrome.app.js'), - 'chrome_runtime': from_file('chrome.runtime.js'), - 'chrome_load_times': from_file('chrome.load.times.js'), - 'chrome_hairline': from_file('chrome.hairline.js'), - 'generate_magic_arrays': from_file('generate.magic.arrays.js'), - 'iframe_content_window': from_file('iframe.contentWindow.js'), - 'media_codecs': from_file('media.codecs.js'), - 'navigator_vendor': from_file('navigator.vendor.js'), - 'navigator_plugins': from_file('navigator.plugins.js'), - 'navigator_permissions': from_file('navigator.permissions.js'), - 'navigator_languages': from_file('navigator.languages.js'), - 'navigator_platform': from_file('navigator.platform.js'), - 'navigator_user_agent': from_file('navigator.userAgent.js'), - 'navigator_hardware_concurrency': from_file('navigator.hardwareConcurrency.js'), - 'outerdimensions': from_file('window.outerdimensions.js'), - 'utils': from_file('utils.js'), - 'webdriver': from_file('navigator.webdriver.js'), - 'webgl_vendor': from_file('webgl.vendor.js'), + "chrome_csi": from_file("chrome.csi.js"), + "chrome_app": from_file("chrome.app.js"), + "chrome_runtime": from_file("chrome.runtime.js"), + "chrome_load_times": from_file("chrome.load.times.js"), + "chrome_hairline": from_file("chrome.hairline.js"), + "generate_magic_arrays": from_file("generate.magic.arrays.js"), + "iframe_content_window": from_file("iframe.contentWindow.js"), + "media_codecs": from_file("media.codecs.js"), + "navigator_vendor": from_file("navigator.vendor.js"), + "navigator_plugins": from_file("navigator.plugins.js"), + "navigator_permissions": from_file("navigator.permissions.js"), + "navigator_languages": from_file("navigator.languages.js"), + "navigator_platform": from_file("navigator.platform.js"), + "navigator_user_agent": from_file("navigator.userAgent.js"), + "navigator_user_agent_data": from_file("navigator.userAgentData.js"), + "navigator_hardware_concurrency": from_file("navigator.hardwareConcurrency.js"), + "outerdimensions": from_file("window.outerdimensions.js"), + "utils": from_file("utils.js"), + "webdriver": from_file("navigator.webdriver.js"), + "webgl_vendor": from_file("webgl.vendor.js"), } @@ -54,6 +57,7 @@ def enabled_scripts(): yield 'console.log("last script")' ``` """ + # load script options webdriver: bool = True webgl_vendor: bool = True @@ -69,68 +73,65 @@ def enabled_scripts(): navigator_platform: bool = True navigator_plugins: bool = True navigator_user_agent: bool = True + navigator_user_agent_data: bool = True navigator_vendor: bool = True outerdimensions: bool = True hairline: bool = True # options - vendor: str = 'Intel Inc.' - renderer: str = 'Intel Iris OpenGL Engine' - nav_vendor: str = 'Google Inc.' + vendor: str = "Google Inc. (Apple)" + renderer: str = ( + "ANGLE (Apple, ANGLE Metal Renderer: Apple M2 Max, Unspecified Version)" + ) + nav_vendor: str = "Google Inc." nav_user_agent: str = None nav_platform: str = None - languages: Tuple[str] = ('en-US', 'en') + languages: Tuple[str] = ("en-US", "en") runOnInsecureOrigins: Optional[bool] = None @property def enabled_scripts(self): - opts = json.dumps({ - 'webgl_vendor': self.vendor, - 'webgl_renderer': self.renderer, - 'navigator_vendor': self.nav_vendor, - 'navigator_platform': self.nav_platform, - 'navigator_user_agent': self.nav_user_agent, - 'languages': list(self.languages), - 'runOnInsecureOrigins': self.runOnInsecureOrigins, - }) + opts = json.dumps( + { + "webgl_vendor": self.vendor, + "webgl_renderer": self.renderer, + "navigator_vendor": self.nav_vendor, + "navigator_platform": self.nav_platform, + "navigator_user_agent": self.nav_user_agent, + "navigator_user_agent_data": self.navigator_user_agent_data, + "languages": list(self.languages), + "runOnInsecureOrigins": self.runOnInsecureOrigins, + } + ) + # defined options constant - yield f'const opts = {opts}' + yield f"window.opts = {opts}; console.log('opts defined:', window.opts);" # init utils and generate_magic_arrays helper - yield SCRIPTS['utils'] - yield SCRIPTS['generate_magic_arrays'] - - if self.chrome_app: - yield SCRIPTS['chrome_app'] - if self.chrome_csi: - yield SCRIPTS['chrome_csi'] - if self.hairline: - yield SCRIPTS['chrome_hairline'] - if self.chrome_load_times: - yield SCRIPTS['chrome_load_times'] - if self.chrome_runtime: - yield SCRIPTS['chrome_runtime'] - if self.iframe_content_window: - yield SCRIPTS['iframe_content_window'] - if self.media_codecs: - yield SCRIPTS['media_codecs'] - if self.navigator_languages: - yield SCRIPTS['navigator_languages'] - if self.navigator_permissions: - yield SCRIPTS['navigator_permissions'] - if self.navigator_platform: - yield SCRIPTS['navigator_platform'] - if self.navigator_plugins: - yield SCRIPTS['navigator_plugins'] - if self.navigator_user_agent: - yield SCRIPTS['navigator_user_agent'] - if self.navigator_vendor: - yield SCRIPTS['navigator_vendor'] - if self.webdriver: - yield SCRIPTS['webdriver'] - if self.outerdimensions: - yield SCRIPTS['outerdimensions'] - if self.webgl_vendor: - yield SCRIPTS['webgl_vendor'] + yield SCRIPTS["utils"] + yield SCRIPTS["generate_magic_arrays"] + + script_keys = [ + "chrome_app", + "chrome_csi", + "chrome_hairline", + "chrome_load_times", + "chrome_runtime", + "iframe_content_window", + "media_codecs", + "navigator_languages", + "navigator_permissions", + "navigator_platform", + "navigator_plugins", + "navigator_user_agent", + "navigator_user_agent_data", + "navigator_vendor", + "webdriver", + "outerdimensions", + "webgl_vendor", + ] + + for key in script_keys: + yield f"{SCRIPTS[key]}; console.log('Script {key} executed with opts:', window.opts);" def stealth_sync(page: SyncPage, config: StealthConfig = None): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1d284e0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=64.0.0", "wheel"] +build-backend = "setuptools.build_meta" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0769d44..a7c2dbd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -playwright +playwright==1.52.0 flake8 pytest \ No newline at end of file diff --git a/setup.py b/setup.py index d8de041..1336e8e 100644 --- a/setup.py +++ b/setup.py @@ -4,14 +4,14 @@ long_description = fh.read() setuptools.setup( - name="playwright-stealth", - version="1.0.6", + name="playwright-sm", + version="0.0.1", author="AtuboDad", - author_email="lcjasas@sina.com", + author_email="maxxrk@pm.me", description="playwright stealth", long_description=long_description, long_description_content_type="text/markdown", - url="https://github.com/AtuboDad/playwright_stealth", + url="https://github.com/MaxxRK/playwright_stealth", packages=setuptools.find_packages(), classifiers=[ "Programming Language :: Python :: 3", @@ -19,9 +19,13 @@ "Operating System :: OS Independent", ], package_data={"playwright_stealth": ["js/*.js"]}, - python_requires='>=3, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', + python_requires=">=3.10", install_requires=[ - 'playwright', + "playwright==1.52.0", ], - extras_require={"test": ["pytest", ]}, + extras_require={ + "test": [ + "pytest", + ] + }, ) diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..03f1fef --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,4 @@ +# Folders +.profile + +*.png \ No newline at end of file diff --git a/tests/demo_persistent_test.py b/tests/demo_persistent_test.py index 28d9218..0a4bb9c 100644 --- a/tests/demo_persistent_test.py +++ b/tests/demo_persistent_test.py @@ -1,12 +1,13 @@ +import os import getpass from playwright.sync_api import sync_playwright from playwright_stealth import stealth_sync -chrome_path = 'C:\\Google\\Chrome\\Application\\chrome.exe' -# 当前用户的Chrome缓存路径 -user_dir_path = f"C:\\Users\\{getpass.getuser()}\\AppData\\Local\\Google\\Chrome\\User Data" + +home_dir = os.path.expanduser("~") +user_dir_path = os.path.join(home_dir, ".profile") channel = 'chrome' headless = False args = ['--ignore-certificate-errors', @@ -23,7 +24,7 @@ browser = p.chromium.launch_persistent_context( user_data_dir=user_dir_path, channel=channel, - executable_path=chrome_path, + #executable_path=chrome_path, args=args, accept_downloads=True, headless=False, @@ -40,3 +41,6 @@ # return False print(f'window navigator webdriver value: {webdriver_flag}') page.screenshot(path=f'example_with_persistent.png') + + input('Press any key to exit...') + browser.close() diff --git a/tests/demo_with_stealth_test.py b/tests/demo_with_stealth_test.py index 04d7f95..4c5d924 100644 --- a/tests/demo_with_stealth_test.py +++ b/tests/demo_with_stealth_test.py @@ -2,7 +2,6 @@ from playwright_stealth import stealth_sync -executablePath = 'C:\\Google\\Chrome\\Application\\chrome.exe' ipAndPort = '221.1.90.67:9000' args = [ '--no-sandbox', @@ -17,8 +16,11 @@ headless = False with sync_playwright() as p: - browser = p.chromium.launch(executable_path=executablePath, args=args, - ignore_default_args=ignoreDefaultArgs, headless=headless) + browser = p.chromium.launch( + args=args, + ignore_default_args=ignoreDefaultArgs, + headless=headless + ) page = browser.new_page() stealth_sync(page) page.goto('https://bot.sannysoft.com/') @@ -30,5 +32,20 @@ # return None print(f'window navigator webdriver value: {webdriver_flag}') - page.screenshot(path=f'example_with_stealth.png', full_page=True) - browser.close() + page.screenshot(path=f'example_with_stealth_chrome.png', full_page=True) + input('Press any key to continue to firefox...') + +with sync_playwright() as p: + browser = p.firefox.launch( + args=args, + headless=headless, + ) + page = browser.new_page() + stealth_sync(page) + page.goto('https://bot.sannysoft.com/') + webdriver_flag = page.evaluate('''() => { + return window.navigator.webdriver + }''') + print(f'window navigator webdriver value: {webdriver_flag}') + page.screenshot(path=f'example_with_stealth_firefox.png', full_page=True) + input('Press any key to exit...') diff --git a/tests/demo_without_stealth_test.py b/tests/demo_without_stealth_test.py index bf6961e..1268425 100644 --- a/tests/demo_without_stealth_test.py +++ b/tests/demo_without_stealth_test.py @@ -2,7 +2,7 @@ from playwright_stealth import stealth_sync -executablePath = 'C:\\Google\\Chrome\\Application\\chrome.exe' +#executablePath = 'C:\\Google\\Chrome\\Application\\chrome.exe' ipAndPort = '221.1.90.67:9000' args = [ '--no-sandbox', @@ -17,8 +17,11 @@ headless = False with sync_playwright() as p: - browser = p.chromium.launch(executable_path=executablePath, args=args, - ignore_default_args=ignoreDefaultArgs, headless=headless) + browser = p.chromium.launch( + args=args, + ignore_default_args=ignoreDefaultArgs, + headless=headless + ) page = browser.new_page() page.goto('https://bot.sannysoft.com/') @@ -29,5 +32,19 @@ # return None print(f'window navigator webdriver value: {webdriver_flag}') - page.screenshot(path=f'example_without_stealth.png', full_page=True) - browser.close() + page.screenshot(path=f'example_without_stealth_chrome.png', full_page=True) + input('Press any key to continue to firefox...') + +with sync_playwright() as p: + browser = p.firefox.launch( + args=args, + headless=headless, + ) + page = browser.new_page() + page.goto('https://bot.sannysoft.com/') + webdriver_flag = page.evaluate('''() => { + return window.navigator.webdriver + }''') + print(f'window navigator webdriver value: {webdriver_flag}') + page.screenshot(path=f'example_without_stealth_firefox.png', full_page=True) + input('Press any key to exit...')