Merge pull request #3441 from seleniumbase/cdp-mode-patch-26
CDP Mode - Patch 26
This commit is contained in:
commit
afd20bcdc5
|
@ -6,16 +6,21 @@
|
|||
|
||||
--------
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM"><img src="https://github.com/user-attachments/assets/91e7ff7b-d155-4ba9-b17b-b097825fcf42" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM"><img src="https://github.com/user-attachments/assets/91e7ff7b-d155-4ba9-b17b-b097825fcf42" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM">Watch the CDP Mode tutorial on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
--------
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=vt2zsdiNh3U"><img src="https://github.com/user-attachments/assets/82ab2715-727e-4d09-9314-b8905795dc43" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=vt2zsdiNh3U"><img src="https://github.com/user-attachments/assets/82ab2715-727e-4d09-9314-b8905795dc43" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=vt2zsdiNh3U">Watch "Hacking websites with CDP" on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
--------
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=gEZhTfaIxHQ"><img src="https://github.com/user-attachments/assets/656977e1-5d66-4d1c-9eec-0aaa41f6522f" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=gEZhTfaIxHQ">Watch "Web-Scraping with GitHub Actions" on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
--------
|
||||
|
||||
👤 <b translate="no">UC Mode</b> avoids bot-detection by first disconnecting WebDriver from the browser at strategic times, calling special <code>PyAutoGUI</code> methods to bypass CAPTCHAs (as needed), and finally reconnecting the <code>driver</code> afterwards so that WebDriver actions can be performed again. Although this approach works for bypassing simple CAPTCHAs, more flexibility is needed for bypassing bot-detection on websites with advanced protection. (That's where <b translate="no">CDP Mode</b> comes in.)
|
||||
|
||||
🐙 <b translate="no">CDP Mode</b> is based on <a href="https://github.com/HyperionGray/python-chrome-devtools-protocol" translate="no">python-cdp</a>, <a href="https://github.com/HyperionGray/trio-chrome-devtools-protocol" translate="no">trio-cdp</a>, and <a href="https://github.com/ultrafunkamsterdam/nodriver" translate="no">nodriver</a>. <code>trio-cdp</code> is an early implementation of <code>python-cdp</code>, and <code>nodriver</code> is a modern implementation of <code>python-cdp</code>. (Refactored <code>Python-CDP</code> code is imported from <a href="https://github.com/mdmintz/MyCDP" translate="no">MyCDP</a>.)
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
from seleniumbase import SB
|
||||
|
||||
with SB(uc=True, test=True, ad_block=True) as sb:
|
||||
url = "https://www.glassdoor.com/Reviews/index.htm"
|
||||
sb.activate_cdp_mode(url)
|
||||
sb.uc_gui_click_captcha()
|
||||
sb.highlight('[data-test="global-nav-glassdoor-logo"]')
|
||||
sb.highlight('[data-test="site-header-companies"]')
|
||||
sb.highlight('[data-test="search-button"]')
|
||||
sb.highlight('[data-test="sign-in-button"]')
|
||||
sb.highlight('[data-test="company-search-autocomplete"]')
|
|
@ -0,0 +1,9 @@
|
|||
from seleniumbase import SB
|
||||
|
||||
with SB(uc=True, test=True, incognito=True) as sb:
|
||||
url = "https://seleniumbase.io/apps/invisible_recaptcha"
|
||||
sb.activate_cdp_mode(url)
|
||||
sb.sleep(1)
|
||||
sb.assert_element("img#captcha-success", timeout=3)
|
||||
sb.set_messenger_theme(location="top_left")
|
||||
sb.post_message("SeleniumBase wasn't detected", duration=3)
|
|
@ -1,14 +1,5 @@
|
|||
from seleniumbase import SB
|
||||
|
||||
with SB(uc=True, test=True, incognito=True) as sb:
|
||||
url = "https://seleniumbase.io/apps/recaptcha"
|
||||
sb.activate_cdp_mode(url)
|
||||
sb.sleep(1)
|
||||
sb.uc_gui_handle_captcha() # Try with TAB + SPACEBAR
|
||||
sb.assert_element("img#captcha-success", timeout=3)
|
||||
sb.set_messenger_theme(location="top_left")
|
||||
sb.post_message("SeleniumBase wasn't detected", duration=3)
|
||||
|
||||
with SB(uc=True, test=True, incognito=True) as sb:
|
||||
url = "https://seleniumbase.io/apps/recaptcha"
|
||||
sb.activate_cdp_mode(url)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from rich.pretty import pprint
|
||||
from seleniumbase import BaseCase
|
||||
BaseCase.main(__name__, __file__, "--uc", "--uc-cdp", "-s")
|
||||
BaseCase.main(__name__, __file__, "--uc", "--uc-cdp")
|
||||
|
||||
|
||||
class CDPTests(BaseCase):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Some sites use scripts to detect Selenium, and then block you.
|
||||
To evade detection, add --uc as a pytest command-line option."""
|
||||
from seleniumbase import BaseCase
|
||||
BaseCase.main(__name__, __file__, "--uc", "-s")
|
||||
BaseCase.main(__name__, __file__, "--uc")
|
||||
|
||||
|
||||
class UndetectedTest(BaseCase):
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
|
||||
---
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=5dMFI3e85ig"><img src="http://img.youtube.com/vi/5dMFI3e85ig/0.jpg" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=5dMFI3e85ig"><img src="http://img.youtube.com/vi/5dMFI3e85ig/0.jpg" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=5dMFI3e85ig">Watch the 1st UC Mode tutorial on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
----
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=2pTpBtaE7SQ"><img src="http://img.youtube.com/vi/2pTpBtaE7SQ/0.jpg" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=2pTpBtaE7SQ"><img src="http://img.youtube.com/vi/2pTpBtaE7SQ/0.jpg" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=2pTpBtaE7SQ">Watch the 2nd UC Mode tutorial on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
----
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=-EpZlhGWo9k"><img src="http://img.youtube.com/vi/-EpZlhGWo9k/0.jpg" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=-EpZlhGWo9k"><img src="http://img.youtube.com/vi/-EpZlhGWo9k/0.jpg" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=-EpZlhGWo9k">Watch the 3rd UC Mode tutorial on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
----
|
||||
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM"><img src="http://img.youtube.com/vi/Mr90iQmNsKM/0.jpg" title="SeleniumBase on YouTube" width="350" /></a>
|
||||
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM"><img src="http://img.youtube.com/vi/Mr90iQmNsKM/0.jpg" title="SeleniumBase on YouTube" width="320" /></a>
|
||||
<p>(<b><a href="https://www.youtube.com/watch?v=Mr90iQmNsKM">Watch the 4th UC Mode tutorial on YouTube! ▶️</a></b>)</p>
|
||||
|
||||
----
|
||||
|
|
|
@ -14,11 +14,11 @@ https://docs.docker.com/engine/install/
|
|||
|
||||
docker build -t seleniumbase .
|
||||
|
||||
If running on an Apple M1/M2 Mac, use this instead:
|
||||
**(NOTE) - If running on an Apple M1/M2 Mac, use this instead:**
|
||||
|
||||
docker build --platform linux/amd64 -t seleniumbase .
|
||||
|
||||
M1/M2 Mac users should also see [StackOverflow.com/a/76586216/7058266](https://stackoverflow.com/a/76586216/7058266) to **Enable Rosetta in Docker Desktop**. (Otherwise **you will** encounter errors like this when Chrome tries to launch: `"Chrome failed to start: crashed."`)
|
||||
**M1/M2 Mac users** should also see [StackOverflow.com/a/76586216/7058266](https://stackoverflow.com/a/76586216/7058266) to **Enable Rosetta in Docker Desktop**. (Otherwise **you will** encounter errors like this when Chrome tries to launch: `"Chrome failed to start: crashed."`)
|
||||
|
||||
#### 4. Run [the example test](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py) with Chrome inside your Docker: (Once the test completes after a few seconds, you'll automatically exit the Docker shell)
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ lxml==5.3.0
|
|||
pyquery==2.0.1
|
||||
readtime==3.0.0
|
||||
mkdocs==1.6.1
|
||||
mkdocs-material==9.5.49
|
||||
mkdocs-material==9.5.50
|
||||
mkdocs-exclude-search==0.6.6
|
||||
mkdocs-simple-hooks==0.1.5
|
||||
mkdocs-material-extensions==1.3.1
|
||||
|
|
|
@ -7,8 +7,9 @@ attrs>=24.3.0
|
|||
certifi>=2024.12.14
|
||||
exceptiongroup>=1.2.2
|
||||
websockets~=13.1;python_version<"3.9"
|
||||
websockets>=14.1;python_version>="3.9"
|
||||
filelock>=3.16.1
|
||||
websockets>=14.2;python_version>="3.9"
|
||||
filelock~=3.16.1;python_version<"3.9"
|
||||
filelock>=3.17.0;python_version>="3.9"
|
||||
fasteners>=0.19
|
||||
mycdp>=1.1.0
|
||||
pynose>=1.5.3
|
||||
|
@ -41,7 +42,8 @@ trio==0.28.0;python_version>="3.9"
|
|||
trio-websocket==0.11.1
|
||||
wsproto==1.2.0
|
||||
websocket-client==1.8.0
|
||||
selenium==4.27.1
|
||||
selenium==4.27.1;python_version<"3.9"
|
||||
selenium==4.28.0;python_version>="3.9"
|
||||
cssselect==1.2.0
|
||||
sortedcontainers==2.4.0
|
||||
execnet==2.1.1
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
# seleniumbase package
|
||||
__version__ = "4.33.15"
|
||||
__version__ = "4.34.0"
|
||||
|
|
|
@ -290,7 +290,9 @@ sbase mkdir ui_tests
|
|||
|
||||
* Options:
|
||||
|
||||
``-b`` / ``--basic`` (Only config files. No tests added.)
|
||||
```bash
|
||||
-b / --basic (Only config files. No tests added.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -350,27 +352,33 @@ sbase mkfile new_test.py
|
|||
|
||||
* Options:
|
||||
|
||||
``--uc`` (UC Mode boilerplate using SB context manager)
|
||||
`-b` / `--basic` (Basic boilerplate / single-line test)
|
||||
`-r` / `--rec` (Adds Pdb+ breakpoint for Recorder Mode)
|
||||
``--url=URL`` (Makes the test start on a specific page)
|
||||
```bash
|
||||
--uc (UC Mode boilerplate using SB context manager)
|
||||
-b / --basic (Basic boilerplate / single-line test)
|
||||
-r / --rec (Adds Pdb+ breakpoint for Recorder Mode)
|
||||
--url=URL (Makes the test start on a specific page)
|
||||
```
|
||||
|
||||
* Language Options:
|
||||
|
||||
``--en`` / ``--English`` | ``--zh`` / ``--Chinese``
|
||||
``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``
|
||||
``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``
|
||||
``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``
|
||||
``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``
|
||||
```bash
|
||||
--en / --English | --zh / --Chinese
|
||||
--nl / --Dutch | --fr / --French
|
||||
--it / --Italian | --ja / --Japanese
|
||||
--ko / --Korean | --pt / --Portuguese
|
||||
--ru / --Russian | --es / --Spanish
|
||||
```
|
||||
|
||||
* Syntax Formats:
|
||||
|
||||
``--bc`` / ``--basecase`` (BaseCase class inheritance)
|
||||
``--pf`` / ``--pytest-fixture`` (sb pytest fixture)
|
||||
``--cf`` / ``--class-fixture`` (class + sb pytest fixture)
|
||||
``--cm`` / ``--context-manager`` (SB context manager)
|
||||
``--dc`` / ``--driver-context`` (DriverContext manager)
|
||||
``--dm`` / ``--driver-manager`` (Driver manager)
|
||||
```bash
|
||||
--bc / --basecase (BaseCase class inheritance)
|
||||
--pf / --pytest-fixture (sb pytest fixture)
|
||||
--cf / --class-fixture (class + sb pytest fixture)
|
||||
--cm / --context-manager (SB context manager)
|
||||
--dc / --driver-context (DriverContext manager)
|
||||
--dm / --driver-manager (Driver manager)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -404,13 +412,15 @@ sbase codegen new_test.py --url=wikipedia.org
|
|||
|
||||
* Options:
|
||||
|
||||
``--url=URL`` (Sets the initial start page URL.)
|
||||
``--edge`` (Use Edge browser instead of Chrome.)
|
||||
``--gui`` / ``--headed`` (Use headed mode on Linux.)
|
||||
``--uc`` / ``--undetected`` (Use undetectable mode.)
|
||||
``--ee`` (Use SHIFT + ESC to end the recording.)
|
||||
``--overwrite`` (Overwrite file when it exists.)
|
||||
``--behave`` (Also output Behave/Gherkin files.)
|
||||
```bash
|
||||
--url=URL (Sets the initial start page URL.)
|
||||
--edge (Use Edge browser instead of Chrome.)
|
||||
--gui / --headed (Use headed mode on Linux.)
|
||||
--uc / --undetected (Use undetectable mode.)
|
||||
--ee (Use SHIFT + ESC to end the recording.)
|
||||
--overwrite (Overwrite file when it exists.)
|
||||
--behave (Also output Behave/Gherkin files.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -427,8 +437,10 @@ sbase recorder [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``--uc`` / ``--undetected`` (Use undetectable mode.)
|
||||
``--behave`` (Also output Behave/Gherkin files.)
|
||||
```bash
|
||||
--uc / --undetected (Use undetectable mode.)
|
||||
--behave (Also output Behave/Gherkin files.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -450,11 +462,13 @@ sbase mkpres new_presentation.py --en
|
|||
|
||||
* Language Options:
|
||||
|
||||
``--en`` / ``--English`` | ``--zh`` / ``--Chinese``
|
||||
``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``
|
||||
``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``
|
||||
``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``
|
||||
``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``
|
||||
```bash
|
||||
--en / --English | --zh / --Chinese
|
||||
--nl / --Dutch | --fr / --French
|
||||
--it / --Italian | --ja / --Japanese
|
||||
--ko / --Korean | --pt / --Portuguese
|
||||
--ru / --Russian | --es / --Spanish
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -480,11 +494,13 @@ sbase mkchart new_chart.py --en
|
|||
|
||||
* Language Options:
|
||||
|
||||
``--en`` / ``--English`` | ``--zh`` / ``--Chinese``
|
||||
``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``
|
||||
``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``
|
||||
``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``
|
||||
``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``
|
||||
```bash
|
||||
--en / --English | --zh / --Chinese
|
||||
--nl / --Dutch | --fr / --French
|
||||
--it / --Italian | --ja / --Japanese
|
||||
--ko / --Korean | --pt / --Portuguese
|
||||
--ru / --Russian | --es / --Spanish
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -504,7 +520,9 @@ sbase print [FILE] [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``-n`` (Add line Numbers to the rows)
|
||||
```bash
|
||||
-n (Add line Numbers to the rows)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -521,21 +539,27 @@ sbase translate [SB_FILE.py] [LANGUAGE] [ACTION]
|
|||
|
||||
* Languages:
|
||||
|
||||
``--en`` / ``--English`` | ``--zh`` / ``--Chinese``
|
||||
``--nl`` / ``--Dutch`` | ``--fr`` / ``--French``
|
||||
``--it`` / ``--Italian`` | ``--ja`` / ``--Japanese``
|
||||
``--ko`` / ``--Korean`` | ``--pt`` / ``--Portuguese``
|
||||
``--ru`` / ``--Russian`` | ``--es`` / ``--Spanish``
|
||||
```bash
|
||||
--en / --English | --zh / --Chinese
|
||||
--nl / --Dutch | --fr / --French
|
||||
--it / --Italian | --ja / --Japanese
|
||||
--ko / --Korean | --pt / --Portuguese
|
||||
--ru / --Russian | --es / --Spanish
|
||||
```
|
||||
|
||||
* Actions:
|
||||
|
||||
``-p`` / ``--print`` (Print translation output to the screen)
|
||||
``-o`` / ``--overwrite`` (Overwrite the file being translated)
|
||||
``-c`` / ``--copy`` (Copy the translation to a new ``.py`` file)
|
||||
```bash
|
||||
-p / --print (Print translation output to the screen)
|
||||
-o / --overwrite (Overwrite the file being translated)
|
||||
-c / --copy (Copy the translation to a new ``.py`` file)
|
||||
```
|
||||
|
||||
* Options:
|
||||
|
||||
``-n`` (include line Numbers when using the Print action)
|
||||
```bash
|
||||
-n (include line Numbers when using the Print action)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -573,7 +597,9 @@ sbase inject-objects [SB_FILE.py] [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``-c``, ``--comments`` (Add object selectors to the comments.)
|
||||
```bash
|
||||
-c / --comments (Add object selectors to the comments.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -591,7 +617,9 @@ sbase objectify [SB_FILE.py] [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``-c``, ``--comments`` (Add object selectors to the comments.)
|
||||
```bash
|
||||
-c / --comments (Add object selectors to the comments.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -611,7 +639,9 @@ sbase revert-objects [SB_FILE.py] [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``-c``, ``--comments`` (Keep existing comments for the lines.)
|
||||
```bash
|
||||
-c / --comments (Keep existing comments for the lines.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -639,7 +669,7 @@ Works on both Selenium IDE & Katalon Recorder scripts.
|
|||
|
||||
* Usage:
|
||||
|
||||
``sbase encrypt`` OR ``sbase obfuscate``
|
||||
``sbase encrypt`` / ``sbase obfuscate``
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -650,7 +680,7 @@ Runs the password encryption/obfuscation tool.
|
|||
|
||||
* Usage:
|
||||
|
||||
``sbase decrypt`` OR ``sbase unobfuscate``
|
||||
``sbase decrypt`` / ``sbase unobfuscate``
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -667,9 +697,11 @@ sbase proxy [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``--hostname=HOSTNAME`` (Set ``hostname``) (Default: ``127.0.0.1``)
|
||||
``--port=PORT`` (Set ``port``) (Default: ``8899``)
|
||||
``--help`` / ``-h`` (Display list of all available ``proxy`` options.)
|
||||
```bash
|
||||
--hostname=HOSTNAME (Set `hostname`) (Default: `127.0.0.1`)
|
||||
--port=PORT (Set `port`) (Default: `8899`)
|
||||
--help / -h (Display available `proxy` options.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -699,8 +731,10 @@ sbase grid-hub {start|stop|restart} [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``-v``, ``--verbose`` (Increases verbosity of logging output.)
|
||||
``--timeout=TIMEOUT`` (Close idle browser windows after TIMEOUT seconds.)
|
||||
```bash
|
||||
-v / --verbose (Increases verbosity of logging output.)
|
||||
--timeout=TIMEOUT (Close idle browser windows after TIMEOUT seconds.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
@ -720,8 +754,10 @@ sbase grid-node {start|stop|restart} [OPTIONS]
|
|||
|
||||
* Options:
|
||||
|
||||
``--hub=HUB_IP`` (The Grid Hub IP Address to connect to.) (Default: ``127.0.0.1``)
|
||||
``-v``, ``--verbose`` (Increases verbosity of logging output.)
|
||||
```bash
|
||||
--hub=HUB_IP (Grid Hub IP Address. Default: `127.0.0.1`)
|
||||
-v / --verbose (Increases verbosity of logging output.)
|
||||
```
|
||||
|
||||
* Output:
|
||||
|
||||
|
|
|
@ -156,9 +156,9 @@ def do_pytest_run(
|
|||
if save_screenshots:
|
||||
full_run_command += " --screenshot"
|
||||
|
||||
dash_s_needed = False
|
||||
if "-s" not in additional_options.split(" "):
|
||||
dash_s_needed = True
|
||||
capture_needed = False
|
||||
if "--capture" not in additional_options:
|
||||
capture_needed = True
|
||||
|
||||
additional_options = additional_options.strip()
|
||||
if additional_options:
|
||||
|
@ -168,8 +168,8 @@ def do_pytest_run(
|
|||
if verbose:
|
||||
full_run_command += " -v"
|
||||
|
||||
if dash_s_needed:
|
||||
full_run_command += " -s"
|
||||
if capture_needed:
|
||||
full_run_command += " --capture=tee-sys"
|
||||
|
||||
print(full_run_command)
|
||||
subprocess.Popen(full_run_command, shell=True)
|
||||
|
|
|
@ -888,6 +888,13 @@ def __install_pyautogui_if_missing():
|
|||
_xvfb_display.start()
|
||||
sb_config._virtual_display = _xvfb_display
|
||||
sb_config.headless_active = True
|
||||
if (
|
||||
hasattr(sb_config, "reuse_session")
|
||||
and sb_config.reuse_session
|
||||
and hasattr(sb_config, "_vd_list")
|
||||
and isinstance(sb_config._vd_list, list)
|
||||
):
|
||||
sb_config._vd_list.append(_xvfb_display)
|
||||
|
||||
|
||||
def install_pyautogui_if_missing(driver):
|
||||
|
@ -1217,6 +1224,13 @@ def _uc_gui_click_captcha(
|
|||
and driver.is_element_present("#challenge-form div > div")
|
||||
):
|
||||
frame = "#challenge-form div > div"
|
||||
elif (
|
||||
driver.is_element_present('[name*="cf-turnstile-"]')
|
||||
and driver.is_element_present(
|
||||
'[style="display: grid;"] div div'
|
||||
)
|
||||
):
|
||||
frame = '[style="display: grid;"] div div'
|
||||
elif (
|
||||
driver.is_element_present('[name*="cf-turnstile-"]')
|
||||
and driver.is_element_present("[class*=spacer] + div div")
|
||||
|
@ -3838,6 +3852,12 @@ def get_local_driver(
|
|||
edge_options.add_argument("--guest")
|
||||
if dark_mode:
|
||||
edge_options.add_argument("--enable-features=WebContentsForceDark")
|
||||
if headless1:
|
||||
# developer.chrome.com/blog/removing-headless-old-from-chrome
|
||||
with suppress(Exception):
|
||||
if int(str(use_version).split(".")[0]) >= 132:
|
||||
headless1 = False
|
||||
headless2 = True
|
||||
if headless2:
|
||||
try:
|
||||
if use_version == "latest" or int(use_version) >= 109:
|
||||
|
@ -4379,6 +4399,12 @@ def get_local_driver(
|
|||
use_version = find_chromedriver_version_to_use(
|
||||
use_version, driver_version
|
||||
)
|
||||
if headless1:
|
||||
# developer.chrome.com/blog/removing-headless-old-from-chrome
|
||||
with suppress(Exception):
|
||||
if int(str(use_version).split(".")[0]) >= 132:
|
||||
headless1 = False
|
||||
headless2 = True
|
||||
if headless2:
|
||||
try:
|
||||
if (
|
||||
|
|
|
@ -95,6 +95,7 @@ logging.getLogger("requests").setLevel(logging.ERROR)
|
|||
logging.getLogger("urllib3").setLevel(logging.ERROR)
|
||||
urllib3.disable_warnings()
|
||||
LOGGER.setLevel(logging.WARNING)
|
||||
is_linux = shared_utils.is_linux()
|
||||
is_windows = shared_utils.is_windows()
|
||||
python3_11_or_newer = False
|
||||
if sys.version_info >= (3, 11):
|
||||
|
@ -4828,7 +4829,7 @@ class BaseCase(unittest.TestCase):
|
|||
from seleniumbase.js_code.recorder_js import recorder_js
|
||||
|
||||
if not self.is_chromium():
|
||||
if "linux" not in sys.platform:
|
||||
if not is_linux:
|
||||
c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
|
||||
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
|
@ -5658,7 +5659,7 @@ class BaseCase(unittest.TestCase):
|
|||
c1 = ""
|
||||
c2 = ""
|
||||
cr = ""
|
||||
if "linux" not in sys.platform:
|
||||
if not is_linux:
|
||||
c1 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
||||
c2 = colorama.Fore.LIGHTRED_EX + colorama.Back.LIGHTYELLOW_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
|
@ -5760,7 +5761,7 @@ class BaseCase(unittest.TestCase):
|
|||
c1 = ""
|
||||
c2 = ""
|
||||
cr = ""
|
||||
if "linux" not in sys.platform:
|
||||
if not is_linux:
|
||||
c1 = colorama.Fore.RED + colorama.Back.LIGHTYELLOW_EX
|
||||
c2 = colorama.Fore.LIGHTRED_EX + colorama.Back.LIGHTYELLOW_EX
|
||||
cr = colorama.Style.RESET_ALL
|
||||
|
@ -14009,6 +14010,9 @@ class BaseCase(unittest.TestCase):
|
|||
if not self.undetectable:
|
||||
sb_config._virtual_display = self._xvfb_display
|
||||
sb_config.headless_active = True
|
||||
if self._reuse_session and hasattr(sb_config, "_vd_list"):
|
||||
if isinstance(sb_config._vd_list, list):
|
||||
sb_config._vd_list.append(self._xvfb_display)
|
||||
|
||||
def __activate_virtual_display(self):
|
||||
if self.undetectable and not (self.headless or self.headless2):
|
||||
|
@ -14033,6 +14037,9 @@ class BaseCase(unittest.TestCase):
|
|||
self.__activate_standard_virtual_display()
|
||||
else:
|
||||
self.headless_active = True
|
||||
if self._reuse_session and hasattr(sb_config, "_vd_list"):
|
||||
if isinstance(sb_config._vd_list, list):
|
||||
sb_config._vd_list.append(self._xvfb_display)
|
||||
except Exception as e:
|
||||
if hasattr(e, "msg"):
|
||||
print("\n" + str(e.msg))
|
||||
|
@ -14087,7 +14094,7 @@ class BaseCase(unittest.TestCase):
|
|||
"""This is only needed on Linux.
|
||||
The "--xvfb" arg is still useful, as it prevents headless mode,
|
||||
which is the default mode on Linux unless using another arg."""
|
||||
if "linux" in sys.platform and (not self.headed or self.xvfb):
|
||||
if is_linux and (not self.headed or self.xvfb):
|
||||
pip_find_lock = fasteners.InterProcessLock(
|
||||
constants.PipInstall.FINDLOCK
|
||||
)
|
||||
|
@ -16604,7 +16611,11 @@ class BaseCase(unittest.TestCase):
|
|||
# (Pynose / Behave / Pure Python) Close all open browser windows
|
||||
self.__quit_all_drivers()
|
||||
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
|
||||
if hasattr(self, "_xvfb_display") and self._xvfb_display:
|
||||
if (
|
||||
hasattr(self, "_xvfb_display")
|
||||
and self._xvfb_display
|
||||
and not self._reuse_session
|
||||
):
|
||||
# Stop the Xvfb virtual display launched from BaseCase
|
||||
try:
|
||||
if hasattr(self._xvfb_display, "stop"):
|
||||
|
@ -16619,6 +16630,13 @@ class BaseCase(unittest.TestCase):
|
|||
hasattr(sb_config, "_virtual_display")
|
||||
and sb_config._virtual_display
|
||||
and hasattr(sb_config._virtual_display, "stop")
|
||||
and (
|
||||
not hasattr(sb_config, "reuse_session")
|
||||
or (
|
||||
hasattr(sb_config, "reuse_session")
|
||||
and not sb_config.reuse_session
|
||||
)
|
||||
)
|
||||
):
|
||||
# CDP Mode may launch a 2nd Xvfb virtual display
|
||||
try:
|
||||
|
|
|
@ -1371,6 +1371,7 @@ def pytest_addoption(parser):
|
|||
|
||||
arg_join = " ".join(sys_argv)
|
||||
sb_config._browser_shortcut = None
|
||||
sb_config._vd_list = []
|
||||
|
||||
# SeleniumBase does not support pytest-timeout due to hanging browsers.
|
||||
for arg in sys_argv:
|
||||
|
@ -2017,6 +2018,13 @@ def pytest_runtest_teardown(item):
|
|||
hasattr(self, "_xvfb_display")
|
||||
and self._xvfb_display
|
||||
and hasattr(self._xvfb_display, "stop")
|
||||
and (
|
||||
not hasattr(sb_config, "reuse_session")
|
||||
or (
|
||||
hasattr(sb_config, "reuse_session")
|
||||
and not sb_config.reuse_session
|
||||
)
|
||||
)
|
||||
):
|
||||
self.headless_active = False
|
||||
sb_config.headless_active = False
|
||||
|
@ -2026,6 +2034,13 @@ def pytest_runtest_teardown(item):
|
|||
hasattr(sb_config, "_virtual_display")
|
||||
and sb_config._virtual_display
|
||||
and hasattr(sb_config._virtual_display, "stop")
|
||||
and (
|
||||
not hasattr(sb_config, "reuse_session")
|
||||
or (
|
||||
hasattr(sb_config, "reuse_session")
|
||||
and not sb_config.reuse_session
|
||||
)
|
||||
)
|
||||
):
|
||||
sb_config._virtual_display.stop()
|
||||
sb_config._virtual_display = None
|
||||
|
@ -2139,6 +2154,21 @@ def _perform_pytest_unconfigure_(config):
|
|||
except Exception:
|
||||
pass
|
||||
sb_config.shared_driver = None
|
||||
with suppress(Exception):
|
||||
if (
|
||||
hasattr(sb_config, "_virtual_display")
|
||||
and sb_config._virtual_display
|
||||
and hasattr(sb_config._virtual_display, "stop")
|
||||
):
|
||||
sb_config._virtual_display.stop()
|
||||
sb_config._virtual_display = None
|
||||
sb_config.headless_active = False
|
||||
if hasattr(sb_config, "_vd_list") and sb_config._vd_list:
|
||||
if isinstance(sb_config._vd_list, list):
|
||||
for display in sb_config._vd_list:
|
||||
if display:
|
||||
with suppress(Exception):
|
||||
display.stop()
|
||||
if hasattr(sb_config, "log_path") and sb_config.item_count > 0:
|
||||
log_helper.archive_logs_if_set(
|
||||
constants.Logs.LATEST + "/", sb_config.archive_logs
|
||||
|
@ -2193,6 +2223,9 @@ def _perform_pytest_unconfigure_(config):
|
|||
the_html_r = the_html_r.replace(
|
||||
ph_link, "%s and %s" % (sb_link, ph_link)
|
||||
)
|
||||
the_html_r = the_html_r.replace(
|
||||
"findAll('.collapsible", "//findAll('.collapsible"
|
||||
)
|
||||
the_html_r = the_html_r.replace(
|
||||
"mediaName.innerText", "//mediaName.innerText"
|
||||
)
|
||||
|
@ -2228,6 +2261,9 @@ def _perform_pytest_unconfigure_(config):
|
|||
html_style = html_style.replace(
|
||||
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
||||
)
|
||||
html_style = html_style.replace(".collapsible", ".oldc")
|
||||
html_style = html_style.replace(" (hide details)", "")
|
||||
html_style = html_style.replace(" (show details)", "")
|
||||
with open(assets_style, "w", encoding="utf-8") as f:
|
||||
f.write(html_style)
|
||||
with suppress(Exception):
|
||||
|
@ -2327,6 +2363,9 @@ def _perform_pytest_unconfigure_(config):
|
|||
html_style = html_style.replace(
|
||||
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
||||
)
|
||||
html_style = html_style.replace(".collapsible", ".oldc")
|
||||
html_style = html_style.replace(" (hide details)", "")
|
||||
html_style = html_style.replace(" (show details)", "")
|
||||
with open(assets_style, "w", encoding="utf-8") as f:
|
||||
f.write(html_style)
|
||||
with suppress(Exception):
|
||||
|
@ -2394,6 +2433,9 @@ def _perform_pytest_unconfigure_(config):
|
|||
the_html_r = the_html_r.replace(
|
||||
ph_link, "%s and %s" % (sb_link, ph_link)
|
||||
)
|
||||
the_html_r = the_html_r.replace(
|
||||
"findAll('.collapsible", "//findAll('.collapsible"
|
||||
)
|
||||
the_html_r = the_html_r.replace(
|
||||
"mediaName.innerText", "//mediaName.innerText"
|
||||
)
|
||||
|
|
8
setup.py
8
setup.py
|
@ -156,8 +156,9 @@ setup(
|
|||
"certifi>=2024.12.14",
|
||||
"exceptiongroup>=1.2.2",
|
||||
'websockets~=13.1;python_version<"3.9"',
|
||||
'websockets>=14.1;python_version>="3.9"',
|
||||
'filelock>=3.16.1',
|
||||
'websockets>=14.2;python_version>="3.9"',
|
||||
'filelock~=3.16.1;python_version<"3.9"',
|
||||
'filelock>=3.17.0;python_version>="3.9"',
|
||||
'fasteners>=0.19',
|
||||
"mycdp>=1.1.0",
|
||||
"pynose>=1.5.3",
|
||||
|
@ -190,7 +191,8 @@ setup(
|
|||
'trio-websocket==0.11.1',
|
||||
'wsproto==1.2.0',
|
||||
'websocket-client==1.8.0',
|
||||
'selenium==4.27.1',
|
||||
'selenium==4.27.1;python_version<"3.9"',
|
||||
'selenium==4.28.0;python_version>="3.9"',
|
||||
'cssselect==1.2.0',
|
||||
"sortedcontainers==2.4.0",
|
||||
'execnet==2.1.1',
|
||||
|
|
Loading…
Reference in New Issue