diff --git a/README.md b/README.md index b2ecddd35c8..8ae5587e7ba 100755 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ šŸ‘¤ Note that SeleniumBase UC Mode (Stealth Mode) has its own ReadMe. +šŸ™ Also note that Seleniumbase CDP Mode has its own separate ReadMe. + ā„¹ļø Scripts can be called via python, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically).

šŸ“— Here's my_first_test.py, which tests login, shopping, and checkout:

@@ -315,48 +317,49 @@ pip install -e . šŸ”µ **Type ``seleniumbase`` or ``sbase`` to verify that SeleniumBase was installed successfully:** ```bash - ______ __ _ ____ - / ____/__ / /__ ____ (_)_ ______ ___ / _ \____ ________ - \__ \/ _ \/ / _ \/ __ \/ / / / / __ `__ \ / /_) / __ \/ ___/ _ \ - ___/ / __/ / __/ / / / / /_/ / / / / / // /_) / (_/ /__ / __/ -/____/\___/_/\___/_/ /_/_/\__,_/_/ /_/ /_//_____/\__,_/____/\___/ ------------------------------------------------------------------- - - * USAGE: "seleniumbase [COMMAND] [PARAMETERS]" - * OR: "sbase [COMMAND] [PARAMETERS]" - -COMMANDS: - get / install [DRIVER] [OPTIONS] - methods (List common Python methods) - options (List common pytest options) - behave-options (List common behave options) - gui / commander [OPTIONAL PATH or TEST FILE] - behave-gui (SBase Commander for Behave) - caseplans [OPTIONAL PATH or TEST FILE] - mkdir [DIRECTORY] [OPTIONS] - mkfile [FILE.py] [OPTIONS] - mkrec / codegen [FILE.py] [OPTIONS] - recorder (Open Recorder Desktop App.) - record (If args: mkrec. Else: App.) - mkpres [FILE.py] [LANG] - mkchart [FILE.py] [LANG] - print [FILE] [OPTIONS] - translate [SB_FILE.py] [LANG] [ACTION] - convert [WEBDRIVER_UNITTEST_FILE.py] - extract-objects [SB_FILE.py] - inject-objects [SB_FILE.py] [OPTIONS] - objectify [SB_FILE.py] [OPTIONS] - revert-objects [SB_FILE.py] [OPTIONS] - encrypt / obfuscate - decrypt / unobfuscate - download server (Get Selenium Grid JAR file) - grid-hub [start|stop] [OPTIONS] - grid-node [start|stop] --hub=[HOST/IP] - * (EXAMPLE: "sbase get chromedriver latest") * - - Type "sbase help [COMMAND]" for specific command info. - For info on all commands, type: "seleniumbase --help". - Use "pytest" for running tests. + ___ _ _ ___ +/ __| ___| |___ _ _ (_)_ _ _ __ | _ ) __ _ ______ +\__ \/ -_) / -_) ' \| | \| | ' \ | _ \/ _` (_-< -_) +|___/\___|_\___|_||_|_|\_,_|_|_|_\|___/\__,_/__|___| +---------------------------------------------------- + +ā•­ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā•® +ā”‚ * USAGE: "seleniumbase [COMMAND] [PARAMETERS]" ā”‚ +ā”‚ * OR: "sbase [COMMAND] [PARAMETERS]" ā”‚ +ā”‚ ā”‚ +ā”‚ COMMANDS: PARAMETERS / DESCRIPTIONS: ā”‚ +ā”‚ get / install [DRIVER_NAME] [OPTIONS] ā”‚ +ā”‚ methods (List common Python methods) ā”‚ +ā”‚ options (List common pytest options) ā”‚ +ā”‚ behave-options (List common behave options) ā”‚ +ā”‚ gui / commander [OPTIONAL PATH or TEST FILE] ā”‚ +ā”‚ behave-gui (SBase Commander for Behave) ā”‚ +ā”‚ caseplans [OPTIONAL PATH or TEST FILE] ā”‚ +ā”‚ mkdir [DIRECTORY] [OPTIONS] ā”‚ +ā”‚ mkfile [FILE.py] [OPTIONS] ā”‚ +ā”‚ mkrec / codegen [FILE.py] [OPTIONS] ā”‚ +ā”‚ recorder (Open Recorder Desktop App.) ā”‚ +ā”‚ record (If args: mkrec. Else: App.) ā”‚ +ā”‚ mkpres [FILE.py] [LANG] ā”‚ +ā”‚ mkchart [FILE.py] [LANG] ā”‚ +ā”‚ print [FILE] [OPTIONS] ā”‚ +ā”‚ translate [SB_FILE.py] [LANG] [ACTION] ā”‚ +ā”‚ convert [WEBDRIVER_UNITTEST_FILE.py] ā”‚ +ā”‚ extract-objects [SB_FILE.py] ā”‚ +ā”‚ inject-objects [SB_FILE.py] [OPTIONS] ā”‚ +ā”‚ objectify [SB_FILE.py] [OPTIONS] ā”‚ +ā”‚ revert-objects [SB_FILE.py] [OPTIONS] ā”‚ +ā”‚ encrypt / obfuscate ā”‚ +ā”‚ decrypt / unobfuscate ā”‚ +ā”‚ proxy (Start a basic proxy server) ā”‚ +ā”‚ download server (Get Selenium Grid JAR file) ā”‚ +ā”‚ grid-hub [start|stop] [OPTIONS] ā”‚ +ā”‚ grid-node [start|stop] --hub=[HOST/IP] ā”‚ +ā”‚ ā”‚ +ā”‚ * EXAMPLE => "sbase get chromedriver stable" ā”‚ +ā”‚ * For command info => "sbase help [COMMAND]" ā”‚ +ā”‚ * For info on all commands => "sbase --help" ā”‚ +ā•°ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā•Æ ```

