diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index ed0283f5c4e..c130db5a434 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -139,7 +139,7 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.pokemon.com/us" sb.activate_cdp_mode(url) sb.sleep(3.2) - sb.click("button#onetrust-accept-btn-handler") + sb.click_if_visible("button#onetrust-accept-btn-handler") sb.sleep(1.2) sb.click("a span.icon_pokeball") sb.sleep(2.5) @@ -188,10 +188,10 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb: ```python from seleniumbase import SB -with SB(uc=True, test=True, locale="en", ad_block=True) as sb: +with SB(uc=True, test=True, locale="en") as sb: url = "https://www.hyatt.com/" sb.activate_cdp_mode(url) - sb.sleep(3.5) + sb.sleep(3.8) sb.click_if_visible('button[aria-label="Close"]') sb.sleep(0.1) sb.click_if_visible("#onetrust-reject-all-handler") diff --git a/examples/cdp_mode/raw_cdp_copilot.py b/examples/cdp_mode/raw_cdp_copilot.py index ee81450eaf4..df2740dc468 100644 --- a/examples/cdp_mode/raw_cdp_copilot.py +++ b/examples/cdp_mode/raw_cdp_copilot.py @@ -9,11 +9,20 @@ sb.sleep(0.5) sb.click('button[data-testid*="chat-mode-"]') sb.sleep(1.1) -sb.click('button[title="Think Deeper"]') +sb.click_if_visible('button[title="Think Deeper"]') sb.sleep(1.1) query = "How to start automating with SeleniumBase?" sb.press_keys(textarea, query) sb.sleep(1.1) +seen_text = sb.get_text(textarea) +if seen_text != query and seen_text in query: + # When CAPTCHA appears while typing text + sb.sleep(1.1) + sb.solve_captcha() + sb.sleep(2.2) + sb.type(textarea, "") + sb.press_keys(textarea, query) + sb.sleep(0.5) sb.click('button[data-testid="submit-button"]') sb.sleep(2.5) sb.solve_captcha() diff --git a/examples/cdp_mode/raw_cf_clearance.py b/examples/cdp_mode/raw_cf_clearance.py index 4d9952ef664..9c1f2a31b2e 100644 --- a/examples/cdp_mode/raw_cf_clearance.py +++ b/examples/cdp_mode/raw_cf_clearance.py @@ -10,8 +10,8 @@ def get_cf_clearance_cookie(sb): url = "https://gitlab.com/users/sign_in" -sb = sb_cdp.Chrome(url, incognito=True) -sb.sleep(2.2) # Wait for CAPTCHA to load +sb = sb_cdp.Chrome(url) +sb.sleep(2.5) # Wait for CAPTCHA to load sb.solve_captcha() # (Only if found) sb.sleep(2.2) # Wait for CAPTCHA success cf_cookie = get_cf_clearance_cookie(sb) diff --git a/examples/cdp_mode/raw_copilot.py b/examples/cdp_mode/raw_copilot.py index 9b722a54c1c..90236c419cd 100644 --- a/examples/cdp_mode/raw_copilot.py +++ b/examples/cdp_mode/raw_copilot.py @@ -10,11 +10,20 @@ sb.sleep(0.5) sb.click('button[data-testid*="chat-mode-"]') sb.sleep(1.1) - sb.click('button[title="Think Deeper"]') + sb.click_if_visible('button[title="Think Deeper"]') sb.sleep(1.1) query = "How to start automating with SeleniumBase?" sb.press_keys(textarea, query) sb.sleep(1.1) + seen_text = sb.get_text(textarea) + if seen_text != query and seen_text in query: + # When CAPTCHA appears while typing text + sb.sleep(1.1) + sb.solve_captcha() + sb.sleep(2.2) + sb.type(textarea, "") + sb.press_keys(textarea, query) + sb.sleep(0.5) sb.click('button[data-testid="submit-button"]') sb.sleep(2.5) sb.solve_captcha() diff --git a/examples/cdp_mode/raw_hyatt.py b/examples/cdp_mode/raw_hyatt.py index 9311f12bd05..eca5cdfd970 100644 --- a/examples/cdp_mode/raw_hyatt.py +++ b/examples/cdp_mode/raw_hyatt.py @@ -1,9 +1,9 @@ from seleniumbase import SB -with SB(uc=True, test=True, locale="en", ad_block=True) as sb: +with SB(uc=True, test=True, locale="en") as sb: url = "https://www.hyatt.com/" sb.activate_cdp_mode(url) - sb.sleep(3.5) + sb.sleep(3.8) sb.click_if_visible('button[aria-label="Close"]') sb.sleep(0.1) sb.click_if_visible("#onetrust-reject-all-handler") diff --git a/examples/cdp_mode/raw_pokemon.py b/examples/cdp_mode/raw_pokemon.py index 87762cc40e1..8e8d820e531 100644 --- a/examples/cdp_mode/raw_pokemon.py +++ b/examples/cdp_mode/raw_pokemon.py @@ -4,7 +4,7 @@ url = "https://www.pokemon.com/us" sb.activate_cdp_mode(url) sb.sleep(3.2) - sb.click("button#onetrust-accept-btn-handler") + sb.click_if_visible("button#onetrust-accept-btn-handler") sb.sleep(1.2) sb.click("a span.icon_pokeball") sb.sleep(2.5) diff --git a/examples/cdp_mode/raw_timezone_sb.py b/examples/cdp_mode/raw_timezone_sb.py index b6abb116f8a..72120e33d7d 100644 --- a/examples/cdp_mode/raw_timezone_sb.py +++ b/examples/cdp_mode/raw_timezone_sb.py @@ -1,7 +1,7 @@ """An example of changing settings during CDP Mode""" from seleniumbase import SB -with SB(uc=True, test=True, pls="eager") as sb: +with SB(uc=True, test=True, pls="eager", ad_block=True) as sb: url = "https://www.randymajors.org/what-time-zone-am-i-in" sb.activate_cdp_mode(url, tzone="Asia/Kolkata", geoloc=(26.863, 80.94)) sb.remove_elements("#right-sidebar") diff --git a/examples/cdp_mode/raw_united.py b/examples/cdp_mode/raw_united.py index 6a371ac7e50..6bafa641e79 100644 --- a/examples/cdp_mode/raw_united.py +++ b/examples/cdp_mode/raw_united.py @@ -3,25 +3,29 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.united.com/en/us" sb.activate_cdp_mode(url) - sb.sleep(2.5) + sb.sleep(2.6) origin_input = 'input[placeholder="Origin"]' origin = "New York, NY" destination_input = 'input[placeholder="Destination"]' destination = "Orlando, FL" - sb.cdp.gui_click_element(origin_input) + sb.click(origin_input) sb.sleep(0.5) sb.type(origin_input, origin) sb.sleep(1.2) sb.click('strong:contains("%s")' % origin) - sb.sleep(1.2) - sb.cdp.gui_click_element(destination_input) + sb.sleep(0.6) + sb.click_if_visible('button[class*="__close--"]') + sb.sleep(0.6) + sb.click(destination_input) sb.sleep(0.5) sb.type(destination_input, destination) sb.sleep(1.2) sb.click('strong:contains("%s")' % destination) sb.sleep(1.2) sb.click('button[aria-label="Find flights"]') - sb.sleep(6) + sb.sleep(4) + sb.click_if_visible('button[class*="__close--"]') + sb.sleep(2) flights = sb.find_elements('div[class*="CardContainer__block"]') print("**** Flights from %s to %s ****" % (origin, destination)) print(" (" + sb.get_text("h2.atm-c-heading") + ")") diff --git a/requirements.txt b/requirements.txt index ad57101a899..60e08c2b1be 100755 --- a/requirements.txt +++ b/requirements.txt @@ -90,7 +90,7 @@ rich>=14.2.0,<15 coverage>=7.6.1;python_version<"3.9" coverage>=7.10.7;python_version>="3.9" and python_version<"3.10" -coverage>=7.11.0;python_version>="3.10" +coverage>=7.11.1;python_version>="3.10" pytest-cov>=5.0.0;python_version<"3.9" pytest-cov>=7.0.0;python_version>="3.9" flake8==5.0.4;python_version<"3.9" diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index f8502eb5fb7..dab771339fb 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.44.7" +__version__ = "4.44.8" diff --git a/seleniumbase/core/detect_b_ver.py b/seleniumbase/core/detect_b_ver.py index acc19ae6d51..129331fcee7 100644 --- a/seleniumbase/core/detect_b_ver.py +++ b/seleniumbase/core/detect_b_ver.py @@ -367,6 +367,7 @@ def comet_on_windows_path(browser_type=None): ), ): for subitem in ( + "Perplexity/Comet/Application" "Comet/Application", "Programs/Comet", ): @@ -396,6 +397,7 @@ def atlas_on_windows_path(browser_type=None): ), ): for subitem in ( + "OpenAI/Atlas/Application" "Atlas/Application", "Programs/Atlas", ): diff --git a/seleniumbase/undetected/cdp_driver/browser.py b/seleniumbase/undetected/cdp_driver/browser.py index 527aaa22213..12dbfd2a078 100644 --- a/seleniumbase/undetected/cdp_driver/browser.py +++ b/seleniumbase/undetected/cdp_driver/browser.py @@ -358,14 +358,24 @@ async def get( await connection.send(cdp.network.enable()) await connection.send(cdp.network.set_blocked_urls( urls=[ + "*cloudflareinsights.com*", "*googlesyndication.com*", "*googletagmanager.com*", "*google-analytics.com*", "*amazon-adsystem.com*", "*adsafeprotected.com*", + "*casalemedia.com*", "*doubleclick.net*", + "*admanmedia.com*", "*fastclick.net*", "*snigelweb.com*", + "*bidswitch.net*", + "*pubmatic.com*", + "*ad.turn.com*", + "*adnxs.com*", + "*openx.net*", + "*tapad.com*", + "*3lift.com*", "*2mdn.net*", ] )) diff --git a/seleniumbase/undetected/cdp_driver/element.py b/seleniumbase/undetected/cdp_driver/element.py index 94a6ab6513b..3da6ededcec 100644 --- a/seleniumbase/undetected/cdp_driver/element.py +++ b/seleniumbase/undetected/cdp_driver/element.py @@ -828,7 +828,7 @@ def text(self): """ with suppress(Exception): if self.node.node_name.lower() in ["input", "textarea"]: - input_node = self.node.shadow_roots[0].children[0].children[0] + input_node = self.node.shadow_roots[0].children[-1].children[0] if input_node: return input_node.node_value text_nodes = util.filter_recurse_all( @@ -841,7 +841,7 @@ def text_all(self): """Same as text(). Kept for backwards compatibility.""" with suppress(Exception): if self.node.node_name.lower() in ["input", "textarea"]: - input_node = self.node.shadow_roots[0].children[0].children[0] + input_node = self.node.shadow_roots[0].children[-1].children[0] if input_node: return input_node.node_value text_nodes = util.filter_recurse_all( diff --git a/seleniumbase/undetected/cdp_driver/tab.py b/seleniumbase/undetected/cdp_driver/tab.py index 235fbb7fe12..3bef17d6055 100644 --- a/seleniumbase/undetected/cdp_driver/tab.py +++ b/seleniumbase/undetected/cdp_driver/tab.py @@ -244,23 +244,7 @@ async def select( Raise timeout exception when after this many seconds nothing is found. :type timeout: float,int """ - loop = asyncio.get_running_loop() - start_time = loop.time() - selector = selector.strip() - item = None - try: - item = await self.query_selector(selector) - except (Exception, TypeError): - pass - while not item: - await self - item = await self.query_selector(selector) - if loop.time() - start_time > timeout: - raise asyncio.TimeoutError( - "Time ran out while waiting for: {%s}" % selector - ) - await self.sleep(0.5) - return item + return await self.wait_for(selector=selector, timeout=timeout) async def find_all( self, @@ -333,6 +317,33 @@ async def select_all( await self.sleep(0.5) return items + async def ad_block(self): + await self.send(cdp.page.navigate("about:blank")) + await self.send(cdp.network.enable()) + await self.send(cdp.network.set_blocked_urls( + urls=[ + "*cloudflareinsights.com*", + "*googlesyndication.com*", + "*googletagmanager.com*", + "*google-analytics.com*", + "*amazon-adsystem.com*", + "*adsafeprotected.com*", + "*casalemedia.com*", + "*doubleclick.net*", + "*admanmedia.com*", + "*fastclick.net*", + "*snigelweb.com*", + "*bidswitch.net*", + "*pubmatic.com*", + "*ad.turn.com*", + "*adnxs.com*", + "*openx.net*", + "*tapad.com*", + "*3lift.com*", + "*2mdn.net*", + ] + )) + async def get( self, url="about:blank", @@ -350,6 +361,9 @@ async def get( :param new_window: open new window :return: Page """ + _cdp_ad_block = None + if hasattr(sb_config, "ad_block_on") and sb_config.ad_block_on: + _cdp_ad_block = sb_config.ad_block_on if not self.browser: raise AttributeError( "This page/tab has no browser attribute, " @@ -357,6 +371,8 @@ async def get( ) if new_window and not new_tab: new_tab = True + if _cdp_ad_block: + await self.ad_block() if new_tab: if hasattr(sb_config, "incognito") and sb_config.incognito: return await self.browser.get( @@ -705,10 +721,12 @@ async def evaluate( raise ProtocolException(errors) if remote_object: if return_by_value: - if remote_object.value: + if remote_object.value is not None: return remote_object.value else: - return remote_object, errors + if remote_object.deep_serialized_value is not None: + return remote_object.deep_serialized_value.value + return None async def js_dumps( self, obj_name: str, return_by_value: Optional[bool] = True @@ -1368,7 +1386,9 @@ def __call__( :param selector: css selector string :type selector: str """ - return self.wait_for(text, selector, timeout) + return self.wait_for( + selector=selector, text=text, timeout=timeout + ) def __eq__(self, other: Tab): try: diff --git a/setup.py b/setup.py index 8d978b896ba..e1aafdded57 100755 --- a/setup.py +++ b/setup.py @@ -248,7 +248,7 @@ "coverage": [ 'coverage>=7.6.1;python_version<"3.9"', 'coverage>=7.10.7;python_version>="3.9" and python_version<"3.10"', - 'coverage>=7.11.0;python_version>="3.10"', + 'coverage>=7.11.1;python_version>="3.10"', 'pytest-cov>=5.0.0;python_version<"3.9"', 'pytest-cov>=7.0.0;python_version>="3.9"', ], @@ -279,7 +279,7 @@ # (An optional library for parsing PDF files.) "pdfminer": [ 'pdfminer.six==20250324;python_version<"3.9"', - 'pdfminer.six==20250506;python_version>="3.9"', + 'pdfminer.six==20251107;python_version>="3.9"', 'cryptography==39.0.2;python_version<"3.9"', 'cryptography==46.0.3;python_version>="3.9"', 'cffi==1.17.1;python_version<"3.9"',