Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/cdp_mode/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ sb.cdp.select_all(selector, timeout=None)
sb.cdp.find_elements(selector, timeout=None)
sb.cdp.find_visible_elements(selector, timeout=None)
sb.cdp.click(selector, timeout=None)
sb.cdp.click_if_visible(selector)
sb.cdp.click_if_visible(selector, timeout=0)
sb.cdp.click_visible_elements(selector, limit=0)
sb.cdp.click_nth_element(selector, number)
sb.cdp.click_nth_visible_element(selector, number)
Expand Down
16 changes: 16 additions & 0 deletions examples/cdp_mode/raw_cdp_reddit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Reddit Search / Bypasses reCAPTCHA."""
from seleniumbase import sb_cdp

search = "reddit+scraper"
url = f"https://www.reddit.com/r/webscraping/search/?q={search}"
sb = sb_cdp.Chrome(url, use_chromium=True)
sb.solve_captcha() # Might not be needed
post_title = '[data-testid="post-title"]'
sb.wait_for_element(post_title)
for i in range(8):
sb.scroll_down(25)
sb.sleep(0.2)
posts = sb.select_all(post_title)
print('*** Reddit Posts for "%s":' % search)
for post in posts:
print("* " + post.text)
4 changes: 2 additions & 2 deletions examples/cdp_mode/raw_cf.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
"""Using CDP Mode with PyAutoGUI to bypass CAPTCHAs."""
from seleniumbase import SB

with SB(uc=True, test=True, locale="en", guest=True) as sb:
with SB(uc=True, test=True, guest=True) as sb:
url = "https://www.cloudflare.com/login"
sb.activate_cdp_mode(url)
sb.sleep(3)
sb.uc_gui_handle_captcha() # PyAutoGUI press Tab and Spacebar
sb.sleep(3)

with SB(uc=True, test=True, locale="en", guest=True) as sb:
with SB(uc=True, test=True, guest=True) as sb:
url = "https://www.cloudflare.com/login"
sb.activate_cdp_mode(url)
sb.sleep(4)
Expand Down
3 changes: 2 additions & 1 deletion examples/cdp_mode/raw_cf_captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
with SB(uc=True, test=True, guest=True) as sb:
url = "https://www.cloudflare.com/login"
sb.activate_cdp_mode(url)
sb.sleep(3)
sb.wait_for_element('div[data-testid*="challenge-widget"]')
sb.sleep(1.5)
sb.solve_captcha()
sb.sleep(3)
28 changes: 28 additions & 0 deletions examples/cdp_mode/raw_gas_records.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""(Bypasses the Imperva/Incapsula hCaptcha)"""
from seleniumbase import SB

