diff --git a/README.md b/README.md index ab5bd5d08d6..e1889da3e36 100755 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ for element in elements:

💡 You can set the Chromium browser to use via command line parameters:

```zsh -python SCRIPT.py --use-chromium # Use the unbranded Chromium browser +python SCRIPT.py --chromium # Use the unbranded Chromium browser python SCRIPT.py --cft # Use Chrome-for-testing python SCRIPT.py --edge # Use Microsoft Edge python SCRIPT.py --brave # Use Brave browser diff --git a/examples/cdp_mode/playwright/ReadMe.md b/examples/cdp_mode/playwright/ReadMe.md index 94bba582b5e..3237348d9dd 100644 --- a/examples/cdp_mode/playwright/ReadMe.md +++ b/examples/cdp_mode/playwright/ReadMe.md @@ -82,8 +82,7 @@ async def main(): await page.goto("https://example.com") if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) ``` ### 💡 Key differences of the 3 stealthy formats: @@ -269,8 +268,7 @@ async def main(): # ... if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) ``` (Fill in the `url` and the `proxy` details to complete the script.) diff --git a/examples/cdp_mode/playwright/raw_basic_async.py b/examples/cdp_mode/playwright/raw_basic_async.py index 975e66032a8..4972a8b2d3f 100644 --- a/examples/cdp_mode/playwright/raw_basic_async.py +++ b/examples/cdp_mode/playwright/raw_basic_async.py @@ -19,5 +19,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/playwright/raw_bing_cap_async.py b/examples/cdp_mode/playwright/raw_bing_cap_async.py index 58c974c3557..9231017cfa3 100644 --- a/examples/cdp_mode/playwright/raw_bing_cap_async.py +++ b/examples/cdp_mode/playwright/raw_bing_cap_async.py @@ -17,5 +17,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/playwright/raw_copilot_async.py b/examples/cdp_mode/playwright/raw_copilot_async.py index 90637e269c2..5f7fe57bc66 100644 --- a/examples/cdp_mode/playwright/raw_copilot_async.py +++ b/examples/cdp_mode/playwright/raw_copilot_async.py @@ -29,5 +29,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/playwright/raw_gas_info_async.py b/examples/cdp_mode/playwright/raw_gas_info_async.py index ee3a7241aab..aa91fad817d 100644 --- a/examples/cdp_mode/playwright/raw_gas_info_async.py +++ b/examples/cdp_mode/playwright/raw_gas_info_async.py @@ -36,5 +36,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/playwright/raw_gitlab_async.py b/examples/cdp_mode/playwright/raw_gitlab_async.py index 30f66676acd..cbe57d434a7 100644 --- a/examples/cdp_mode/playwright/raw_gitlab_async.py +++ b/examples/cdp_mode/playwright/raw_gitlab_async.py @@ -21,5 +21,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/playwright/raw_yc_news_async.py b/examples/cdp_mode/playwright/raw_yc_news_async.py index 623c20a9aca..331f16438db 100644 --- a/examples/cdp_mode/playwright/raw_yc_news_async.py +++ b/examples/cdp_mode/playwright/raw_yc_news_async.py @@ -19,5 +19,4 @@ async def main(): if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/raw_basic_async.py b/examples/cdp_mode/raw_basic_async.py index 5c497a469ba..876a00846b7 100644 --- a/examples/cdp_mode/raw_basic_async.py +++ b/examples/cdp_mode/raw_basic_async.py @@ -21,6 +21,5 @@ async def main(): driver.quit() if __name__ == "__main__": - loop = asyncio.new_event_loop() with decorators.print_runtime("raw_basic_async.py"): - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/raw_hilton.py b/examples/cdp_mode/raw_hilton.py index 73bdcdaa81e..d6ab75784ea 100644 --- a/examples/cdp_mode/raw_hilton.py +++ b/examples/cdp_mode/raw_hilton.py @@ -8,9 +8,9 @@ location_input = "input#location-input" sb.wait_for_element(location_input) sb.sleep(1.2) - sb.click("input#location-input") + sb.click(location_input) sb.sleep(1.2) - sb.press_keys("input#location-input", location) + sb.press_keys(location_input, location) sb.sleep(2) sb.click('span:contains("Check-in")') sb.sleep(1.2) diff --git a/examples/cdp_mode/raw_mobile_async.py b/examples/cdp_mode/raw_mobile_async.py index a6bfd024bbe..1a087e59cc8 100644 --- a/examples/cdp_mode/raw_mobile_async.py +++ b/examples/cdp_mode/raw_mobile_async.py @@ -25,6 +25,5 @@ async def main(): driver.stop() if __name__ == "__main__": - loop = asyncio.new_event_loop() with decorators.print_runtime("raw_mobile_async.py"): - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/raw_multi_async.py b/examples/cdp_mode/raw_multi_async.py index d7363f0768b..7cf5e0b8b01 100644 --- a/examples/cdp_mode/raw_multi_async.py +++ b/examples/cdp_mode/raw_multi_async.py @@ -17,9 +17,8 @@ async def main(url): driver.stop() -def set_up_loop(url): - loop = asyncio.new_event_loop() - loop.run_until_complete(main(url)) +def run_main(url): + asyncio.run(main(url)) if __name__ == "__main__": @@ -27,4 +26,4 @@ def set_up_loop(url): with decorators.print_runtime("raw_multi_async.py"): with ThreadPoolExecutor(max_workers=len(urls)) as executor: for url in urls: - executor.submit(set_up_loop, url) + executor.submit(run_main, url) diff --git a/examples/cdp_mode/raw_multi_c_async.py b/examples/cdp_mode/raw_multi_c_async.py index eed9486e060..6257f8a6873 100644 --- a/examples/cdp_mode/raw_multi_c_async.py +++ b/examples/cdp_mode/raw_multi_c_async.py @@ -19,9 +19,8 @@ async def main(url): driver.stop() -def set_up_loop(url): - loop = asyncio.new_event_loop() - loop.run_until_complete(main(url)) +def run_main(url): + asyncio.run(main(url)) if __name__ == "__main__": @@ -29,4 +28,4 @@ def set_up_loop(url): with decorators.print_runtime("raw_multi_c_async.py"): with ThreadPoolExecutor(max_workers=len(urls)) as executor: for url in urls: - executor.submit(set_up_loop, url) + executor.submit(run_main, url) diff --git a/examples/cdp_mode/raw_muse_async.py b/examples/cdp_mode/raw_muse_async.py index 03cd0919b7e..c5a97efe5e8 100644 --- a/examples/cdp_mode/raw_muse_async.py +++ b/examples/cdp_mode/raw_muse_async.py @@ -14,5 +14,4 @@ async def main(): await page.sleep(3) if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/raw_priceline.py b/examples/cdp_mode/raw_priceline.py index 048dfa5615b..a7edf9b10f6 100644 --- a/examples/cdp_mode/raw_priceline.py +++ b/examples/cdp_mode/raw_priceline.py @@ -6,9 +6,7 @@ sb.activate_cdp_mode() sb.goto("https://www.priceline.com") sb.sleep(3) - input_selector = 'input[name="endLocation"]' - if not sb.is_element_present(input_selector): - input_selector = "div.location-input input" + input_selector = "div.location-input input" sb.gui_hover_element(input_selector) sb.mouse_click(input_selector) location = "Portland, OR" diff --git a/examples/cdp_mode/raw_reddit_async.py b/examples/cdp_mode/raw_reddit_async.py index d24ae7fe594..430c03a3b6f 100644 --- a/examples/cdp_mode/raw_reddit_async.py +++ b/examples/cdp_mode/raw_reddit_async.py @@ -20,5 +20,4 @@ async def main(): driver.stop() if __name__ == "__main__": - loop = asyncio.new_event_loop() - loop.run_until_complete(main()) + asyncio.run(main()) diff --git a/examples/cdp_mode/raw_req_async.py b/examples/cdp_mode/raw_req_async.py index ba1c4b69298..eeb5c6fc42f 100644 --- a/examples/cdp_mode/raw_req_async.py +++ b/examples/cdp_mode/raw_req_async.py @@ -42,8 +42,7 @@ async def start_test(self): @decorators.print_runtime("RequestPausedTest") def main(): test = RequestPausedTest() - loop = asyncio.new_event_loop() - loop.run_until_complete(test.start_test()) + asyncio.run(test.start_test()) if __name__ == "__main__": diff --git a/examples/cdp_mode/raw_stopandshop.py b/examples/cdp_mode/raw_stopandshop.py index edb2b50d25d..40b94650a84 100644 --- a/examples/cdp_mode/raw_stopandshop.py +++ b/examples/cdp_mode/raw_stopandshop.py @@ -4,11 +4,9 @@ with SB(uc=True, test=True, guest=True) as sb: sb.activate_cdp_mode() sb.goto("https://stopandshop.com/") - sb.sleep(2.8) - if not sb.is_element_present("#brand-logo_link"): - sb.refresh() - sb.sleep(2.6) - sb.wait_for_element("#brand-logo_link", timeout=3) + sb.sleep(1.6) + sb.solve_captcha() + sb.sleep(1.8) sb.click_if_visible("#optly-popup-refresh-btn") query = "Fresh Turkey" required_text = "Turkey" diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index b601ffcf1f7..034462cbd96 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -5,7 +5,7 @@ regex>=2026.5.9 pymdown-extensions>=10.21.3 pipdeptree>=3.1.0 python-dateutil>=2.8.2 -click>=8.4.1 +click>=8.4.2 Markdown==3.10.2 ghp-import==2.1.0 watchdog==6.0.0 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 3765f875930..4c5a00bb3ef 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.50.2" +__version__ = "4.50.3" diff --git a/seleniumbase/behave/behave_sb.py b/seleniumbase/behave/behave_sb.py index 6cdfedcb819..c7f9aa8f3a3 100644 --- a/seleniumbase/behave/behave_sb.py +++ b/seleniumbase/behave/behave_sb.py @@ -492,8 +492,11 @@ def get_configured_sb(context): sb.binary_location = binary_location sb_config.binary_location = binary_location continue - # Handle: -D use-chromium - if low_key in ["use-chromium"] and not sb_config.binary_location: + # Handle: -D use-chromium / chromium + if ( + low_key in ["use-chromium", "chromium"] + and not sb_config.binary_location + ): binary_location = "_chromium_" sb.binary_location = binary_location sb_config.binary_location = binary_location diff --git a/seleniumbase/console_scripts/ReadMe.md b/seleniumbase/console_scripts/ReadMe.md index 178747504d1..c49cafc6e7f 100644 --- a/seleniumbase/console_scripts/ReadMe.md +++ b/seleniumbase/console_scripts/ReadMe.md @@ -63,13 +63,14 @@ sbase install [DRIVER] [OPTIONS] sbase get chromedriver sbase get geckodriver sbase get edgedriver -sbase get chromedriver 114 -sbase get chromedriver 114.0.5735.90 +sbase get chromedriver 149 +sbase get chromedriver 149.0.7827.115 sbase get chromedriver stable sbase get chromedriver beta sbase get chromedriver -p sbase get chromium -sbase get cft 131 +sbase get chromium --revision=1639046 +sbase get cft 149 sbase get chs ``` diff --git a/seleniumbase/console_scripts/run.py b/seleniumbase/console_scripts/run.py index fb8a2828709..6cf3fa357c7 100644 --- a/seleniumbase/console_scripts/run.py +++ b/seleniumbase/console_scripts/run.py @@ -152,12 +152,14 @@ def show_install_usage(): print(" sbase get chromedriver") print(" sbase get geckodriver") print(" sbase get edgedriver") - print(" sbase get chromedriver 114") - print(" sbase get chromedriver 114.0.5735.90") + print(" sbase get chromedriver 149") + print(" sbase get chromedriver 149.0.7827.115") print(" sbase get chromedriver stable") print(" sbase get chromedriver beta") print(" sbase get chromedriver -p") - print(" sbase get cft 131") + print(" sbase get chromium") + print(" sbase get chromium --revision=1639046") + print(" sbase get cft 149") print(" sbase get chs") print(" Output:") print(" Downloads the webdriver to seleniumbase/drivers/") diff --git a/seleniumbase/console_scripts/sb_install.py b/seleniumbase/console_scripts/sb_install.py index 8cfb02ff90a..b753cf631de 100644 --- a/seleniumbase/console_scripts/sb_install.py +++ b/seleniumbase/console_scripts/sb_install.py @@ -14,13 +14,14 @@ sbase get chromedriver sbase get geckodriver sbase get edgedriver - sbase get chromedriver 114 - sbase get chromedriver 114.0.5735.90 + sbase get chromedriver 149 + sbase get chromedriver 149.0.7827.115 sbase get chromedriver stable sbase get chromedriver beta sbase get chromedriver -p sbase get chromium - sbase get cft 131 + sbase get chromium --revision=1639046 + sbase get cft 149 sbase get chs Output: Downloads the webdriver to seleniumbase/drivers/ diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index f05a9e36e64..7d727eb6ade 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -5012,7 +5012,10 @@ def get_local_driver( device_height, device_pixel_ratio, ) - if binary_location and "chromium_drivers" in binary_location: + if ( + (binary_location and "chromium_drivers" in binary_location) + or (binary_location and "Chromium.app" in binary_location) + ): chrome_options.add_argument("--use-mock-keychain") use_version = "latest" major_chrome_version = None diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 45bf1c9fc5f..8b12c42b4f3 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -2308,6 +2308,8 @@ def __gui_slide_datadome_captcha(self): time.sleep(0.48) self.loop.run_until_complete(self.page.wait(0.1)) x2 = x2 + 22.5 # Overshoot drop to maximize compatibility + y1 = y1 + 3 + y2 = y2 + 3 self.gui_drag_drop_points(x1, y1, x2, y2, timeframe=0.55) time.sleep(0.25) self.loop.run_until_complete(self.page.wait(0.2)) diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py index 7c5c0e910f7..42f5dc762ff 100644 --- a/seleniumbase/plugins/driver_manager.py +++ b/seleniumbase/plugins/driver_manager.py @@ -668,7 +668,10 @@ def Driver( binary_location = "cft" elif chs and not binary_location: binary_location = "chs" - if "--use-chromium" in sys_argv and not binary_location: + if ( + ("--use-chromium" in sys_argv and not binary_location) + or ("--chromium" in sys_argv and not binary_location) + ): binary_location = "_chromium_" elif "--cft" in sys_argv and not binary_location: binary_location = "cft" diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py index afca75d19b4..f0670e888cb 100644 --- a/seleniumbase/plugins/pytest_plugin.py +++ b/seleniumbase/plugins/pytest_plugin.py @@ -33,7 +33,7 @@ def pytest_addoption(parser): --brave (Shortcut for "--browser=brave".) --comet (Shortcut for "--browser=comet".) --atlas (Shortcut for "--browser=atlas".) - --use-chromium (Shortcut for using base `Chromium`) + --chromium (Shortcut for using base `Chromium`) --cft (Shortcut for using `Chrome for Testing`) --chs (Shortcut for using `Chrome-Headless-Shell`) --settings-file=FILE (Override default SeleniumBase settings.) @@ -223,6 +223,7 @@ def pytest_addoption(parser): ) parser.addoption( "--use-chromium", + "--chromium", action="store_true", dest="use_chromium", default=False, diff --git a/seleniumbase/plugins/sb_manager.py b/seleniumbase/plugins/sb_manager.py index d36630636ef..6dfacfeeba2 100644 --- a/seleniumbase/plugins/sb_manager.py +++ b/seleniumbase/plugins/sb_manager.py @@ -708,7 +708,10 @@ def SB( binary_location = "cft" elif chs and not binary_location: binary_location = "chs" - if "--use-chromium" in sys_argv and not binary_location: + if ( + ("--use-chromium" in sys_argv and not binary_location) + or ("--chromium" in sys_argv and not binary_location) + ): binary_location = "_chromium_" elif "--cft" in sys_argv and not binary_location: binary_location = "cft" diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index 2f680066a75..744d58aaa88 100644 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -22,7 +22,7 @@ class SeleniumBrowser(Plugin): --brave (Shortcut for "--browser=brave".) --comet (Shortcut for "--browser=comet".) --atlas (Shortcut for "--browser=atlas".) - --use-chromium (Shortcut for using base `Chromium`) + --chromium (Shortcut for using base `Chromium`) --cft (Shortcut for using `Chrome for Testing`) --chs (Shortcut for using `Chrome-Headless-Shell`) --user-data-dir=DIR (Set the Chrome user data directory to use.) @@ -184,6 +184,7 @@ def options(self, parser, env): ) parser.addoption( "--use-chromium", + "--chromium", action="store_true", dest="use_chromium", default=False, diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py index 508160e834d..89a0292685a 100644 --- a/seleniumbase/undetected/cdp_driver/cdp_util.py +++ b/seleniumbase/undetected/cdp_driver/cdp_util.py @@ -527,7 +527,11 @@ async def start( print(" Using default Chrome browser instead!") bin_loc = None browser_executable_path = bin_loc - elif use_chromium or "--use-chromium" in arg_join: + elif ( + use_chromium + or "--use-chromium" in arg_join + or "--chromium" in sys_argv + ): browser_executable_path = "_chromium_" elif cft or "--cft" in arg_join: browser_executable_path = "_cft_" diff --git a/seleniumbase/undetected/cdp_driver/config.py b/seleniumbase/undetected/cdp_driver/config.py index 986849026bf..6f19d0eb3c2 100644 --- a/seleniumbase/undetected/cdp_driver/config.py +++ b/seleniumbase/undetected/cdp_driver/config.py @@ -195,6 +195,8 @@ def __init__( f"Defaulting to regular Chrome!" ) browser_executable_path = find_chrome_executable() + elif "Chromium.app" in browser_executable_path: + mock_keychain = True self._browser_args = browser_args self.browser_executable_path = browser_executable_path self.headless = headless