From ae9df3ea9f6340474e8aacf2e7b952342ec53088 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 20 Jul 2026 14:49:48 -0400 Subject: [PATCH 1/4] Update CDP Mode --- seleniumbase/core/browser_launcher.py | 8 ++------ seleniumbase/core/sb_cdp.py | 9 +++------ seleniumbase/undetected/cdp_driver/config.py | 2 +- seleniumbase/undetected/cdp_driver/element.py | 2 +- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index a9e8616fef2..648c1ff8404 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -2800,9 +2800,7 @@ def _set_chrome_options( included_disabled_features.append("SidePanelPinning") included_disabled_features.append("UserAgentClientHint") included_disabled_features.append("DisableLoadExtensionCommandLineSwitch") - included_disabled_features.append("Bluetooth") - included_disabled_features.append("WebBluetooth") - included_disabled_features.append("UnifiedWebBluetooth") + included_disabled_features.append("NetworkPrediction") included_disabled_features.append("WebAuthentication") included_disabled_features.append("PasskeyAuth") included_disabled_features.append("MediaRouter") @@ -4833,9 +4831,7 @@ def get_local_driver( included_disabled_features.append( "DisableLoadExtensionCommandLineSwitch" ) - included_disabled_features.append("Bluetooth") - included_disabled_features.append("WebBluetooth") - included_disabled_features.append("UnifiedWebBluetooth") + included_disabled_features.append("NetworkPrediction") included_disabled_features.append("WebAuthentication") included_disabled_features.append("PasskeyAuth") included_disabled_features.append("msAutofillEdgeCoupons") diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index f8c82f85e7b..077fddac9c9 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -876,8 +876,6 @@ def click(self, selector, timeout=None, scroll=True): self.__slow_mode_pause_if_set() element = self.find_element(selector, timeout=timeout) tag_name = element.tag_name - current_url = self.get_current_url() - if tag_name: tag_name = tag_name.lower().strip() if ( @@ -894,8 +892,6 @@ def click(self, selector, timeout=None, scroll=True): "svg", ] and "contains(" not in selector - and "://google" not in current_url - and "://www.google" not in current_url ): if scroll: element.scroll_into_view() @@ -909,9 +905,10 @@ def click(self, selector, timeout=None, scroll=True): element.scroll_into_view() else: try: - self.js_scroll_into_view(selector) - except Exception: element.scroll_into_view() + except Exception: + with suppress(Exception): + self.js_scroll_into_view(selector) element.click() # Standard CDP click self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait(0.2)) diff --git a/seleniumbase/undetected/cdp_driver/config.py b/seleniumbase/undetected/cdp_driver/config.py index a5e28702fd4..80c7d8894f0 100644 --- a/seleniumbase/undetected/cdp_driver/config.py +++ b/seleniumbase/undetected/cdp_driver/config.py @@ -324,7 +324,7 @@ def __call__(self): "OptimizationTargetPrediction,OptimizationGuideModelDownloading," "SidePanelPinning,UserAgentClientHint,PrivacySandboxSettings4," "OptimizationHintsFetching,InterestFeedContentSuggestions," - "Bluetooth,WebBluetooth,UnifiedWebBluetooth,ComponentUpdater," + "ComponentUpdater,NetworkPrediction," "DisableLoadExtensionCommandLineSwitch,WebAuthentication," "OmniboxUIFeedback,OmniboxPopupShortcut,PasskeyAuth," "MediaRouter,DialMediaRouteProvider,WebRtcHideLocalIpsWithMdns" diff --git a/seleniumbase/undetected/cdp_driver/element.py b/seleniumbase/undetected/cdp_driver/element.py index 2a748d615d7..3bd1b9b052c 100644 --- a/seleniumbase/undetected/cdp_driver/element.py +++ b/seleniumbase/undetected/cdp_driver/element.py @@ -389,7 +389,7 @@ async def click_async(self): object_id=self._remote_object.object_id, arguments=arguments, await_promise=True, - user_gesture=True, + user_gesture=False, return_by_value=True, ) ) From 6b6599ac6689c7efe4e5e784814c7d4151de0652 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 20 Jul 2026 14:57:34 -0400 Subject: [PATCH 2/4] Update CDP Mode examples --- .../playwright/raw_footlocker_sync.py | 4 +-- examples/cdp_mode/raw_cdp_clearcote.py | 4 +-- examples/cdp_mode/raw_cdp_target.py | 10 +++++--- examples/cdp_mode/raw_footlocker.py | 4 +-- examples/cdp_mode/raw_priceline.py | 25 ++++++++++--------- examples/cdp_mode/raw_science.py | 2 +- examples/cdp_mode/raw_target.py | 10 +++++--- examples/raw_invisible_captcha.py | 2 +- 8 files changed, 35 insertions(+), 26 deletions(-) diff --git a/examples/cdp_mode/playwright/raw_footlocker_sync.py b/examples/cdp_mode/playwright/raw_footlocker_sync.py index af4b9a2e4e9..28e35dd6797 100644 --- a/examples/cdp_mode/playwright/raw_footlocker_sync.py +++ b/examples/cdp_mode/playwright/raw_footlocker_sync.py @@ -12,9 +12,9 @@ page.wait_for_selector(input_field) sb.sleep(1.5) sb.click_if_visible('button[id*="Agree"]') - sb.sleep(1.2) + sb.sleep(0.6) page.click(input_field) - sb.sleep(0.5) + sb.sleep(0.6) search = "Nike Shoes" page.type(input_field, search) sb.sleep(1.2) diff --git a/examples/cdp_mode/raw_cdp_clearcote.py b/examples/cdp_mode/raw_cdp_clearcote.py index 717e2007de4..9ab1868edd4 100644 --- a/examples/cdp_mode/raw_cdp_clearcote.py +++ b/examples/cdp_mode/raw_cdp_clearcote.py @@ -3,8 +3,8 @@ sb = sb_cdp.Chrome() sb.goto("https://www.clearcotelabs.com/audit") sb.click('button:contains("Run the audit")') -sb.sleep(5) -sb.assert_element("div.text-emerald-700", timeout=6) +sb.sleep(6) +sb.assert_element("div.text-emerald-700", timeout=8) try: sb.assert_text("100", "div.text-emerald-700", timeout=5) sb.highlight('div.text-emerald-700:contains("100")') diff --git a/examples/cdp_mode/raw_cdp_target.py b/examples/cdp_mode/raw_cdp_target.py index 7380b639a04..8e49149ebc9 100644 --- a/examples/cdp_mode/raw_cdp_target.py +++ b/examples/cdp_mode/raw_cdp_target.py @@ -14,14 +14,18 @@ print('*** Target Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] -items = sb.find_elements('[data-test="product-details"]') +items = sb.find_elements( + '[data-test*="ProductListing"], [data-test="product-details"]' +) for item in items: if required_text.lower() in item.text.lower(): - description = item.query_selector('a[data-test*="Card/title"]') + description = item.query_selector('h3, a[data-test*="Card/title"]') if description and description.text not in unique_item_text: unique_item_text.append(description.text) print("* " + description.text) - price = item.query_selector('[data-test="current-price"]') + price = item.query_selector( + '[style*="weight: 700;"], [data-test="current-price"]' + ) if price: print(" (" + price.text + ")") item.scroll_into_view() diff --git a/examples/cdp_mode/raw_footlocker.py b/examples/cdp_mode/raw_footlocker.py index 46ae030e3b9..8601fbe2c1f 100644 --- a/examples/cdp_mode/raw_footlocker.py +++ b/examples/cdp_mode/raw_footlocker.py @@ -5,9 +5,9 @@ sb.goto("https://www.footlocker.com/") sb.sleep(2.5) sb.click_if_visible('button[id*="Agree"]') - sb.sleep(1.5) + sb.sleep(0.6) sb.click('input[name="query"]') - sb.sleep(1.5) + sb.sleep(0.6) search = "Nike Shoes" sb.press_keys('input[name="query"]', search) sb.sleep(2.5) diff --git a/examples/cdp_mode/raw_priceline.py b/examples/cdp_mode/raw_priceline.py index a7edf9b10f6..f4489be22b5 100644 --- a/examples/cdp_mode/raw_priceline.py +++ b/examples/cdp_mode/raw_priceline.py @@ -35,18 +35,19 @@ sb.switch_to_newest_tab() sb.sleep(0.6) sb.sleep(0.8) - for y in range(1, 9): - sb.scroll_to_y(y * 200) - sb.sleep(0.4) - hotels = sb.find_elements('div[data-vis-key*="content"]') + titles = [] count = 0 - for hotel in hotels: - title = hotel.query_selector("h3") - if title: - price = hotel.query_selector(".text-heading4") - if price: - count += 1 - price_text = price.text.replace(" ", "") - print("* %s: %s => %s" % (count, title.text, price_text)) + for y in range(1, 10): + sb.scroll_to_y(y * 500) + hotels = sb.find_elements('div[data-vis-key*="content"]') + for hotel in hotels: + title = hotel.query_selector("h3") + if title and title not in titles: + titles.append(title) + price = hotel.query_selector(".text-heading4") + if price: + count += 1 + price_text = price.text.replace(" ", "") + print("* %s: %s => %s" % (count, title.text, price_text)) if not count: print("No availability over the selected dates!") diff --git a/examples/cdp_mode/raw_science.py b/examples/cdp_mode/raw_science.py index ff59c9769e4..9bcfcf110b2 100644 --- a/examples/cdp_mode/raw_science.py +++ b/examples/cdp_mode/raw_science.py @@ -4,7 +4,7 @@ sb.activate_cdp_mode() sb.goto("https://earth.esa.int/eogateway/search") sb.sleep(1) - sb.click_if_visible('button:contains("Accept cookies")') + sb.click_if_visible('button:contains("Accept cookies")', timeout=3) for i in range(20): sb.scroll_to_bottom() sb.click_if_visible('button:contains("READ MORE")') diff --git a/examples/cdp_mode/raw_target.py b/examples/cdp_mode/raw_target.py index 946ee2c783c..403c12a111c 100644 --- a/examples/cdp_mode/raw_target.py +++ b/examples/cdp_mode/raw_target.py @@ -15,14 +15,18 @@ print('*** Target Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] - items = sb.find_elements('[data-test="product-details"]') + items = sb.find_elements( + '[data-test*="ProductListing"], [data-test="product-details"]' + ) for item in items: if required_text.lower() in item.text.lower(): - description = item.query_selector('a[data-test*="Card/title"]') + description = item.query_selector('h3, a[data-test*="Card/title"]') if description and description.text not in unique_item_text: unique_item_text.append(description.text) print("* " + description.text) - price = item.query_selector('[data-test="current-price"]') + price = item.query_selector( + '[style*="weight: 700;"], [data-test="current-price"]' + ) if price: print(" (" + price.text + ")") item.scroll_into_view() diff --git a/examples/raw_invisible_captcha.py b/examples/raw_invisible_captcha.py index 276b04f0675..182afa88d21 100644 --- a/examples/raw_invisible_captcha.py +++ b/examples/raw_invisible_captcha.py @@ -1,6 +1,6 @@ from seleniumbase import SB -with SB(uc=True, test=True, guest=True) as sb: +with SB(uc=True, test=True) as sb: sb.activate_cdp_mode() sb.goto("https://seleniumbase.io/apps/invisible_recaptcha") sb.sleep(1) From a8b84ff9f8051a52ae72e81dfb6aab3d62458459 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 20 Jul 2026 14:58:06 -0400 Subject: [PATCH 3/4] Refresh Python dependencies --- mkdocs_build/requirements.txt | 4 ++-- requirements.txt | 5 +++-- setup.py | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index cc95a93ad99..63063704d43 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -1,9 +1,9 @@ # mkdocs dependencies for generating the seleniumbase.io website # Minimum Python version: 3.10 (for generating docs only) -regex>=2026.7.10 +regex>=2026.7.19 pymdown-extensions>=10.21.3 -pipdeptree>=3.1.1 +pipdeptree>=4.0.0 python-dateutil>=2.8.2 click>=8.4.2 Markdown==3.10.2 diff --git a/requirements.txt b/requirements.txt index f8cdba1d076..9ee92aa1526 100755 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ exceptiongroup>=1.3.1 websockets~=15.0.1;python_version<"3.10" websockets>=16.1.1;python_version>="3.10" filelock~=3.19.1;python_version<"3.10" -filelock>=3.31.0;python_version>="3.10" +filelock>=3.31.1;python_version>="3.10" fasteners>=0.20 mycdp>=1.4.0 pynose>=1.5.5 @@ -66,7 +66,8 @@ pytest-rerunfailures==16.4;python_version>="3.11" pytest-xdist==3.8.0 parameterized==0.9.0 behave==1.2.6 -soupsieve~=2.8.4 +soupsieve~=2.8.4;python_version<"3.10" +soupsieve~=2.9.0;python_version>="3.10" beautifulsoup4~=4.15.0 pyotp~=2.10.0 python-xlib==0.33;platform_system=="Linux" diff --git a/setup.py b/setup.py index a0e8e27c040..bbd962cd41e 100755 --- a/setup.py +++ b/setup.py @@ -174,7 +174,7 @@ 'websockets~=15.0.1;python_version<"3.10"', 'websockets>=16.1.1;python_version>="3.10"', 'filelock~=3.19.1;python_version<"3.10"', - 'filelock>=3.31.0;python_version>="3.10"', + 'filelock>=3.31.1;python_version>="3.10"', 'fasteners>=0.20', 'mycdp>=1.4.0', 'pynose>=1.5.5', @@ -230,7 +230,8 @@ 'pytest-xdist==3.8.0', 'parameterized==0.9.0', 'behave==1.2.6', # Newer ones had issues - 'soupsieve~=2.8.4', + 'soupsieve~=2.8.4;python_version<"3.10"', + 'soupsieve~=2.9.0;python_version>="3.10"', 'beautifulsoup4~=4.15.0', 'pyotp~=2.10.0', 'python-xlib==0.33;platform_system=="Linux"', From 8bca2b0b64717330d1b9a84e1f0d974f6f441e5b Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 20 Jul 2026 14:58:31 -0400 Subject: [PATCH 4/4] Version 4.51.4 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 7a4a75400a3..3f2547aee94 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.51.3" +__version__ = "4.51.4"