From c3ce0b0e8278c1d2a59dce64a0a02d5063b7349b Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 11 Sep 2024 01:14:57 -0400 Subject: [PATCH 1/5] Make the Recorder stealthier --- seleniumbase/console_scripts/sb_mkrec.py | 35 ++++++++++++++++++++- seleniumbase/console_scripts/sb_recorder.py | 7 +++++ seleniumbase/fixtures/base_case.py | 5 +++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/seleniumbase/console_scripts/sb_mkrec.py b/seleniumbase/console_scripts/sb_mkrec.py index 6becb6c48da..65933894b74 100644 --- a/seleniumbase/console_scripts/sb_mkrec.py +++ b/seleniumbase/console_scripts/sb_mkrec.py @@ -181,6 +181,28 @@ def main(): data.append("") data.append("class RecorderTest(BaseCase):") data.append(" def test_recording(self):") + if use_uc: + data.append(" if self.undetectable:") + if ( + start_page + and ( + start_page.startswith("http:") + or start_page.startswith("https:") + or start_page.startswith("file:") + ) + ): + used_sp = start_page + if '"' not in start_page: + used_sp = '"%s"' % start_page + elif "'" not in start_page: + used_sp = "'%s'" % start_page + data.append( + " self.uc_open_with_disconnect(\n" + " %s\n" + " )" % used_sp + ) + else: + data.append(" self.disconnect()") data.append(" if self.recorder_ext:") data.append(" # When done recording actions,") data.append(' # type "c", and press [Enter].') @@ -231,7 +253,18 @@ def main(): ) print(success) run_cmd = None - if not start_page: + if ( + not start_page + or ( + use_uc + and ( + start_page.startswith("http:") + or start_page.startswith("https:") + or start_page.startswith("file:") + ) + and not esc_end + ) + ): run_cmd = "%s -m pytest %s --rec -q -s" % (sys_executable, file_name) else: run_cmd = "%s -m pytest %s --rec -q -s --url=%s" % ( diff --git a/seleniumbase/console_scripts/sb_recorder.py b/seleniumbase/console_scripts/sb_recorder.py index 056cb2b61f1..0e9e3365f67 100644 --- a/seleniumbase/console_scripts/sb_recorder.py +++ b/seleniumbase/console_scripts/sb_recorder.py @@ -197,6 +197,13 @@ def do_playback(file_name, use_chrome, window, demo_mode=False): command += " --edge" if demo_mode: command += " --demo" + command_args = sys.argv[2:] + if ( + "--uc" in command_args + or "--undetected" in command_args + or "--undetectable" in command_args + ): + command += " --uc" poll = None if sb_config.rec_subprocess_used: poll = sb_config.rec_subprocess_p.poll() diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 851514a10ee..0d02e781585 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -16029,6 +16029,11 @@ def tearDown(self): # This test already called tearDown() return if hasattr(self, "recorder_mode") and self.recorder_mode: + if self.undetectable: + try: + self.driver.window_handles + except Exception: + self.driver.connect() self.__process_recorded_actions() self.__called_teardown = True self.__called_setup = False From f745eee9efee6514969b663e9aaea95db98da05d Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 11 Sep 2024 01:16:30 -0400 Subject: [PATCH 2/5] Improve UC Mode --- seleniumbase/core/browser_launcher.py | 45 +++++++++++++++++++++------ 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 413aec8d36c..6559cbc186e 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -728,8 +728,23 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25): install_pyautogui_if_missing(driver) import pyautogui pyautogui = get_configured_pyautogui(pyautogui) + connected = True + width_ratio = 1.0 if IS_WINDOWS: - width_ratio = 1.0 + try: + driver.window_handles + except Exception: + connected = False + if ( + not connected + and ( + not hasattr(sb_config, "_saved_width_ratio") + or not sb_config._saved_width_ratio + ) + ): + driver.reconnect(0.1) + connected = True + if IS_WINDOWS and connected: window_rect = driver.get_window_rect() width = window_rect["width"] height = window_rect["height"] @@ -751,13 +766,24 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25): sb_config._saved_width_ratio = width_ratio driver.minimize_window() driver.set_window_rect(win_x, win_y, width, height) + elif ( + IS_WINDOWS + and not connected + and hasattr(sb_config, "_saved_width_ratio") + and sb_config._saved_width_ratio + ): + width_ratio = sb_config._saved_width_ratio + if IS_WINDOWS: x = x * width_ratio y = y * width_ratio _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) return - page_actions.switch_to_window( - driver, driver.current_window_handle, 2, uc_lock=False - ) + try: + page_actions.switch_to_window( + driver, driver.current_window_handle, 2, uc_lock=False + ) + except Exception: + pass _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) @@ -958,21 +984,20 @@ def _uc_gui_click_captcha( pass reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5 if IS_LINUX: - reconnect_time = constants.UC.RECONNECT_TIME + 0.15 + reconnect_time = constants.UC.RECONNECT_TIME + 0.2 if not x or not y: reconnect_time = 1 # Make it quick (it already failed) driver.reconnect(reconnect_time) - if blind: + if blind or (IS_LINUX and "Just a moment" in driver.title): retry = True + blind = True if retry and x and y and _on_a_captcha_page(driver): with gui_lock: # Prevent issues with multiple processes # Make sure the window is on top page_actions.switch_to_window( driver, driver.current_window_handle, 2, uc_lock=False ) - if not driver.is_element_present("iframe"): - return - else: + if driver.is_element_present("iframe"): try: driver.switch_to_frame(frame) except Exception: @@ -1179,7 +1204,7 @@ def _uc_gui_handle_captcha( pass reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5 if IS_LINUX: - reconnect_time = constants.UC.RECONNECT_TIME + 0.15 + reconnect_time = constants.UC.RECONNECT_TIME + 0.2 driver.reconnect(reconnect_time) From aaa68a6d8470979852ed534427de503dea576e20 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 11 Sep 2024 01:17:41 -0400 Subject: [PATCH 3/5] Refresh Python dependencies --- mkdocs_build/requirements.txt | 2 +- requirements.txt | 8 ++++---- setup.py | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index 22c596a7931..a9d21ae460e 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -3,7 +3,7 @@ regex>=2024.7.24 pymdown-extensions>=10.9 -pipdeptree>=2.23.1 +pipdeptree>=2.23.3 python-dateutil>=2.8.2 Markdown==3.7 markdown2==2.5.0 diff --git a/requirements.txt b/requirements.txt index a83a65fa9ab..510ce34b74d 100755 --- a/requirements.txt +++ b/requirements.txt @@ -11,9 +11,9 @@ attrs>=24.2.0 certifi>=2024.8.30 exceptiongroup>=1.2.2 filelock>=3.12.2;python_version<"3.8" -filelock>=3.15.4;python_version>="3.8" +filelock>=3.16.0;python_version>="3.8" platformdirs>=4.0.0;python_version<"3.8" -platformdirs>=4.2.2;python_version>="3.8" +platformdirs>=4.3.2;python_version>="3.8" typing-extensions>=4.12.2;python_version>="3.8" parse>=1.20.2 parse-type>=0.6.3 @@ -47,7 +47,7 @@ pluggy==1.2.0;python_version<"3.8" pluggy==1.5.0;python_version>="3.8" py==1.11.0 pytest==7.4.4;python_version<"3.8" -pytest==8.3.2;python_version>="3.8" +pytest==8.3.3;python_version>="3.8" pytest-html==2.0.1 pytest-metadata==3.0.0;python_version<"3.8" pytest-metadata==3.1.1;python_version>="3.8" @@ -73,7 +73,7 @@ python-xlib==0.33;platform_system=="Linux" markdown-it-py==2.2.0;python_version<"3.8" markdown-it-py==3.0.0;python_version>="3.8" mdurl==0.1.2 -rich==13.8.0 +rich==13.8.1 # --- Testing Requirements --- # # ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.) diff --git a/setup.py b/setup.py index 968f434b044..c84e5295244 100755 --- a/setup.py +++ b/setup.py @@ -159,9 +159,9 @@ "certifi>=2024.8.30", "exceptiongroup>=1.2.2", 'filelock>=3.12.2;python_version<"3.8"', - 'filelock>=3.15.4;python_version>="3.8"', + 'filelock>=3.16.0;python_version>="3.8"', 'platformdirs>=4.0.0;python_version<"3.8"', - 'platformdirs>=4.2.2;python_version>="3.8"', + 'platformdirs>=4.3.2;python_version>="3.8"', 'typing-extensions>=4.12.2;python_version>="3.8"', 'parse>=1.20.2', 'parse-type>=0.6.3', @@ -195,7 +195,7 @@ 'pluggy==1.5.0;python_version>="3.8"', "py==1.11.0", # Needed by pytest-html 'pytest==7.4.4;python_version<"3.8"', - 'pytest==8.3.2;python_version>="3.8"', + 'pytest==8.3.3;python_version>="3.8"', "pytest-html==2.0.1", # Newer ones had issues 'pytest-metadata==3.0.0;python_version<"3.8"', 'pytest-metadata==3.1.1;python_version>="3.8"', @@ -221,7 +221,7 @@ 'markdown-it-py==2.2.0;python_version<"3.8"', 'markdown-it-py==3.0.0;python_version>="3.8"', 'mdurl==0.1.2', - 'rich==13.8.0', + 'rich==13.8.1', ], extras_require={ # pip install -e .[allure] @@ -310,7 +310,7 @@ 'hyperframe==6.0.1', 'kaitaistruct==0.10', 'pyasn1==0.5.1;python_version<"3.8"', - 'pyasn1==0.6.0;python_version>="3.8"', + 'pyasn1==0.6.1;python_version>="3.8"', 'zstandard==0.23.0', ], }, From 268e9929d95ff9da2a6bc40422f6df85dab14150 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 11 Sep 2024 01:18:19 -0400 Subject: [PATCH 4/5] Update the docs --- README.md | 25 +++++++++++++------------ examples/ReadMe.md | 6 ++++++ integrations/github/workflows/extras.md | 8 ++++---- mkdocs.yml | 1 + seleniumbase/common/ReadMe.md | 2 +- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 241e0190770..0895fe5eb34 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

All-in-one Browser Automation Framework:
Web Crawling / Testing / Scraping / Stealth

-

PyPI version GitHub version SeleniumBase Docs SeleniumBase GitHub Actions Gitter chat

+

PyPI version GitHub version SeleniumBase Docs SeleniumBase GitHub Actions Join the SeleniumBase chat on Discord

🚀 Start | @@ -1361,22 +1361,23 @@ pytest --reruns=1 --reruns-delay=1

-

SeleniumBase

+

SeleniumBase

-SeleniumBase Playlist on YouTube -SeleniumBase on GitHub -SeleniumBase on Facebook -SeleniumBase on Gitter +SeleniumBase Playlist on YouTube +SeleniumBase on GitHub +SeleniumBase on Discord +SeleniumBase on Facebook +SeleniumBase on Gitter

https://github.com/mdmintz

-
-
SeleniumBase Docs
Tested with SeleniumBase
Gitter chat
-
Featured|HelloGitHub
-
SeleniumBase PyPI downloads
-
-
Views
+
+
SeleniumBase Docs
+
Tested with SeleniumBase
+
Featured|HelloGitHub Join the SeleniumBase chat on Discord Gitter chat
+
SeleniumBase PyPI downloads Views
+
diff --git a/examples/ReadMe.md b/examples/ReadMe.md index 840b616b1bc..0f3102fc0c2 100644 --- a/examples/ReadMe.md +++ b/examples/ReadMe.md @@ -251,6 +251,12 @@ python gui_test_runner.py -------- +

Join the SeleniumBase chat on Discord Join the SeleniumBase chat on Discord!

+ +Ask questions. Find answers. Learn how to automate! + +-------- + diff --git a/integrations/github/workflows/extras.md b/integrations/github/workflows/extras.md index 5d72984e721..a5d67509d15 100644 --- a/integrations/github/workflows/extras.md +++ b/integrations/github/workflows/extras.md @@ -1,10 +1,10 @@

Integrations for GitHub Actions:

### Uploading Artifacts: -* Here's an example using [upload-artifact@v2](https://github.com/actions/upload-artifact) to push up a SeleniumBase-generated artifact. +* Here's an example using [upload-artifact@v4](https://github.com/actions/upload-artifact) to push up a SeleniumBase-generated artifact. -``` - - uses: actions/upload-artifact@v2 +```yml + - uses: actions/upload-artifact@v4 with: name: Click to download the presentation path: saved_presentations/my_presentation.html @@ -18,7 +18,7 @@ * For this particular action, ``SLACK_CHANNEL`` is an optional environment variable that defaults to the webhook token channel if not specified. * The following example shows how to put a link to your workflow as the ``SLACK_MESSAGE`` (Lets you see artifacts pushed up, such as from the SeleniumBase Presenter feature!): -``` +```yml - name: Slack notification uses: rtCamp/action-slack-notify@master env: diff --git a/mkdocs.yml b/mkdocs.yml index 6a87aaefed4..ea530a02353 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -75,6 +75,7 @@ plugins: - examples/case_summary.md - help_docs/chinese.md - integrations/katalon/ReadMe.md + - help_docs/ReadMe.md - help_docs/verify_webdriver.md - help_docs/webdriver_installation.md - seleniumbase/masterqa/ReadMe.md diff --git a/seleniumbase/common/ReadMe.md b/seleniumbase/common/ReadMe.md index f8193129368..6927fa3ca9a 100644 --- a/seleniumbase/common/ReadMe.md +++ b/seleniumbase/common/ReadMe.md @@ -1,6 +1,6 @@ -## Using [seleniumbase/common](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/common) methods. +## [seleniumbase/common](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/common) decorators and security. ### Part 1: Decorators - (from [decorators.py](https://github.com/seleniumbase/SeleniumBase/blob/master/seleniumbase/common/decorators.py)) From b1698a166cefb916e50a8d8744798007ad598852 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 11 Sep 2024 01:18:45 -0400 Subject: [PATCH 5/5] Version 4.30.4 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 0305db40ed2..a408493f059 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.30.3" +__version__ = "4.30.4"