diff --git a/README.md b/README.md index 3180e9f34bb..8c398897352 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@

SeleniumBase

-

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

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

@@ -54,7 +53,9 @@

-

SeleniumBase is the professional toolkit for web automation activities. Built for testing websites, bypassing CAPTCHAs, enhancing productivity, completing tasks, and scaling your business.

+

seleniumbase%2FSeleniumBase | Trendshift

+ +

SeleniumBase is the professional toolkit for web automation. Built for testing websites, bypassing CAPTCHAs, completing tasks, and scaling your business.

-------- @@ -81,7 +82,7 @@ with SB(test=True, uc=True) as sb: > `python raw_google.py` -SeleniumBase Test +SeleniumBase Test -------- @@ -1393,5 +1394,5 @@ pytest --reruns=1 --reruns-delay=1
SeleniumBase Docs
Tested with SeleniumBase
Featured|HelloGitHub Join the SeleniumBase chat on Discord Gitter chat
-
SeleniumBase PyPI downloads Views
+
SeleniumBase PyPI downloads Views
diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index ede98774998..fb339ee2a49 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -413,6 +413,7 @@ sb.cdp.send_keys(selector, text, timeout=None) sb.cdp.press_keys(selector, text, timeout=None) sb.cdp.type(selector, text, timeout=None) sb.cdp.set_value(selector, text, timeout=None) +sb.cdp.submit(selector) sb.cdp.evaluate(expression) sb.cdp.js_dumps(obj_name) sb.cdp.maximize() @@ -438,6 +439,8 @@ sb.cdp.get_page_source() sb.cdp.get_user_agent() sb.cdp.get_cookie_string() sb.cdp.get_locale_code() +sb.cdp.get_local_storage_item(key) +sb.cdp.get_session_storage_item(key) sb.cdp.get_screen_rect() sb.cdp.get_window_rect() sb.cdp.get_window_size() @@ -454,6 +457,8 @@ sb.cdp.get_element_attribute(selector, attribute) sb.cdp.get_attribute(selector, attribute) sb.cdp.get_element_html(selector) sb.cdp.set_locale(locale) +sb.cdp.set_local_storage_item(key, value) +sb.cdp.set_session_storage_item(key, value) sb.cdp.set_attributes(selector, attribute, value) sb.cdp.gui_press_key(key) sb.cdp.gui_press_keys(keys) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index 19dab0dc4cb..19c65c37eae 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -3,7 +3,7 @@ regex>=2024.11.6 pymdown-extensions>=10.14.3 -pipdeptree>=2.25.0 +pipdeptree>=2.25.1 python-dateutil>=2.8.2 Markdown==3.7 click==8.1.8 diff --git a/requirements.txt b/requirements.txt index f21539031cb..b9620764b01 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ pip>=25.0.1 packaging>=24.2 setuptools~=70.2;python_version<"3.10" -setuptools>=75.8.2;python_version>="3.10" +setuptools>=76.0.0;python_version>="3.10" wheel>=0.45.1 attrs>=25.1.0 certifi>=2025.1.31 @@ -11,7 +11,7 @@ websockets>=15.0.1;python_version>="3.9" filelock~=3.16.1;python_version<"3.9" filelock>=3.17.0;python_version>="3.9" fasteners>=0.19 -mycdp>=1.1.0 +mycdp>=1.1.1 pynose>=1.5.4 platformdirs>=4.3.6 typing-extensions>=4.12.2 @@ -44,7 +44,8 @@ wsproto==1.2.0 websocket-client==1.8.0 selenium==4.27.1;python_version<"3.9" selenium==4.29.0;python_version>="3.9" -cssselect==1.2.0 +cssselect==1.2.0;python_version<"3.9" +cssselect==1.3.0;python_version>="3.9" sortedcontainers==2.4.0 execnet==2.1.1 iniconfig==2.0.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 00256da934d..0c4da959fab 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.35.6" +__version__ = "4.35.7" diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 6341d61e0ac..5f8f8eaa73b 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -662,6 +662,7 @@ def uc_open_with_cdp_mode(driver, url=None): cdp.press_keys = CDPM.press_keys cdp.type = CDPM.type cdp.set_value = CDPM.set_value + cdp.submit = CDPM.submit cdp.evaluate = CDPM.evaluate cdp.js_dumps = CDPM.js_dumps cdp.maximize = CDPM.maximize @@ -670,6 +671,8 @@ def uc_open_with_cdp_mode(driver, url=None): cdp.set_window_rect = CDPM.set_window_rect cdp.reset_window_size = CDPM.reset_window_size cdp.set_locale = CDPM.set_locale + cdp.set_local_storage_item = CDPM.set_local_storage_item + cdp.set_session_storage_item = CDPM.set_session_storage_item cdp.set_attributes = CDPM.set_attributes cdp.gui_press_key = CDPM.gui_press_key cdp.gui_press_keys = CDPM.gui_press_keys @@ -705,6 +708,8 @@ def uc_open_with_cdp_mode(driver, url=None): cdp.get_user_agent = CDPM.get_user_agent cdp.get_cookie_string = CDPM.get_cookie_string cdp.get_locale_code = CDPM.get_locale_code + cdp.get_local_storage_item = CDPM.get_local_storage_item + cdp.get_session_storage_item = CDPM.get_session_storage_item cdp.get_text = CDPM.get_text cdp.get_title = CDPM.get_title cdp.get_page_title = CDPM.get_title diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 31bb25b1681..ed017b17a01 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -955,6 +955,20 @@ def set_value(self, selector, text, timeout=None): self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.sleep(0.025)) + def submit(self, selector): + submit_script = ( + """elm = document.querySelector('%s'); + const event = new KeyboardEvent("keydown", { + key: "Enter", + keyCode: 13, + code: "Enter", + which: 13, + bubbles: true + }); + elm.dispatchEvent(event);""" % selector + ) + self.loop.run_until_complete(self.page.evaluate(submit_script)) + def evaluate(self, expression): """Run a JavaScript expression and return the result.""" expression = expression.strip() @@ -1115,6 +1129,16 @@ def get_locale_code(self): self.page.evaluate("navigator.language || navigator.languages[0]") ) + def get_local_storage_item(self, key): + js_code = """localStorage.getItem('%s');""" % key + with suppress(Exception): + return self.loop.run_until_complete(self.page.evaluate(js_code)) + + def get_session_storage_item(self, key): + js_code = """sessionStorage.getItem('%s');""" % key + with suppress(Exception): + return self.loop.run_until_complete(self.page.evaluate(js_code)) + def get_screen_rect(self): coordinates = self.loop.run_until_complete( self.page.js_dumps("window.screen") @@ -1302,6 +1326,16 @@ def set_locale(self, locale): """(Settings will take effect on the next page load)""" self.loop.run_until_complete(self.page.set_locale(locale)) + def set_local_storage_item(self, key, value): + js_code = """localStorage.setItem('%s','%s');""" % (key, value) + with suppress(Exception): + self.loop.run_until_complete(self.page.evaluate(js_code)) + + def set_session_storage_item(self, key, value): + js_code = """sessionStorage.setItem('%s','%s');""" % (key, value) + with suppress(Exception): + self.loop.run_until_complete(self.page.evaluate(js_code)) + def set_attributes(self, selector, attribute, value): """This method uses JavaScript to set/update a common attribute. All matching selectors from querySelectorAll() are used. diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 488ad617ef4..dad222fd6d7 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -1164,6 +1164,9 @@ def submit(self, selector, by="css selector"): """Alternative to self.driver.find_element_by_*(SELECTOR).submit()""" self.__check_scope() selector, by = self.__recalculate_selector(selector, by) + if self.__is_cdp_swap_needed(): + self.cdp.submit(selector) + return element = self.wait_for_element_clickable( selector, by=by, timeout=settings.SMALL_TIMEOUT ) @@ -8800,6 +8803,9 @@ def set_local_storage_item(self, key, value): self.__check_scope() if not self.__is_valid_storage_url(): raise WebDriverException("Local Storage is not available here!") + if self.__is_cdp_swap_needed(): + self.cdp.set_local_storage_item(key, value) + return self.execute_script( "window.localStorage.setItem('{}', '{}');".format(key, value) ) @@ -8808,6 +8814,8 @@ def get_local_storage_item(self, key): self.__check_scope() if not self.__is_valid_storage_url(): raise WebDriverException("Local Storage is not available here!") + if self.__is_cdp_swap_needed(): + return self.cdp.get_local_storage_item(key) return self.execute_script( "return window.localStorage.getItem('{}');".format(key) ) @@ -8859,6 +8867,9 @@ def set_session_storage_item(self, key, value): self.__check_scope() if not self.__is_valid_storage_url(): raise WebDriverException("Session Storage is not available here!") + if self.__is_cdp_swap_needed(): + self.cdp.set_session_storage_item(key, value) + return self.execute_script( "window.sessionStorage.setItem('{}', '{}');".format(key, value) ) @@ -8867,6 +8878,8 @@ def get_session_storage_item(self, key): self.__check_scope() if not self.__is_valid_storage_url(): raise WebDriverException("Session Storage is not available here!") + if self.__is_cdp_swap_needed(): + return self.cdp.get_session_storage_item(key) return self.execute_script( "return window.sessionStorage.getItem('{}');".format(key) ) diff --git a/setup.py b/setup.py index 6d6a804d69b..50df36e3ca0 100755 --- a/setup.py +++ b/setup.py @@ -150,7 +150,7 @@ 'pip>=25.0.1', 'packaging>=24.2', 'setuptools~=70.2;python_version<"3.10"', # Newer ones had issues - 'setuptools>=75.8.2;python_version>="3.10"', + 'setuptools>=76.0.0;python_version>="3.10"', 'wheel>=0.45.1', 'attrs>=25.1.0', "certifi>=2025.1.31", @@ -160,7 +160,7 @@ 'filelock~=3.16.1;python_version<"3.9"', 'filelock>=3.17.0;python_version>="3.9"', 'fasteners>=0.19', - "mycdp>=1.1.0", + "mycdp>=1.1.1", "pynose>=1.5.4", 'platformdirs>=4.3.6', 'typing-extensions>=4.12.2', @@ -193,7 +193,8 @@ 'websocket-client==1.8.0', 'selenium==4.27.1;python_version<"3.9"', 'selenium==4.29.0;python_version>="3.9"', - 'cssselect==1.2.0', + 'cssselect==1.2.0;python_version<"3.9"', + 'cssselect==1.3.0;python_version>="3.9"', "sortedcontainers==2.4.0", 'execnet==2.1.1', 'iniconfig==2.0.0',