šŸ”µ Downloading webdrivers:

@@ -1375,7 +1378,6 @@ pytest --reruns=1 --reruns-delay=1 SeleniumBase on GitHub SeleniumBase on Discord SeleniumBase on Facebook -SeleniumBase on Gitter

https://github.com/mdmintz

diff --git a/examples/cdp_mode/raw_antibot.py b/examples/cdp_mode/raw_antibot.py new file mode 100644 index 00000000000..9239e862fa5 --- /dev/null +++ b/examples/cdp_mode/raw_antibot.py @@ -0,0 +1,16 @@ +from seleniumbase import SB + +with SB(uc=True, test=True) as sb: + url = "https://seleniumbase.io/antibot/login" + sb.activate_cdp_mode(url) + sb.press_keys("input#username", "demo_user") + sb.press_keys("input#password", "secret_pass") + x, y = sb.cdp.get_gui_element_center("button#myButton") + sb.uc_gui_click_x_y(x, y) + sb.sleep(1.5) + x, y = sb.cdp.get_gui_element_center("a#log-in") + sb.uc_gui_click_x_y(x, y) + sb.assert_text("Welcome!", "h1") + sb.set_messenger_theme(location="bottom_center") + sb.post_message("SeleniumBase wasn't detected!") + sb.sleep(1.5) diff --git a/examples/cdp_mode/raw_gitlab.py b/examples/cdp_mode/raw_gitlab.py new file mode 100644 index 00000000000..870c1f68d0d --- /dev/null +++ b/examples/cdp_mode/raw_gitlab.py @@ -0,0 +1,11 @@ +from seleniumbase import SB + +with SB(uc=True, test=True, locale_code="en") as sb: + url = "https://gitlab.com/users/sign_in" + sb.activate_cdp_mode(url) + sb.uc_gui_click_captcha() + sb.assert_text("Username", '[for="user_login"]', timeout=3) + sb.assert_element('label[for="user_login"]') + sb.highlight('button:contains("Sign in")') + sb.highlight('h1:contains("GitLab.com")') + sb.post_message("SeleniumBase wasn't detected", duration=4) diff --git a/requirements.txt b/requirements.txt index 286c50fd313..ffc8921fa55 100755 --- a/requirements.txt +++ b/requirements.txt @@ -21,8 +21,8 @@ colorama>=0.4.6 pyyaml>=6.0.2 pygments>=2.18.0 pyreadline3>=3.5.3;platform_system=="Windows" -tabcompleter>=1.3.3 -pdbp>=1.5.4 +tabcompleter>=1.4.0 +pdbp>=1.6.0 idna==3.10 chardet==5.2.0 charset-normalizer==3.4.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 24c8669f810..bec1f2f6776 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.32.3" +__version__ = "4.32.4" diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 3b1501a3715..74b2aebe1de 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -542,6 +542,7 @@ def uc_open_with_cdp_mode(driver, url=None): driver.cdp_base = loop.run_until_complete( cdp_util.start(host=cdp_host, port=cdp_port) ) + page = loop.run_until_complete(driver.cdp_base.get(url)) loop.run_until_complete(page.activate()) if not safe_url: diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 90399539e03..c439a7e8891 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -4167,13 +4167,13 @@ def get_new_driver( device_pixel_ratio=d_p_r, browser=browser_name, ) - time.sleep(0.2) + time.sleep(0.16) except Exception: pass finally: with suppress(Exception): decoy_driver.quit() - time.sleep(0.1) + time.sleep(0.08) # Launch a web browser new_driver = browser_launcher.get_driver( browser_name=browser_name, diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py index 3f0e8e83e41..00de9de3d05 100644 --- a/seleniumbase/plugins/driver_manager.py +++ b/seleniumbase/plugins/driver_manager.py @@ -870,13 +870,13 @@ def Driver( device_pixel_ratio=d_p_r, browser=browser_name, ) - time.sleep(0.2) + time.sleep(0.16) except Exception: pass finally: with suppress(Exception): decoy_driver.quit() - time.sleep(0.1) + time.sleep(0.08) driver = browser_launcher.get_driver( browser_name=browser_name, diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py index ecbdaa006b6..cbd04f0ec9f 100644 --- a/seleniumbase/undetected/__init__.py +++ b/seleniumbase/undetected/__init__.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import logging import os import re @@ -433,10 +432,15 @@ def reconnect(self, timeout=0.1): time.sleep(timeout) with suppress(Exception): self.service.start() - time.sleep(0.012) with suppress(Exception): self.start_session() - time.sleep(0.012) + with suppress(Exception): + if self.current_url.startswith("chrome-extension://"): + self.close() + self.service.stop() + self.service.start() + self.start_session() + self._is_connected = True def disconnect(self): """Stops the chromedriver service that runs in the background. @@ -445,7 +449,6 @@ def disconnect(self): with suppress(Exception): self.service.stop() self._is_connected = False - time.sleep(0.012) def connect(self): """Starts the chromedriver service that runs in the background @@ -453,11 +456,15 @@ def connect(self): if hasattr(self, "service"): with suppress(Exception): self.service.start() - time.sleep(0.012) with suppress(Exception): self.start_session() + with suppress(Exception): + if self.current_url.startswith("chrome-extension://"): + self.close() + self.service.stop() + self.service.start() + self.start_session() self._is_connected = True - time.sleep(0.012) def start_session(self, capabilities=None): if not capabilities: diff --git a/seleniumbase/undetected/cdp.py b/seleniumbase/undetected/cdp.py index db8897d7640..38bbe2862cd 100644 --- a/seleniumbase/undetected/cdp.py +++ b/seleniumbase/undetected/cdp.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import fasteners import json import logging diff --git a/seleniumbase/undetected/cdp_driver/config.py b/seleniumbase/undetected/cdp_driver/config.py index b5641eb8e3e..d3f128b4ab5 100644 --- a/seleniumbase/undetected/cdp_driver/config.py +++ b/seleniumbase/undetected/cdp_driver/config.py @@ -5,6 +5,7 @@ import sys import tempfile import zipfile +from seleniumbase.config import settings from typing import Union, List, Optional __all__ = [ @@ -101,7 +102,13 @@ def __init__( # Other keyword args will be accessible by attribute self.__dict__.update(kwargs) super().__init__() + start_width = settings.CHROME_START_WIDTH + start_height = settings.CHROME_START_HEIGHT + start_x = settings.WINDOW_START_X + start_y = settings.WINDOW_START_Y self._default_browser_args = [ + "--window-size=%s,%s" % (start_width, start_height), + "--window-position=%s,%s" % (start_x, start_y), "--remote-allow-origins=*", "--no-first-run", "--no-service-autorun", diff --git a/seleniumbase/undetected/cdp_driver/connection.py b/seleniumbase/undetected/cdp_driver/connection.py index 4ecfbe5624d..7eba23cb534 100644 --- a/seleniumbase/undetected/cdp_driver/connection.py +++ b/seleniumbase/undetected/cdp_driver/connection.py @@ -292,7 +292,14 @@ async def aclose(self): if self.listener and self.listener.running: self.listener.cancel() self.enabled_domains.clear() - await self.websocket.close() + await asyncio.sleep(0.015) + try: + await self.websocket.close() + except Exception: + logger.debug( + "\nāŒ Error closing websocket connection to %s", + self.websocket_url + ) logger.debug( "\nāŒ Closed websocket connection to %s", self.websocket_url ) @@ -540,6 +547,7 @@ async def listener_loop(self): self.idle.set() # Pause for a moment. # await asyncio.sleep(self.time_before_considered_idle / 10) + await asyncio.sleep(0.015) continue except (Exception,) as e: logger.debug( diff --git a/seleniumbase/undetected/dprocess.py b/seleniumbase/undetected/dprocess.py index dc6009b8962..07d90d6ce17 100644 --- a/seleniumbase/undetected/dprocess.py +++ b/seleniumbase/undetected/dprocess.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import os import sys import atexit diff --git a/seleniumbase/undetected/options.py b/seleniumbase/undetected/options.py index 2f83cec71f3..eefff9b4444 100644 --- a/seleniumbase/undetected/options.py +++ b/seleniumbase/undetected/options.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import json import os from contextlib import suppress @@ -59,7 +58,9 @@ def handle_prefs(self, user_data_dir): json.load(f), undot_prefs ) with suppress(Exception): - with open(prefs_file, encoding="utf-8", mode="w") as f: + with open( + prefs_file, encoding="utf-8", mode="w", errors="ignore" + ) as f: json.dump(undot_prefs, f) # Remove experimental_options to avoid errors del self._experimental_options["prefs"] diff --git a/seleniumbase/undetected/patcher.py b/seleniumbase/undetected/patcher.py index 08c775cb089..b4191fdc993 100644 --- a/seleniumbase/undetected/patcher.py +++ b/seleniumbase/undetected/patcher.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import io import logging import os diff --git a/seleniumbase/undetected/reactor.py b/seleniumbase/undetected/reactor.py index f1f1549be69..5af0cb5d664 100644 --- a/seleniumbase/undetected/reactor.py +++ b/seleniumbase/undetected/reactor.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import asyncio import json import logging diff --git a/setup.py b/setup.py index 5f7f3c7dcfd..165e32079a9 100755 --- a/setup.py +++ b/setup.py @@ -170,8 +170,8 @@ 'pyyaml>=6.0.2', 'pygments>=2.18.0', 'pyreadline3>=3.5.3;platform_system=="Windows"', - "tabcompleter>=1.3.3", - "pdbp>=1.5.4", + "tabcompleter>=1.4.0", + "pdbp>=1.6.0", "idna==3.10", 'chardet==5.2.0', 'charset-normalizer==3.4.0',