diff --git a/README.md b/README.md index 085cec4c7e8..0cb7d5b3e99 100755 --- a/README.md +++ b/README.md @@ -54,15 +54,15 @@

-

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.

+

SeleniumBase is a browser automation framework that empowers software teams to innovate faster and handle modern web challenges with ease. With stealth options like CDP Mode, you'll avoid the usual restrictions imposed by websites deploying bot-detection services.

-------- 📚 Learn from [**over 200 examples** in the **SeleniumBase/examples/** folder](https://github.com/seleniumbase/SeleniumBase/tree/master/examples). -🐙 Stealth modes: UC Mode and CDP Mode help you evade bot-detection. +🐙 Stealth modes: UC Mode and CDP Mode can bypass bot-detection, solve CAPTCHAs, and call advanced methods from the Chrome Devtools Protocol. -â„šī¸ Most scripts run with raw python, although some scripts use Syntax Formats that expect pytest (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically). +â„šī¸ Many examples run with raw python, although some use Syntax Formats that expect pytest (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically). -------- diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index 18e194b60db..ed0283f5c4e 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -2,7 +2,7 @@ ## [](https://github.com/seleniumbase/SeleniumBase/) CDP Mode 🐙 -🐙 SeleniumBase CDP Mode is a stealth mode of SeleniumBase that uses the Chrome Devtools Protocol (via MyCDP) to control the web browser. CDP Mode can be used either as a subset of SeleniumBase UC Mode, or via Pure CDP Mode (sb_cdp), which doesn't use WebDriver at all, and has a slightly different setup. +🐙 SeleniumBase CDP Mode is a stealth mode of SeleniumBase that uses the Chrome Devtools Protocol (via MyCDP) to control the web browser. CDP Mode can be used either as a subset of SeleniumBase UC Mode, or via Pure CDP Mode (sb_cdp), which doesn't use WebDriver at all, and has a slightly different setup. -------- @@ -55,6 +55,7 @@ with SB(uc=True, test=True, locale="en") as sb: sb.activate_cdp_mode(url) sb.sleep(2) sb.solve_captcha() + sb.sleep(2) ``` @@ -63,7 +64,7 @@ with SB(uc=True, test=True, locale="en") as sb: -------- -`sb.cdp.gui_click_element(selector)` lets you click on elements using `PyAutoGUI`. Example: +You can also use `PyAutoGUI` to click on elements with the mouse by calling `sb.cdp.gui_click_element(selector)`. Example: ```python from seleniumbase import SB @@ -86,7 +87,7 @@ Eg. `sb.cdp.gui_click_element("#turnstile-widget div")` In most cases, `sb.solve_captcha()` is good enough for CF Turnstiles without needing `sb.cdp.gui_click_element(selector)`. (See [SeleniumBase/examples/cdp_mode/raw_planetmc.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_planetmc.py)) -â„šī¸ Note that `PyAutoGUI` is an optional dependency. If calling a method that uses it when not already installed, then `SeleniumBase` installs `PyAutoGUI` at run-time. +â„šī¸ Note that `PyAutoGUI` is an optional dependency. If calling a method that uses it when not already installed, then `SeleniumBase` installs `PyAutoGUI` at runtime. -------- diff --git a/examples/cdp_mode/raw_albertsons.py b/examples/cdp_mode/raw_albertsons.py index 5050ec201ce..c11bd4493f5 100644 --- a/examples/cdp_mode/raw_albertsons.py +++ b/examples/cdp_mode/raw_albertsons.py @@ -5,24 +5,24 @@ sb.activate_cdp_mode(url) sb.sleep(2.5) sb.remove_element("div > div > article") - sb.cdp.scroll_into_view('input[type="search"]') + sb.scroll_into_view('input[type="search"]') close_btn = ".notification-alert-wrapper__close-button" - sb.cdp.click_if_visible(close_btn) - sb.cdp.click("input#search-suggestion-input") + sb.click_if_visible(close_btn) + sb.click("input#search-suggestion-input") sb.sleep(0.2) search = "Avocado Smoked Salmon" required_text = "Salmon" - sb.cdp.press_keys("input#search-suggestion-input", search) + sb.press_keys("input#search-suggestion-input", search) sb.sleep(0.8) - sb.cdp.click("#suggestion-0 a span") + sb.click("#suggestion-0 a span") sb.sleep(0.8) - sb.cdp.click_if_visible(close_btn) - sb.sleep(2.8) + sb.click_if_visible(close_btn) + sb.sleep(3.2) print('*** Albertsons Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] item_selector = 'a[href*="/meal-plans-recipes/shop/"]' - items = sb.cdp.find_elements(item_selector) + items = sb.find_elements(item_selector) for item in items: sb.sleep(0.06) if required_text in item.text: diff --git a/examples/cdp_mode/raw_cdp_copilot.py b/examples/cdp_mode/raw_cdp_copilot.py index 5e5d68ee8f5..ee81450eaf4 100644 --- a/examples/cdp_mode/raw_cdp_copilot.py +++ b/examples/cdp_mode/raw_cdp_copilot.py @@ -1,7 +1,7 @@ from seleniumbase import sb_cdp url = "https://copilot.microsoft.com/" -sb = sb_cdp.Chrome(url, locale="en", guest=True) +sb = sb_cdp.Chrome(url, locale="en") textarea = "textarea#userInput" sb.wait_for_element(textarea) sb.sleep(1.5) diff --git a/examples/cdp_mode/raw_cf_clearance.py b/examples/cdp_mode/raw_cf_clearance.py index b6318da268b..4d9952ef664 100644 --- a/examples/cdp_mode/raw_cf_clearance.py +++ b/examples/cdp_mode/raw_cf_clearance.py @@ -12,7 +12,7 @@ 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.gui_click_captcha() # (Only if found) +sb.solve_captcha() # (Only if found) sb.sleep(2.2) # Wait for CAPTCHA success cf_cookie = get_cf_clearance_cookie(sb) if cf_cookie: diff --git a/examples/cdp_mode/raw_copilot.py b/examples/cdp_mode/raw_copilot.py index b280c58cf0c..9b722a54c1c 100644 --- a/examples/cdp_mode/raw_copilot.py +++ b/examples/cdp_mode/raw_copilot.py @@ -1,6 +1,6 @@ from seleniumbase import SB -with SB(uc=True, test=True, guest=True) as sb: +with SB(uc=True, test=True, locale="en") as sb: url = "https://copilot.microsoft.com/" sb.activate_cdp_mode(url) textarea = "textarea#userInput" diff --git a/examples/cdp_mode/raw_driver.py b/examples/cdp_mode/raw_driver.py index d9ff6a20648..47e39c37e3a 100644 --- a/examples/cdp_mode/raw_driver.py +++ b/examples/cdp_mode/raw_driver.py @@ -6,6 +6,6 @@ url = "www.planetminecraft.com/account" driver.uc_activate_cdp_mode(url) driver.sleep(1) -driver.cdp.solve_captcha() +driver.solve_captcha() driver.wait_for_element_absent("input[disabled]") driver.sleep(2) diff --git a/examples/cdp_mode/raw_elal.py b/examples/cdp_mode/raw_elal.py index 49855d88840..973f50782a3 100644 --- a/examples/cdp_mode/raw_elal.py +++ b/examples/cdp_mode/raw_elal.py @@ -6,7 +6,7 @@ url = "www.elal.com/flight-deals/en-us/flights-from-boston-to-tel-aviv" sb.activate_cdp_mode(url) sb.sleep(3) - sb.cdp.click('label:contains("Departure date")') + sb.click('label:contains("Departure date")') sb.sleep(1) today = datetime.date.today() days_ahead = (4 - today.weekday() + 7) % 7 @@ -25,21 +25,21 @@ sb.sleep(1) sb.cdp.gui_press_keys("\b" * 10 + formatted_date + "\n") sb.sleep(1) - sb.cdp.click('button[data-att="done"]') + sb.click('button[data-att="done"]') sb.sleep(1) - sb.cdp.click('button[data-att="search"]') + sb.click('button[data-att="search"]') sb.sleep(5) - sb.cdp.click_if_visible("#onetrust-close-btn-container button") + sb.click_if_visible("#onetrust-close-btn-container button") sb.sleep(1) view_other_dates = 'button[aria-label*="viewOtherDates.cta"]' - if sb.cdp.is_element_visible(view_other_dates): - sb.cdp.click(view_other_dates) + if sb.is_element_visible(view_other_dates): + sb.click(view_other_dates) sb.sleep(5) if sb.is_element_visible("flexible-search-calendar"): print("*** Flight Calendar for El Al (Boston to Tel Aviv): ***") - print(sb.cdp.get_text("flexible-search-calendar")) + print(sb.get_text("flexible-search-calendar")) prices = [] - elements = sb.cdp.find_elements("span.matric-cell__content__price") + elements = sb.find_elements("span.matric-cell__content__price") if elements: print("*** Prices List: ***") for element in elements: @@ -50,32 +50,32 @@ print("*** Lowest Price: ***") lowest_price = prices[0] print(lowest_price) - sb.cdp.scroll_down(12) + sb.scroll_down(12) sb.sleep(1) - sb.cdp.find_element_by_text(lowest_price).click() + sb.find_element_by_text(lowest_price).click() sb.sleep(2) search_cell = 'button[aria-label*="Search.cell.buttonTitle"]' - sb.cdp.scroll_into_view(search_cell) + sb.scroll_into_view(search_cell) sb.sleep(1) - sb.cdp.click(search_cell) + sb.click(search_cell) sb.sleep(5) else: print("*** Lowest Prices: ***") departure_prices = "#uiFlightPanel0 div.ui-bound__price__value" return_prices = "#uiFlightPanel1 div.ui-bound__price__value" - elements = sb.cdp.find_elements(departure_prices) + elements = sb.find_elements(departure_prices) for element in elements: if "lowest price" in element.text: print("Departure Flight:") print(element.text) break - elements = sb.cdp.find_elements(return_prices) + elements = sb.find_elements(return_prices) for element in elements: if "lowest price" in element.text: print("Return Flight:") print(element.text) break - dates = sb.cdp.find_elements('div[class*="flight-date"]') + dates = sb.find_elements('div[class*="flight-date"]') if len(dates) == 2: print("*** Departure Date: ***") print(dates[0].text) diff --git a/examples/cdp_mode/raw_nordstrom.py b/examples/cdp_mode/raw_nordstrom.py index 2ef935cadff..96f7ff9cfb2 100644 --- a/examples/cdp_mode/raw_nordstrom.py +++ b/examples/cdp_mode/raw_nordstrom.py @@ -4,17 +4,17 @@ url = "https://www.nordstrom.com/" sb.activate_cdp_mode(url) sb.sleep(2.2) - sb.cdp.click("input#keyword-search-input") + sb.click("input#keyword-search-input") sb.sleep(0.8) search = "cocktail dresses for women teal" - sb.cdp.press_keys("input#keyword-search-input", search + "\n") + sb.press_keys("input#keyword-search-input", search + "\n") sb.sleep(2.2) for i in range(17): - sb.cdp.scroll_down(16) + sb.scroll_down(16) sb.sleep(0.14) print('*** Nordstrom Search for "%s":' % search) unique_item_text = [] - items = sb.cdp.find_elements("article") + items = sb.find_elements("article") for item in items: description = item.querySelector("article h3") if description and description.text not in unique_item_text: diff --git a/examples/presenter/uc_presentation_4.py b/examples/presenter/uc_presentation_4.py index b54176c624f..58049a43532 100644 --- a/examples/presenter/uc_presentation_4.py +++ b/examples/presenter/uc_presentation_4.py @@ -352,11 +352,11 @@ def test_presentation_4(self): ) self.begin_presentation(filename="uc_presentation.html") - with SB(uc=True, test=True, locale="en") as sb: + with SB(uc=True, test=True) as sb: url = "www.planetminecraft.com/account/sign_in/" sb.activate_cdp_mode(url) sb.sleep(2) - sb.uc_gui_click_captcha() + sb.solve_captcha() sb.wait_for_element_absent("input[disabled]") sb.sleep(2) @@ -371,8 +371,8 @@ def test_presentation_4(self): with SB(uc=True, test=True, locale="en") as sb: url = "https://www.cloudflare.com/login" sb.activate_cdp_mode(url) - sb.sleep(3) - sb.uc_gui_click_captcha() + sb.sleep(3.5) + sb.solve_captcha() sb.sleep(2.5) self.create_presentation(theme="serif", transition="none") @@ -387,12 +387,13 @@ def test_presentation_4(self): url = "https://gitlab.com/users/sign_in" sb.activate_cdp_mode(url) sb.sleep(2) - sb.uc_gui_click_captcha() + sb.solve_captcha() + # (The rest is for testing and demo purposes) sb.assert_text("Username", '[for="user_login"]', timeout=3) sb.assert_element('label[for="user_login"]') sb.highlight('button:contains("Sign in")') sb.highlight('h1:contains("GitLab")') - sb.post_message("SeleniumBase wasn't detected", duration=8) + sb.post_message("SeleniumBase wasn't detected", duration=4) self.create_presentation(theme="serif", transition="none") self.add_slide( @@ -404,7 +405,7 @@ def test_presentation_4(self): ' url = "https://gitlab.com/users/sign_in"\n' " sb.activate_cdp_mode(url)\n" " sb.sleep(2)\n" - " sb.uc_gui_click_captcha()\n\n" + " sb.solve_captcha()\n\n" " ...\n\n\n\n\n" ), ) @@ -417,7 +418,7 @@ def test_presentation_4(self): ' url = "https://gitlab.com/users/sign_in"\n' " sb.activate_cdp_mode(url)\n" " sb.sleep(2)\n" - " sb.uc_gui_click_captcha()\n\n" + " sb.solve_captcha()\n\n" ' sb.assert_text("Username", \'[for="user_login"]\',' ' timeout=3)\n' ' sb.assert_element(\'[for="user_login"]\')\n' @@ -434,12 +435,12 @@ def test_presentation_4(self): ) self.begin_presentation(filename="uc_presentation.html") - with SB(uc=True, test=True, locale="en") as sb: + with SB(uc=True, test=True) as sb: url = "https://www.bing.com/turing/captcha/challenge" sb.activate_cdp_mode(url) sb.sleep(1) - sb.uc_gui_click_captcha() - sb.sleep(2.5) + sb.solve_captcha() + sb.sleep(2) self.create_presentation(theme="serif", transition="none") self.add_slide("

Having fun yet?!?

") @@ -512,22 +513,21 @@ def test_presentation_4(self): 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.cdp.gui_click_and_hold("#px-captcha", 7.2) sb.sleep(3.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.remove_elements('[data-testid="skyline-ad"]') + sb.remove_elements('[data-testid="sba-container"]') print('*** Walmart Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] @@ -570,24 +570,24 @@ def test_presentation_4(self): sb.activate_cdp_mode(url) sb.sleep(2.5) sb.remove_element("div > div > article") - sb.cdp.scroll_into_view('input[type="search"]') + sb.scroll_into_view('input[type="search"]') close_btn = ".notification-alert-wrapper__close-button" - sb.cdp.click_if_visible(close_btn) - sb.cdp.click("input#search-suggestion-input") + sb.click_if_visible(close_btn) + sb.click("input#search-suggestion-input") sb.sleep(0.2) search = "Avocado Smoked Salmon" required_text = "Salmon" - sb.cdp.press_keys("input#search-suggestion-input", search) + sb.press_keys("input#search-suggestion-input", search) sb.sleep(0.8) - sb.cdp.click("#suggestion-0 a span") + sb.click("#suggestion-0 a span") sb.sleep(0.8) - sb.cdp.click_if_visible(close_btn) - sb.sleep(2.8) + sb.click_if_visible(close_btn) + sb.sleep(3.2) print('*** Albertsons Search for "%s":' % search) print(' (Results must contain "%s".)' % required_text) unique_item_text = [] item_selector = 'a[href*="/meal-plans-recipes/shop/"]' - items = sb.cdp.find_elements(item_selector) + items = sb.find_elements(item_selector) for item in items: sb.sleep(0.06) if required_text in item.text: @@ -610,34 +610,34 @@ def test_presentation_4(self): with SB(uc=True, test=True, locale="en", ad_block=True) as sb: url = "https://www.easyjet.com/en/" sb.activate_cdp_mode(url) - sb.sleep(2.5) - sb.cdp.click_if_visible("button#ensCloseBanner") + sb.sleep(2) + sb.click_if_visible("button#ensCloseBanner") sb.sleep(1.2) - sb.cdp.click('input[name="from"]') + sb.click('input[name="from"]') sb.sleep(1.2) - sb.cdp.type('input[name="from"]', "London") + sb.type('input[name="from"]', "London Gatwick") sb.sleep(0.6) - sb.cdp.click_if_visible("button#ensCloseBanner") + sb.click_if_visible("button#ensCloseBanner") sb.sleep(0.6) - sb.cdp.click('span[data-testid="airport-name"]') + sb.click('span[data-testid="airport-name"]') sb.sleep(1.2) - sb.cdp.type('input[name="to"]', "Venice") + sb.type('input[name="to"]', "Paris") sb.sleep(1.2) - sb.cdp.click('span[data-testid="airport-name"]') + sb.click('span[data-testid="airport-name"]') sb.sleep(1.2) - sb.cdp.click('input[name="when"]') + sb.click('input[name="when"]') sb.sleep(1.2) sb.cdp.click( '[data-testid="month"]:last-of-type' ' [aria-disabled="false"]' ) sb.sleep(1.2) - sb.cdp.click( + sb.click( '[data-testid="month"]:last-of-type' ' [aria-disabled="false"]' ) sb.sleep(1.2) - sb.cdp.click('button[data-testid="submit"]') + sb.click('button[data-testid="submit"]') sb.sleep(3.5) sb.connect() sb.sleep(4.2) @@ -724,26 +724,26 @@ def test_presentation_4(self): url = "https://www.bestwestern.com/en_US.html" sb.activate_cdp_mode(url) sb.sleep(2.5) - sb.cdp.click_if_visible(".onetrust-close-btn-handler") + sb.click_if_visible(".onetrust-close-btn-handler") sb.sleep(1) - sb.cdp.click("input#destination-input") + sb.click("input#destination-input") sb.sleep(2) location = "Palm Springs, CA, USA" - sb.cdp.press_keys("input#destination-input", location) + sb.press_keys("input#destination-input", location) sb.sleep(1) - sb.cdp.click("ul#google-suggestions li") + sb.click("ul#google-suggestions li") sb.sleep(1) - sb.cdp.click("button#btn-modify-stay-update") + sb.click("button#btn-modify-stay-update") sb.sleep(4) - sb.cdp.click("label#available-label") + sb.click("label#available-label") sb.sleep(2.5) print("Best Western Hotels in %s:" % location) - summary_details = sb.cdp.get_text("#summary-details-column") + summary_details = sb.get_text("#summary-details-column") dates = summary_details.split("DESTINATION")[-1] dates = dates.split(" CHECK-OUT")[0].strip() + " CHECK-OUT" dates = dates.replace(" ", " ") print("(Dates: %s)" % dates) - flip_cards = sb.cdp.select_all(".flipCard") + flip_cards = sb.select_all(".flipCard") for i, flip_card in enumerate(flip_cards): hotel = flip_card.query_selector(".hotelName") price = flip_card.query_selector(".priceSection") @@ -865,17 +865,17 @@ def test_presentation_4(self): url = "https://www.nordstrom.com/" sb.activate_cdp_mode(url) sb.sleep(2.2) - sb.cdp.click("input#keyword-search-input") + sb.click("input#keyword-search-input") sb.sleep(0.8) search = "cocktail dresses for women teal" - sb.cdp.press_keys("input#keyword-search-input", search + "\n") + sb.press_keys("input#keyword-search-input", search + "\n") sb.sleep(2.2) - for i in range(16): - sb.cdp.scroll_down(16) - sb.sleep(0.16) - print('\n\n*** Nordstrom Search for "%s":' % search) + for i in range(17): + sb.scroll_down(16) + sb.sleep(0.14) + print('*** Nordstrom Search for "%s":' % search) unique_item_text = [] - items = sb.cdp.find_elements("article") + items = sb.find_elements("article") for item in items: description = item.querySelector("article h3") if description and description.text not in unique_item_text: diff --git a/examples/raw_bing_captcha.py b/examples/raw_bing_captcha.py index 052d7cb4160..1cb47ee159b 100644 --- a/examples/raw_bing_captcha.py +++ b/examples/raw_bing_captcha.py @@ -6,4 +6,3 @@ sb.sleep(1) sb.solve_captcha() sb.sleep(2) - breakpoint() diff --git a/help_docs/uc_mode.md b/help_docs/uc_mode.md index 611f04290c9..1b3c6503aad 100644 --- a/help_docs/uc_mode.md +++ b/help_docs/uc_mode.md @@ -4,7 +4,7 @@ 👤 SeleniumBase UC Mode (Undetected-Chromedriver Mode) allows bots to appear human, which lets them evade detection from anti-bot services that try to block them or trigger CAPTCHAs on various websites. -> #### (For the successor to default UC Mode, see **[CDP Mode 🐙](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md)**) +> ### (For the successor to plain UC Mode, see **[CDP Mode 🐙](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md)**) --- @@ -28,11 +28,7 @@ ---- -👤 UC Mode is based on [undetected-chromedriver](https://github.com/ultrafunkamsterdam/undetected-chromedriver). UC Mode includes multiple updates, fixes, and improvements, such as: - -* Automatically changing user-agents to prevent detection. -* Automatically setting various Chromium args as needed. -* Has special `uc_*()` methods for bypassing CAPTCHAs. +👤 UC Mode is based on [undetected-chromedriver](https://github.com/ultrafunkamsterdam/undetected-chromedriver). UC Mode includes multiple updates, fixes, and improvements, such as having special uc_*() methods for bypassing CAPTCHAs. 👤 Here's a simple example with the Driver manager: @@ -110,10 +106,10 @@ with SB(uc=True, test=True, incognito=True, locale="en") as sb: submit_button = 'span:contains("Check Authority")' sb.uc_open_with_reconnect(url) # The bot-check is later sb.type(input_field, "github.com/seleniumbase/SeleniumBase") - sb.reconnect(0.1) - sb.uc_click(submit_button, reconnect_time=4) + sb.uc_click(submit_button, reconnect_time=3.25) sb.uc_gui_click_captcha() - sb.wait_for_text_not_visible("Checking", timeout=12) + sb.wait_for_text_not_visible("Checking", timeout=15) + sb.click_if_visible('button[data-cky-tag="close-button"]') sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")') sb.highlight('a:contains("Top 100 backlinks")') sb.set_messenger_theme(location="bottom_center") @@ -122,20 +118,6 @@ with SB(uc=True, test=True, incognito=True, locale="en") as sb: -👤 Here, the CAPTCHA appears after clicking to go to the sign-in screen: - -```python -from seleniumbase import SB - -with SB(uc=True, test=True, ad_block=True) as sb: - url = "https://www.thaiticketmajor.com/concert/" - sb.uc_open_with_reconnect(url, 6.111) - sb.uc_click("button.btn-signin", 4.1) - sb.uc_gui_click_captcha() -``` - - - -------- 👤 On Linux, use `sb.uc_gui_click_captcha()` to handle CAPTCHAs (Cloudflare Turnstiles): @@ -169,24 +151,21 @@ The 2nd print() should output V ### 👤 Here are some examples that use UC Mode: * [SeleniumBase/examples/verify_undetected.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/verify_undetected.py) -* [SeleniumBase/examples/raw_bing_captcha.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_bing_captcha.py) +* [SeleniumBase/examples/raw_turnstile.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_turnstile.py) +* [SeleniumBase/examples/raw_form_turnstile.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_form_turnstile.py) * [SeleniumBase/examples/raw_uc_mode.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_uc_mode.py) -* [SeleniumBase/examples/raw_cf.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_cf.py) + + -------- 👤 Here's an example where incognito=True is needed for bypassing detection: -* [SeleniumBase/examples/raw_pixelscan.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_pixelscan.py) - ```python from seleniumbase import SB with SB(uc=True, incognito=True, test=True) as sb: sb.driver.uc_open_with_reconnect("https://pixelscan.net/", 10) - sb.remove_elements("jdiv") # Remove chat widgets - sb.highlight("span.text-success", loops=8) - sb.highlight(".bot-detection-context", loops=10, scroll=False) sb.sleep(2) ``` @@ -194,16 +173,6 @@ with SB(uc=True, incognito=True, test=True) as sb: -------- -### 👤 Here are some UC Mode examples that bypass CAPTCHAs when clicking is required: -* [SeleniumBase/examples/raw_pyautogui.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_pyautogui.py) -* [SeleniumBase/examples/raw_turnstile.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_turnstile.py) -* [SeleniumBase/examples/raw_form_turnstile.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_form_turnstile.py) -* [SeleniumBase/examples/uc_cdp_events.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/uc_cdp_events.py) - - - --------- - ### 👤 Here are the SeleniumBase UC Mode methods: (**`--uc`** / **`uc=True`**) ```python diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index 578d6525627..f8502eb5fb7 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.44.6" +__version__ = "4.44.7" diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 0b2a92099da..4802f0d21ba 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -936,6 +936,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs): cdp.loop = cdp.get_event_loop() driver.cdp = cdp driver.solve_captcha = CDPM.solve_captcha + driver.find_element_by_text = CDPM.find_element_by_text driver._is_using_cdp = True diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index 53e9125ffbb..7041df57b08 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -2,6 +2,7 @@ import asyncio import fasteners import os +import random import re import sys import time @@ -479,7 +480,7 @@ def __press_keys(self, element, text): text = text[:-1] for key in text: element.send_keys(key) - time.sleep(0.044) + time.sleep(float(0.042 + (random.random() / 110.0))) if submit: element.send_keys("\r\n") time.sleep(0.044) @@ -938,7 +939,7 @@ def press_keys(self, selector, text, timeout=None): text = text.replace("\n", "\r") for key in text: element.send_keys(key) - time.sleep(0.044) + time.sleep(float(0.042 + (random.random() / 110.0))) if submit: element.send_keys("\r\n") time.sleep(0.044) @@ -1699,7 +1700,7 @@ def gui_press_keys(self, keys): self.__make_sure_pyautogui_lock_is_writable() for key in keys: pyautogui.press(key) - time.sleep(0.044) + time.sleep(float(0.042 + (random.random() / 110.0))) self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.sleep(0.025)) diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index d107dc0acbe..0c15b9f1460 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -5013,6 +5013,8 @@ def activate_cdp_mode(self, url=None, **kwargs): self.cdp = self.driver.cdp if hasattr(self.cdp, "solve_captcha"): self.solve_captcha = self.cdp.solve_captcha + if hasattr(self.cdp, "find_element_by_text"): + self.find_element_by_text = self.cdp.find_element_by_text self.undetectable = True def activate_recorder(self):