diff --git a/README.md b/README.md index 8bd290efeee..604050a08bf 100755 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

Automate, test, and scrape the web — on your own terms.

PyPI version GitHub version SeleniumBase Docs

-

SeleniumBase GitHub Actions

+

SeleniumBase GitHub Actions SeleniumBase PyPI downloads

🚀 Start | @@ -54,7 +54,7 @@

-

SeleniumBase is a browser automation framework for the modern web. Whether you're new or experienced in Python, SeleniumBase makes it easy to get started. With special features like Stealth Mode (UC Mode / CDP Mode), you'll be evading bot-detection and bypassing CAPTCHAs in minutes.

+

SeleniumBase is a browser automation framework for the modern web. Both new and experienced Python users alike can easily get started. With special stealth features like UC Mode and CDP Mode, you'll be evading bot-detection and bypassing CAPTCHAs in minutes.

-------- diff --git a/requirements.txt b/requirements.txt index 3ba928a114e..80a446ecd49 100755 --- a/requirements.txt +++ b/requirements.txt @@ -52,7 +52,7 @@ websocket-client~=1.8.0;python_version<"3.9" websocket-client~=1.9.0;python_version>="3.9" selenium==4.27.1;python_version<"3.9" selenium==4.32.0;python_version>="3.9" and python_version<"3.10" -selenium==4.36.0;python_version>="3.10" +selenium==4.37.0;python_version>="3.10" cssselect==1.2.0;python_version<"3.9" cssselect==1.3.0;python_version>="3.9" sortedcontainers==2.4.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 2984fa9fe87..ae8ed88c79c 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.42.6" +__version__ = "4.43.0" diff --git a/seleniumbase/console_scripts/sb_mkdir.py b/seleniumbase/console_scripts/sb_mkdir.py index 84620456495..83fc045dc0f 100644 --- a/seleniumbase/console_scripts/sb_mkdir.py +++ b/seleniumbase/console_scripts/sb_mkdir.py @@ -636,17 +636,12 @@ def main(): data.append("") data.append("class GoogleTests(BaseCase):") data.append(" def test_google_dot_com(self):") + data.append(" if self.headless:") + data.append(' self.skip("Skipping test in headless mode.")') data.append(" if not self.undetectable:") data.append(" self.get_new_driver(undetectable=True)") data.append(' self.open("https://google.com/ncr")') data.append(' self.assert_title_contains("Google")') - data.append(" self.sleep(0.05)") - data.append(" self.save_screenshot_to_logs()") - data.append( - " self.wait_for_element('iframe[role=\"presentation\"]')" - ) - data.append(" self.hide_elements('iframe')") - data.append(" self.sleep(0.05)") data.append(" self.save_screenshot_to_logs()") data.append(' self.type(HomePage.search_box, "github.com")') data.append(" self.assert_element(HomePage.search_button)") diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 835c82fba66..80755b5b5c8 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -187,46 +187,23 @@ def find_element_by_text(self, text, tag_name=None, timeout=None): element with the given tag. (Eg: a, button, div, script, span)""" if not timeout: timeout = settings.SMALL_TIMEOUT - self.__add_light_pause() - time_now = time.time() - self.assert_text(text, timeout=timeout) - spent = int(time.time() - time_now) - remaining = 1 + timeout - spent - if tag_name: - self.assert_element(tag_name, timeout=remaining) - elements = self.loop.run_until_complete( - self.page.find_elements_by_text(text=text) - ) if tag_name: - tag_name = tag_name.lower().strip() - for element in elements: - if element and not tag_name: - element = self.__add_sync_methods(element) - return self.__add_sync_methods(element) - elif ( - element - and tag_name in element.tag_name.lower() - and text.strip() in element.text - ): - element = self.__add_sync_methods(element) - return self.__add_sync_methods(element) - elif ( - element - and element.parent - and tag_name in element.parent.tag_name.lower() - and text.strip() in element.parent.text - ): - element = self.__add_sync_methods(element.parent) - return self.__add_sync_methods(element) - elif ( - element - and element.parent - and element.parent.parent - and tag_name in element.parent.parent.tag_name.lower() - and text.strip() in element.parent.parent.text - ): - element = self.__add_sync_methods(element.parent.parent) - return self.__add_sync_methods(element) + try: + return self.find_element( + '%s:contains("%s")' % (tag_name, text), timeout=timeout + ) + except Exception: + pass # The exception will be raised later + else: + self.__add_light_pause() + self.assert_text(text, timeout=timeout) + elements = self.loop.run_until_complete( + self.page.find_elements_by_text(text=text) + ) + for element in elements: + if element: + element = self.__add_sync_methods(element) + return self.__add_sync_methods(element) plural = "s" if timeout == 1: plural = "" diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index f8017249cf7..a75ee6e0a01 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -10173,7 +10173,7 @@ def wait_for_text_visible( text = self.__get_type_checked_text(text) selector, by = self.__recalculate_selector(selector, by) if self.__is_cdp_swap_needed(): - return self.cdp.find_element(selector, timeout=timeout) + return self.cdp.wait_for_text(text, selector, timeout=timeout) elif self.__is_shadow_selector(selector): return self.__wait_for_shadow_text_visible(text, selector, timeout) return page_actions.wait_for_text_visible( @@ -10530,6 +10530,8 @@ def wait_for_link_text_visible(self, link_text, timeout=None): timeout = settings.LARGE_TIMEOUT if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT: timeout = self.__get_new_timeout(timeout) + if self.__is_cdp_swap_needed(): + return self.cdp.find_element_by_text(text=link_text, tag_name="a") return self.wait_for_element_visible( link_text, by="link text", timeout=timeout ) diff --git a/seleniumbase/undetected/cdp_driver/browser.py b/seleniumbase/undetected/cdp_driver/browser.py index f048087f920..7623df7ff7e 100644 --- a/seleniumbase/undetected/cdp_driver/browser.py +++ b/seleniumbase/undetected/cdp_driver/browser.py @@ -369,7 +369,8 @@ async def get( proxy_user = username_and_password.split(":")[0] proxy_pass = username_and_password.split(":")[1] await connection.set_auth(proxy_user, proxy_pass, self.tabs[0]) - time.sleep(0.25) + time.sleep(0.22) + await connection.sleep(0.05) frame_id, loader_id, *_ = await connection.send( cdp.page.navigate(url) ) diff --git a/setup.py b/setup.py index f19d8a62b76..5bafac5dfdc 100755 --- a/setup.py +++ b/setup.py @@ -199,7 +199,7 @@ 'websocket-client~=1.9.0;python_version>="3.9"', 'selenium==4.27.1;python_version<"3.9"', 'selenium==4.32.0;python_version>="3.9" and python_version<"3.10"', - 'selenium==4.36.0;python_version>="3.10"', + 'selenium==4.37.0;python_version>="3.10"', 'cssselect==1.2.0;python_version<"3.9"', 'cssselect==1.3.0;python_version>="3.9"', "sortedcontainers==2.4.0", @@ -277,7 +277,7 @@ 'pdfminer.six==20250324;python_version<"3.9"', 'pdfminer.six==20250506;python_version>="3.9"', 'cryptography==39.0.2;python_version<"3.9"', - 'cryptography==46.0.2;python_version>="3.9"', + 'cryptography==46.0.3;python_version>="3.9"', 'cffi==1.17.1;python_version<"3.9"', 'cffi==2.0.0;python_version>="3.9"', 'pycparser==2.22;python_version<"3.9"',