diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index c111ad04aef..b08995fab0b 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -189,14 +189,17 @@ from seleniumbase import SB with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.hyatt.com/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible('button[aria-label="Close"]') - sb.cdp.click_if_visible("#onetrust-reject-all-handler") - sb.sleep(2) + sb.sleep(3.5) + sb.click_if_visible('button[aria-label="Close"]') + sb.click_if_visible("#onetrust-reject-all-handler") + sb.sleep(1) location = "Anaheim, CA, USA" - sb.cdp.type('input[data-id="location"]', location) - sb.cdp.click("button.quickbookSearchFormButton") - sb.sleep(5) + sb.type('input[id="search-term"]', location) + sb.sleep(1) + sb.click('li[data-js="suggestion"]') + sb.sleep(1) + sb.click("button.be-button-shop") + sb.sleep(6) card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]' hotels = sb.cdp.select_all(card_info) print("Hyatt Hotels in %s:" % location) @@ -274,22 +277,21 @@ from seleniumbase import SB with SB(uc=True, test=True, ad_block=True) as sb: url = "https://www.walmart.com/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible('[data-automation-id*="close-mark"]') - sb.sleep(0.3) - sb.cdp.mouse_click('input[aria-label="Search"]') + sb.sleep(2.8) + sb.click('input[aria-label="Search"]') sb.sleep(1.2) search = "Settlers of Catan Board Game" required_text = "Catan" - sb.cdp.press_keys('input[aria-label="Search"]', search + "\n") + sb.press_keys('input[aria-label="Search"]', search + "\n") sb.sleep(3.8) if sb.is_element_visible("#px-captcha"): - sb.cdp.gui_click_and_hold("#px-captcha", 12) - sb.sleep(3.2) + sb.cdp.gui_click_and_hold("#px-captcha", 7.2) + sb.sleep(4.2) if sb.is_element_visible("#px-captcha"): - sb.cdp.gui_click_and_hold("#px-captcha", 12) + sb.cdp.gui_click_and_hold("#px-captcha", 4.2) sb.sleep(3.2) sb.cdp.remove_elements('[data-testid="skyline-ad"]') + sb.cdp.remove_elements('[data-testid="sba-container"]') print('*** Walmart Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] diff --git a/examples/cdp_mode/raw_consecutive_c.py b/examples/cdp_mode/raw_consecutive_c.py index 378949de1d0..6f0da1c2a9e 100644 --- a/examples/cdp_mode/raw_consecutive_c.py +++ b/examples/cdp_mode/raw_consecutive_c.py @@ -6,6 +6,6 @@ sb.activate_cdp_mode(url) sb.sleep(2.2) sb.uc_gui_click_captcha() - sb.sleep(2.2) + sb.sleep(2.6) sb.uc_gui_click_captcha() sb.sleep(2) diff --git a/examples/cdp_mode/raw_hyatt.py b/examples/cdp_mode/raw_hyatt.py index ebe8f4a4053..fff0b4e8570 100644 --- a/examples/cdp_mode/raw_hyatt.py +++ b/examples/cdp_mode/raw_hyatt.py @@ -3,14 +3,17 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.hyatt.com/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible('button[aria-label="Close"]') - sb.cdp.click_if_visible("#onetrust-reject-all-handler") - sb.sleep(2) + sb.sleep(3.5) + sb.click_if_visible('button[aria-label="Close"]') + sb.click_if_visible("#onetrust-reject-all-handler") + sb.sleep(1) location = "Anaheim, CA, USA" - sb.cdp.type('input[data-id="location"]', location) - sb.cdp.click("button.quickbookSearchFormButton") - sb.sleep(5) + sb.type('input[id="search-term"]', location) + sb.sleep(1) + sb.click('li[data-js="suggestion"]') + sb.sleep(1) + sb.click("button.be-button-shop") + sb.sleep(6) card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]' hotels = sb.cdp.select_all(card_info) print("Hyatt Hotels in %s:" % location) diff --git a/examples/cdp_mode/raw_nordstrom.py b/examples/cdp_mode/raw_nordstrom.py index ddc34dd1eb4..297485ba18e 100644 --- a/examples/cdp_mode/raw_nordstrom.py +++ b/examples/cdp_mode/raw_nordstrom.py @@ -23,4 +23,4 @@ price = item.querySelector('div div span[aria-hidden="true"]') if price: price_text = price.text - print("* %s (%s)" % (description.text, price_text)) + print("* %s (%s)" % (description.text, price_text)) diff --git a/examples/cdp_mode/raw_walmart.py b/examples/cdp_mode/raw_walmart.py index 6ba0524f93a..c9bc0f93190 100644 --- a/examples/cdp_mode/raw_walmart.py +++ b/examples/cdp_mode/raw_walmart.py @@ -3,22 +3,21 @@ with SB(uc=True, test=True, ad_block=True) as sb: url = "https://www.walmart.com/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible('[data-automation-id*="close-mark"]') - sb.sleep(0.3) - sb.cdp.mouse_click('input[aria-label="Search"]') + sb.sleep(2.8) + sb.click('input[aria-label="Search"]') sb.sleep(1.2) search = "Settlers of Catan Board Game" required_text = "Catan" - sb.cdp.press_keys('input[aria-label="Search"]', search + "\n") + sb.press_keys('input[aria-label="Search"]', search + "\n") sb.sleep(3.8) if sb.is_element_visible("#px-captcha"): - sb.cdp.gui_click_and_hold("#px-captcha", 12) - sb.sleep(3.2) + sb.cdp.gui_click_and_hold("#px-captcha", 7.2) + sb.sleep(4.2) if sb.is_element_visible("#px-captcha"): - sb.cdp.gui_click_and_hold("#px-captcha", 12) + sb.cdp.gui_click_and_hold("#px-captcha", 4.2) sb.sleep(3.2) sb.cdp.remove_elements('[data-testid="skyline-ad"]') + sb.cdp.remove_elements('[data-testid="sba-container"]') print('*** Walmart Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] diff --git a/examples/presenter/uc_presentation_4.py b/examples/presenter/uc_presentation_4.py index 496c1e1281c..36bc7ab9e5f 100644 --- a/examples/presenter/uc_presentation_4.py +++ b/examples/presenter/uc_presentation_4.py @@ -684,14 +684,17 @@ def test_presentation_4(self): with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.hyatt.com/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible('button[aria-label="Close"]') - sb.cdp.click_if_visible("#onetrust-reject-all-handler") - sb.sleep(2) + sb.sleep(3.5) + sb.click_if_visible('button[aria-label="Close"]') + sb.click_if_visible("#onetrust-reject-all-handler") + sb.sleep(1) location = "Anaheim, CA, USA" - sb.cdp.type('input[data-id="location"]', location) - sb.cdp.click("button.quickbookSearchFormButton") - sb.sleep(5) + sb.type('input[id="search-term"]', location) + sb.sleep(1) + sb.click('li[data-js="suggestion"]') + sb.sleep(1) + sb.click("button.be-button-shop") + sb.sleep(6) card_info = ( 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]' ) @@ -887,7 +890,7 @@ def test_presentation_4(self): ) if price: price_text = price.text - print("* %s (%s)" % (description.text, price_text)) + print("* %s (%s)" % (description.text, price_text)) self.create_presentation(theme="serif", transition="none") self.add_slide( diff --git a/requirements.txt b/requirements.txt index fd06570103f..e1ac91fd6b1 100755 --- a/requirements.txt +++ b/requirements.txt @@ -46,7 +46,8 @@ trio==0.27.0;python_version<"3.9" trio>=0.31.0,<1;python_version>="3.9" trio-websocket~=0.12.2 wsproto==1.2.0 -websocket-client~=1.8.0 +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" @@ -73,6 +74,7 @@ soupsieve~=2.8;python_version>="3.9" beautifulsoup4~=4.14.2 pyotp==2.9.0 python-xlib==0.33;platform_system=="Linux" +PyAutoGUI>=0.9.54;platform_system=="Linux" markdown-it-py==3.0.0;python_version<"3.10" markdown-it-py==4.0.0;python_version>="3.10" mdurl==0.1.2 diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index f731a2b60ad..57275d83a59 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.42.2" +__version__ = "4.42.3" diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 20e2573f6aa..2b0d208df4a 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -712,7 +712,10 @@ def click(self, selector, timeout=None): self.__slow_mode_pause_if_set() element = self.find_element(selector, timeout=timeout) element.scroll_into_view() - element.click() + if element.tag_name == "div" or element.tag_name == "input": + element.mouse_click() # Simulated click (not PyAutoGUI) + else: + element.click() self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.wait()) diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py index 4e65f59e933..8d733fc1b5f 100644 --- a/seleniumbase/undetected/cdp_driver/cdp_util.py +++ b/seleniumbase/undetected/cdp_driver/cdp_util.py @@ -258,13 +258,13 @@ async def start( config: Optional[Config] = None, *, user_data_dir: Optional[PathLike] = None, - headless: Optional[bool] = False, - incognito: Optional[bool] = False, - guest: Optional[bool] = False, + headless: Optional[bool] = None, + incognito: Optional[bool] = None, + guest: Optional[bool] = None, browser_executable_path: Optional[PathLike] = None, browser_args: Optional[List[str]] = None, xvfb_metrics: Optional[List[str]] = None, # "Width,Height" for Linux - ad_block: Optional[bool] = False, + ad_block: Optional[bool] = None, sandbox: Optional[bool] = True, lang: Optional[str] = None, # Set the Language Locale Code host: Optional[str] = None, # Chrome remote-debugging-host @@ -318,6 +318,210 @@ async def start( (For example, ensuring shadow-root is always in "open" mode.) :type expert: bool """ + sys_argv = sys.argv + arg_join = " ".join(sys_argv) + if headless is None: + if "--headless" in sys_argv: + headless = True + else: + headless = False + if headed is None: + if "--gui" in sys_argv or "--headed" in sys_argv: + headed = True + else: + headed = False + if xvfb is None: + if "--xvfb" in sys_argv: + xvfb = True + else: + xvfb = False + if incognito is None: + if "--incognito" in sys_argv: + incognito = True + else: + incognito = False + if guest is None: + if "--guest" in sys_argv: + guest = True + else: + guest = False + if ad_block is None: + if "--ad-block" in sys_argv or "--ad_block" in sys_argv: + ad_block = True + else: + ad_block = False + if xvfb_metrics is None and "--xvfb-metrics" in arg_join: + x_m = xvfb_metrics + count = 0 + for arg in sys_argv: + if arg.startswith("--xvfb-metrics="): + x_m = arg.split("--xvfb-metrics=")[1] + break + elif arg == "--xvfb-metrics" and len(sys_argv) > count + 1: + x_m = sys_argv[count + 1] + if x_m.startswith("-"): + x_m = None + break + count += 1 + if x_m: + if x_m.startswith('"') and x_m.endswith('"'): + x_m = x_m[1:-1] + elif x_m.startswith("'") and x_m.endswith("'"): + x_m = x_m[1:-1] + xvfb_metrics = x_m + if agent is None and "user_agent" not in kwargs and "--agent" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--agent="): + agent = arg.split("--agent=")[1] + break + elif arg == "--agent" and len(sys_argv) > count + 1: + agent = sys_argv[count + 1] + if agent.startswith("-"): + agent = None + break + count += 1 + if agent: + if agent.startswith('"') and agent.endswith('"'): + agent = agent[1:-1] + elif agent.startswith("'") and agent.endswith("'"): + agent = agent[1:-1] + if ( + geoloc is None + and "geolocation" not in kwargs + and "--geolocation" in arg_join + ): + count = 0 + for arg in sys_argv: + if arg.startswith("--geolocation="): + geoloc = arg.split("--geolocation=")[1] + break + elif arg == "--geolocation" and len(sys_argv) > count + 1: + geoloc = sys_argv[count + 1] + if geoloc.startswith("-"): + geoloc = None + break + count += 1 + if geoloc: + if geoloc.startswith('"') and geoloc.endswith('"'): + geoloc = geoloc[1:-1] + elif geoloc.startswith("'") and geoloc.endswith("'"): + geoloc = geoloc[1:-1] + if geoloc: + import ast + geoloc = ast.literal_eval(geoloc) + if not lang and "locale" not in kwargs and "locale_code" not in kwargs: + if "--locale" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--locale="): + lang = arg.split("--locale=")[1] + break + elif arg == "--locale" and len(sys_argv) > count + 1: + lang = sys_argv[count + 1] + if lang.startswith("-"): + lang = None + break + count += 1 + elif "--lang" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--lang="): + lang = arg.split("--lang=")[1] + break + elif arg == "--lang" and len(sys_argv) > count + 1: + lang = sys_argv[count + 1] + if lang.startswith("-"): + lang = None + break + count += 1 + if lang: + if lang.startswith('"') and lang.endswith('"'): + lang = lang[1:-1] + elif lang.startswith("'") and lang.endswith("'"): + lang = lang[1:-1] + if not browser_executable_path and "binary_location" not in kwargs: + bin_loc = None + if "--binary-location" in arg_join or "--binary_location" in arg_join: + bin_loc_cmd = "--binary-location" + if "--binary_location" in arg_join: + bin_loc_cmd = "--binary_location" + count = 0 + bin_loc = None + for arg in sys_argv: + if arg.startswith("%s=" % bin_loc_cmd): + bin_loc = arg.split("%s=" % bin_loc_cmd)[1] + break + elif arg == bin_loc_cmd and len(sys_argv) > count + 1: + bin_loc = sys_argv[count + 1] + if bin_loc.startswith("-"): + bin_loc = None + break + count += 1 + elif "--bl=" in arg_join: + count = 0 + bin_loc = None + for arg in sys_argv: + if arg.startswith("--bl="): + bin_loc = arg.split("--bl=")[1] + break + count += 1 + if bin_loc: + if bin_loc.startswith('"') and bin_loc.endswith('"'): + bin_loc = bin_loc[1:-1] + elif bin_loc.startswith("'") and bin_loc.endswith("'"): + bin_loc = bin_loc[1:-1] + if bin_loc and not os.path.exists(bin_loc): + print(" No browser executable at PATH {%s}! " % bin_loc) + print(" Using default Chrome browser instead!") + bin_loc = None + browser_executable_path = bin_loc + if proxy is None and "--proxy" in arg_join: + proxy_string = None + if "--proxy=" in arg_join: + proxy_string = arg_join.split("--proxy=")[1].split(" ")[0] + elif "--proxy " in arg_join: + proxy_string = arg_join.split("--proxy ")[1].split(" ")[0] + if proxy_string: + if proxy_string.startswith('"') and proxy_string.endswith('"'): + proxy_string = proxy_string[1:-1] + elif proxy_string.startswith("'") and proxy_string.endswith("'"): + proxy_string = proxy_string[1:-1] + proxy = proxy_string + if tzone is None and "timezone" not in kwargs and "--timezone" in arg_join: + tz_string = None + if "--timezone=" in arg_join: + tz_string = arg_join.split("--timezone=")[1].split(" ")[0] + elif "--timezone " in arg_join: + tz_string = arg_join.split("--timezone ")[1].split(" ")[0] + if tz_string: + if tz_string.startswith('"') and tz_string.endswith('"'): + tz_string = proxy_string[1:-1] + elif tz_string.startswith("'") and tz_string.endswith("'"): + tz_string = proxy_string[1:-1] + tzone = tz_string + platform_var = None + if ( + "platform" not in kwargs + and "plat" not in kwargs + and "--platform" in arg_join + ): + count = 0 + for arg in sys_argv: + if arg.startswith("--platform="): + platform_var = arg.split("--platform=")[1] + break + elif arg == "--platform" and len(sys_argv) > count + 1: + platform_var = sys_argv[count + 1] + if platform_var.startswith("-"): + platform_var = None + break + count += 1 + if platform_var: + if platform_var.startswith('"') and platform_var.endswith('"'): + platform_var = platform_var[1:-1] + elif platform_var.startswith("'") and platform_var.endswith("'"): + platform_var = platform_var[1:-1] if IS_LINUX and not headless and not headed and not xvfb: xvfb = True # The default setting on Linux __activate_virtual_display_as_needed(headless, headed, xvfb, xvfb_metrics) @@ -404,6 +608,8 @@ async def start( sb_config._cdp_platform = kwargs["platform"] elif "plat" in kwargs: sb_config._cdp_platform = kwargs["plat"] + elif platform_var: + sb_config._cdp_platform = platform_var else: sb_config._cdp_platform = None return driver diff --git a/setup.py b/setup.py index eedcc9ae1e2..f4e5ddd1814 100755 --- a/setup.py +++ b/setup.py @@ -193,7 +193,8 @@ 'trio>=0.31.0,<1;python_version>="3.9"', 'trio-websocket~=0.12.2', 'wsproto==1.2.0', - 'websocket-client~=1.8.0', + '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"', @@ -220,6 +221,7 @@ "beautifulsoup4~=4.14.2", 'pyotp==2.9.0', 'python-xlib==0.33;platform_system=="Linux"', + 'PyAutoGUI>=0.9.54;platform_system=="Linux"', 'markdown-it-py==3.0.0;python_version<"3.10"', 'markdown-it-py==4.0.0;python_version>="3.10"', 'mdurl==0.1.2', @@ -300,8 +302,9 @@ "psutil==7.1.0", ], # pip install -e .[pyautogui] + # (Already a required dependency on Linux now.) "pyautogui": [ - "PyAutoGUI==0.9.54", + 'PyAutoGUI>=0.9.54;platform_system!="Linux"', ], # pip install -e .[selenium-stealth] "selenium-stealth": [ @@ -310,7 +313,7 @@ # pip install -e .[selenium-wire] "selenium-wire": [ 'selenium-wire==5.1.0', - 'pyOpenSSL==24.2.1', + 'pyOpenSSL>=24.2.1', 'pyparsing>=3.1.4', 'Brotli==1.1.0', 'blinker==1.7.0', # Newer ones had issues @@ -319,7 +322,7 @@ 'hyperframe==6.0.1', 'kaitaistruct==0.10', 'pyasn1==0.6.1', - 'zstandard==0.23.0', + 'zstandard>=0.23.0', ], }, packages=[