with SB(uc=True, test=True) as sb:
url = (
"https://www.gassaferegister.co.uk/gas-safety"
"/gas-safety-certificates-records/building-regulations-certificate"
"/order-replacement-building-regulations-certificate/"
)
sb.activate_cdp_mode(url)
sb.sleep(0.6)
sb.solve_captcha()
sb.sleep(1)
sb.wait_for_element("#SearchTerm", timeout=5)
sb.sleep(2)
allow_cookies = 'button:contains("Allow all cookies")'
sb.click_if_visible(allow_cookies, timeout=2)
sb.sleep(1.2)
sb.press_keys("#SearchTerm", "Hydrogen")
sb.sleep(0.5)
sb.click("button.search-button")
sb.sleep(3)
results = sb.find_elements("div.search-result")
for result in results:
print(result.text.replace(" " * 12, " ").strip())
print()
sb.scroll_to_bottom()
sb.sleep(1)
7 changes: 4 additions & 3 deletions examples/raw_cf.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""SB Manager using CDP Mode for bypassing CAPTCHAs."""
from seleniumbase import SB

with SB(uc=True, test=True, locale="en", guest=True) as sb:
with SB(uc=True, test=True, guest=True) as sb:
url = "https://www.cloudflare.com/login"
sb.activate_cdp_mode(url)
sb.sleep(4)
sb.wait_for_element('div[data-testid*="challenge-widget"]')
sb.sleep(1.5)
sb.solve_captcha()
sb.sleep(2.5)
sb.sleep(3)
2 changes: 1 addition & 1 deletion mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ click==8.3.1
ghp-import==2.1.0
watchdog==6.0.0
cairocffi==1.7.1
pathspec==1.0.1
pathspec==1.0.3
Babel==2.17.0
paginate==0.5.7
mkdocs==1.6.1
Expand Down
7 changes: 4 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ wheel>=0.45.1
attrs>=25.4.0
certifi>=2026.1.4
exceptiongroup>=1.3.1
websockets>=15.0.1
websockets~=15.0.1;python_version<"3.10"
websockets>=16.0;python_version>="3.10"
filelock~=3.19.1;python_version<"3.10"
filelock>=3.20.2;python_version>="3.10"
filelock>=3.20.3;python_version>="3.10"
fasteners>=0.20
mycdp>=1.3.2
pynose>=1.5.5
Expand All @@ -26,7 +27,7 @@ pyyaml>=6.0.3
pygments>=2.19.2
pyreadline3>=3.5.4;platform_system=="Windows"
tabcompleter>=1.4.0
pdbp>=1.8.1
pdbp>=1.8.2
idna>=3.11
chardet==5.2.0
charset-normalizer>=3.4.4,<4
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.45.10"
__version__ = "4.45.11"
10 changes: 9 additions & 1 deletion seleniumbase/console_scripts/sb_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,15 @@ def main(override=None, intel_for_uc=None, force_uc=None):
else:
url_request = get_cft_latest_versions_per_milestone()
if not force_cft and url_request.ok:
fver = get_cft_latest_version_from_milestone(use_version)
try:
fver = get_cft_latest_version_from_milestone(
use_version
)
except KeyError:
use_version = str(int(use_version) - 1)
fver = get_cft_latest_version_from_milestone(
use_version
)
found_chromedriver = True
use_version = str(fver)
if use_version == latest_version:
Expand Down
40 changes: 28 additions & 12 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -1338,12 +1338,12 @@ def _uc_gui_click_captcha(
_on_a_captcha_page = None
if ctype == "cf_t":
if not _on_a_cf_turnstile_page(driver):
return
return False
else:
_on_a_captcha_page = _on_a_cf_turnstile_page
elif ctype == "g_rc":
if not _on_a_g_recaptcha_page(driver):
return
return False
else:
_on_a_captcha_page = _on_a_g_recaptcha_page
else:
Expand All @@ -1354,7 +1354,7 @@ def _uc_gui_click_captcha(
ctype = "cf_t"
_on_a_captcha_page = _on_a_cf_turnstile_page
else:
return
return False
install_pyautogui_if_missing(driver)
import pyautogui
pyautogui = get_configured_pyautogui(pyautogui)
Expand Down Expand Up @@ -1505,7 +1505,7 @@ def _uc_gui_click_captcha(
):
frame = "div:not([class]) > div:not([class])"
else:
return
return False
if (
driver.is_element_present("form")
and (
Expand Down Expand Up @@ -1605,9 +1605,9 @@ def _uc_gui_click_captcha(
if driver.is_connected():
driver.switch_to_frame("iframe")
else:
return
return False
if not i_x or not i_y:
return
return False
try:
if ctype == "g_rc" and not driver.is_connected():
x = (i_x + 29) * width_ratio
Expand Down Expand Up @@ -1638,7 +1638,7 @@ def _uc_gui_click_captcha(
try:
driver.switch_to.default_content()
except Exception:
return
return False
if x and y:
sb_config._saved_cf_x_y = (x, y)
if not __is_cdp_swap_needed(driver):
Expand All @@ -1652,7 +1652,7 @@ def _uc_gui_click_captcha(
_uc_gui_click_x_y(driver, x, y, timeframe=0.32)
if __is_cdp_swap_needed(driver):
time.sleep(float(constants.UC.RECONNECT_TIME) / 2.0)
return
return True
reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.6
if IS_LINUX:
reconnect_time = constants.UC.RECONNECT_TIME + 0.2
Expand Down Expand Up @@ -1684,17 +1684,17 @@ def _uc_gui_click_captcha(
try:
driver.switch_to_frame("iframe")
except Exception:
return
return False
checkbox_success = None
if ctype == "cf_t":
checkbox_success = "#success-icon"
elif ctype == "g_rc":
checkbox_success = "span.recaptcha-checkbox-checked"
else:
return # If this line is reached, ctype wasn't set
return False # If line is reached, ctype wasn't set
if driver.is_element_visible("#success-icon"):
driver.switch_to.parent_frame(checkbox_success)
return
return True
if blind:
driver.uc_open_with_disconnect(driver.get_current_url(), 3.8)
if __is_cdp_swap_needed(driver) and _on_a_captcha_page(driver):
Expand All @@ -1708,6 +1708,7 @@ def _uc_gui_click_captcha(
_uc_gui_click_x_y(driver, x, y, timeframe=0.32)
if not cdp_mode_on_at_start:
driver.reconnect(reconnect_time)
return True


def uc_gui_click_captcha(driver, frame="iframe", retry=False, blind=False):
Expand Down Expand Up @@ -5244,6 +5245,15 @@ def get_local_driver(
or driver_version == "keep"
):
browser_driver_close_match = True
one_off_chromium = False
if (
hasattr(sb_config, "binary_location")
and sb_config.binary_location == "_chromium_"
):
with suppress(Exception):
one_off_chromium_ver = int(use_version.split(".")[0]) - 1
if one_off_chromium_ver == int(ch_driver_version):
one_off_chromium = True
# If not ARM MAC and need to use uc_driver (and it's missing),
# and already have chromedriver with the correct version,
# then copy chromedriver to uc_driver (and it'll get patched).
Expand Down Expand Up @@ -5275,25 +5285,31 @@ def get_local_driver(
and use_version != "latest" # Browser version detected
and (ch_driver_version or not local_ch_exists)
and (
use_version.split(".")[0] != ch_driver_version
(
use_version.split(".")[0] != ch_driver_version
and not one_off_chromium
)
or (
not local_ch_exists
and use_version.isnumeric()
and int(use_version) >= 115
and not browser_driver_close_match
and not one_off_chromium
)
)
)
or (
use_uc
and use_version != "latest" # Browser version detected
and uc_driver_version != use_version
and not one_off_chromium
)
or (
full_ch_driver_version # Also used for the uc_driver
and driver_version
and len(str(driver_version).split(".")) == 4
and full_ch_driver_version != driver_version
and not one_off_chromium
)
):
# chromedriver download needed in the seleniumbase/drivers dir
Expand Down
Loading