From 111f8eefbd3c6597ef1f37775e6f3ad81a604b91 Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Wed, 4 Sep 2024 22:48:41 -0400
Subject: [PATCH 1/5] Improve UC Mode methods
---
seleniumbase/core/browser_launcher.py | 90 +++++++++++----------------
1 file changed, 36 insertions(+), 54 deletions(-)
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 9e41ed3d9cd..413aec8d36c 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -861,10 +861,19 @@ def _uc_gui_click_captcha(
visible_iframe = False
if (
frame != "iframe"
- and driver.is_element_present('[name*="cf-turnstile-"]')
- and driver.is_element_present("%s div[style]" % frame)
+ and driver.is_element_present(
+ "%s .cf-turnstile-wrapper" % frame
+ )
+ ):
+ frame = "%s .cf-turnstile-wrapper" % frame
+ elif (
+ frame != "iframe"
+ and driver.is_element_present(
+ '%s [name*="cf-turnstile"]' % frame
+ )
+ and driver.is_element_present("%s div" % frame)
):
- frame = "%s div[style]" % frame
+ frame = "%s div" % frame
elif (
driver.is_element_present('[name*="cf-turnstile-"]')
and driver.is_element_present("div.spacer div")
@@ -877,47 +886,21 @@ def _uc_gui_click_captcha(
)
):
frame = '[data-testid*="challenge-"] div'
- elif (
- (
- driver.is_element_present('[name*="cf-turnstile-"]')
- or driver.is_element_present('[id*="cf-turnstile-"]')
- )
- and driver.is_element_present(
- 'form div div[style*="margin"][style*="padding"]'
- )
- ):
- frame = 'form div div[style*="margin"][style*="padding"]'
- elif (
- frame != "iframe"
- and driver.is_element_present(
- "%s .cf-turnstile-wrapper" % frame
- )
+ elif driver.is_element_present(
+ 'form div:not([class]):has(input[name*="cf-turn"])'
):
- frame = "%s .cf-turnstile-wrapper" % frame
+ frame = 'form div:not([class]):has(input[name*="cf-turn"])'
elif (
- frame != "iframe"
- and driver.is_element_present(
- '%s [name*="cf-turnstile"]' % frame
- )
- and driver.is_element_present("%s div" % frame)
+ driver.is_element_present('[src*="/turnstile/"]')
+ and driver.is_element_present("form div:not(:has(*))")
):
- frame = "%s div" % frame
+ frame = "form div:not(:has(*))"
elif driver.is_element_present(".cf-turnstile-wrapper"):
frame = ".cf-turnstile-wrapper"
elif driver.is_element_present(
'[data-callback="onCaptchaSuccess"]'
):
frame = '[data-callback="onCaptchaSuccess"]'
- elif (
- (
- driver.is_element_present('[name*="cf-turnstile-"]')
- or driver.is_element_present('[id*="cf-turnstile-"]')
- )
- and driver.is_element_present(
- 'div > div > [style*="margin"][style*="padding"]'
- )
- ):
- frame = 'div > div > [style*="margin"][style*="padding"]'
else:
return
if driver.is_element_present('form[class*=center]'):
@@ -1100,6 +1083,8 @@ def _uc_gui_handle_captcha(
driver.minimize_window()
driver.set_window_rect(win_x, win_y, width, height)
time.sleep(0.33)
+ tab_up_first = False
+ special_form = False
if ctype == "cf_t":
if (
driver.is_element_present(".cf-turnstile-wrapper iframe")
@@ -1128,26 +1113,18 @@ def _uc_gui_handle_captcha(
)
):
frame = '[data-testid*="challenge-"] div'
- elif (
- (
- driver.is_element_present('[name*="cf-turnstile-"]')
- or driver.is_element_present('[id*="cf-turnstile-"]')
- )
- and driver.is_element_present(
- 'form div div[style*="margin"][style*="padding"]'
- )
+ elif driver.is_element_present(
+ 'form div:not([class]):has(input[name*="cf-turn"])'
):
- frame = 'form div div[style*="margin"][style*="padding"]'
+ frame = 'form div:not([class]):has(input[name*="cf-turn"])'
+ tab_up_first = True
+ special_form = True
elif (
- (
- driver.is_element_present('[name*="cf-turnstile-"]')
- or driver.is_element_present('[id*="cf-turnstile-"]')
- )
- and driver.is_element_present(
- 'div > div > [style*="margin"][style*="padding"]'
- )
+ driver.is_element_present('[src*="/turnstile/"]')
+ and driver.is_element_present("form div:not(:has(*))")
):
- frame = 'div > div > [style*="margin"][style*="padding"]'
+ frame = "form div:not(:has(*))"
+ tab_up_first = True
else:
return
else:
@@ -1172,13 +1149,18 @@ def _uc_gui_handle_captcha(
if ctype == "g_rc":
selector = "span#recaptcha-anchor"
found_checkbox = False
- for i in range(24):
+ if tab_up_first:
+ for i in range(10):
+ pyautogui.hotkey("shift", "tab")
+ time.sleep(0.027)
+ for i in range(34):
pyautogui.press("\t")
- time.sleep(0.02)
+ time.sleep(0.027)
active_element_css = js_utils.get_active_element_css(driver)
if (
active_element_css.startswith(selector)
or active_element_css.endswith(" > div" * 2)
+ or (special_form and active_element_css.endswith(" div"))
):
found_checkbox = True
break
From fab150b88193abc73389f8bc40441a2084b00bb0 Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Wed, 4 Sep 2024 22:59:03 -0400
Subject: [PATCH 2/5] Update examples
---
examples/presenter/uc_presentation.py | 21 +++++++++--------
examples/presenter/uc_presentation_3.py | 30 ++++++++++++-------------
examples/raw_ahrefs.py | 4 ++--
examples/raw_cf.py | 8 +++----
examples/raw_order_tickets.py | 3 ++-
examples/raw_pixelscan.py | 12 +++++-----
6 files changed, 40 insertions(+), 38 deletions(-)
diff --git a/examples/presenter/uc_presentation.py b/examples/presenter/uc_presentation.py
index ba6247cdc0c..ae5ff4dc2f2 100644
--- a/examples/presenter/uc_presentation.py
+++ b/examples/presenter/uc_presentation.py
@@ -30,12 +30,12 @@ def test_presentation(self):
self.get_new_driver(undetectable=True)
url = "https://gitlab.com/users/sign_in"
try:
- self.driver.uc_open_with_reconnect(url, reconnect_time=3)
+ self.uc_open_with_reconnect(url, reconnect_time=3)
try:
self.assert_text("Username", '[for="user_login"]', timeout=3)
self.post_message("SeleniumBase wasn't detected", duration=4)
except Exception:
- self.driver.uc_open_with_reconnect(url, reconnect_time=4)
+ self.uc_open_with_reconnect(url, reconnect_time=4)
self.assert_text("Username", '[for="user_login"]', timeout=3)
self.post_message("SeleniumBase wasn't detected", duration=4)
finally:
@@ -249,8 +249,7 @@ def test_presentation(self):
code=(
"from seleniumbase import SB\n\n"
"with SB(uc=True) as sb:\n"
- ' sb.driver.get('
- '"https://seleniumbase.io/simple/login")\n'
+ ' sb.get("seleniumbase.io/simple/login")\n'
' sb.type("#username", "demo_user")\n'
' sb.type("#password", "secret_pass")\n'
' sb.click(\'a:contains("Sign in")\')\n'
@@ -266,7 +265,7 @@ def test_presentation(self):
try:
with SB(uc=True) as sb:
- sb.driver.get("https://seleniumbase.io/simple/login")
+ sb.get("https://seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
@@ -285,7 +284,7 @@ def test_presentation(self):
code=(
"from seleniumbase import SB\n\n"
"with SB(uc=True, demo=True) as sb:\n"
- ' sb.driver.get('
+ ' sb.get('
'"https://seleniumbase.io/simple/login")\n'
' sb.type("#username", "demo_user")\n'
' sb.type("#password", "secret_pass")\n'
@@ -301,7 +300,7 @@ def test_presentation(self):
try:
with SB(uc=True, demo=True) as sb:
- sb.driver.get("https://seleniumbase.io/simple/login")
+ sb.get("https://seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
@@ -340,11 +339,11 @@ def test_presentation(self):
code=(
"from seleniumbase import SB\n\n"
"with SB(uc=True) as sb:\n"
- ' sb.driver.get("https://nowsecure.nl/#relax")\n'
+ ' sb.get("https://nowsecure.nl/#relax")\n'
" sb.sleep(1)\n"
' if not sb.is_text_visible("OH YEAH, you passed", "h1"):\n'
" sb.get_new_driver(undetectable=True)\n"
- ' sb.driver.get("https://nowsecure.nl/#relax")\n'
+ ' sb.get("https://nowsecure.nl/#relax")\n'
" sb.sleep(1)\n"
' sb.activate_demo_mode()\n'
' sb.assert_text("OH YEAH, you passed!", "h1", timeout=3)\n'
@@ -354,10 +353,10 @@ def test_presentation(self):
try:
with SB(uc=True) as sb:
- sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
+ sb.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
if not sb.is_text_visible("OH YEAH, you passed", "h1"):
- sb.driver.uc_open_with_tab("https://nowsecure.nl/#relax")
+ sb.uc_open_with_tab("https://nowsecure.nl/#relax")
sb.sleep(1)
sb.activate_demo_mode()
sb.assert_text("OH YEAH, you passed!", "h1", timeout=3)
diff --git a/examples/presenter/uc_presentation_3.py b/examples/presenter/uc_presentation_3.py
index bc428759344..a3da212dcd4 100644
--- a/examples/presenter/uc_presentation_3.py
+++ b/examples/presenter/uc_presentation_3.py
@@ -18,7 +18,7 @@ def test_presentation_3(self):
self.begin_presentation(filename="uc_presentation.html")
self.open("https://seleniumbase.io/other/uc3_title.jpg")
- self.sleep(3)
+ self.sleep(2.5)
self.create_presentation(theme="serif", transition="fade")
self.add_slide(
@@ -108,11 +108,11 @@ def test_presentation_3(self):
"Special UC Mode methods for clicking CAPTCHAs:"
"
"
"
\n"
- "uc_gui_handle_captcha()
"
- "\n"
+ "sb.uc_gui_handle_captcha()
"
+ " \n"
"PyAutoGUI uses the TAB key with SPACEBAR.
\n\n"
- "uc_gui_click_captcha()
"
- "\n\n"
+ "sb.uc_gui_click_captcha()
"
+ " \n\n"
"PyAutoGUI clicks CAPTCHA with the mouse.
\n"
"(Note that you'll need to use this one on Linux!)\n"
"
\n\n\n\n"
@@ -171,7 +171,7 @@ def test_presentation_3(self):
"with SB(uc=True) as sb:\n"
' url = "https://gitlab.com/users/sign_in"\n'
" sb.uc_open_with_reconnect(url, 4)\n"
- " uc_gui_handle_captcha()\n\n"
+ " sb.uc_gui_handle_captcha()\n\n"
" ...\n\n\n\n\n\n"
),
)
@@ -183,7 +183,7 @@ def test_presentation_3(self):
"with SB(uc=True) as sb:\n"
' url = "https://gitlab.com/users/sign_in"\n'
" sb.uc_open_with_reconnect(url, 4)\n"
- " uc_gui_handle_captcha()\n\n"
+ " sb.uc_gui_handle_captcha()\n\n"
' sb.assert_text("Username", \'[for="user_login"]\','
' timeout=3)\n'
' sb.assert_element(\'[for="user_login"]\')\n'
@@ -221,7 +221,7 @@ def test_presentation_3(self):
"with SB(uc=True) as sb:\n"
' url = "https://gitlab.com/users/sign_in"\n'
" sb.uc_open_with_reconnect(url, 4)\n"
- " uc_gui_click_captcha()\n\n"
+ " sb.uc_gui_click_captcha()\n\n"
" ...\n\n\n\n\n"
),
)
@@ -233,7 +233,7 @@ def test_presentation_3(self):
"with SB(uc=True) as sb:\n"
' url = "https://gitlab.com/users/sign_in"\n'
" sb.uc_open_with_reconnect(url, 4)\n"
- " uc_gui_click_captcha()\n\n"
+ " sb.uc_gui_click_captcha()\n\n"
' sb.assert_text("Username", \'[for="user_login"]\','
' timeout=3)\n'
' sb.assert_element(\'[for="user_login"]\')\n'
@@ -252,8 +252,8 @@ def test_presentation_3(self):
"Navigate with stealth by calling "
"sb.uc_open_with_reconnect(url)
"
"
\n"
- "Use uc_gui_handle_captcha()
"
- " or uc_gui_click_captcha()
"
+ "Use sb.uc_gui_handle_captcha()
"
+ " or sb.uc_gui_click_captcha()
"
" to bypass CAPTCHAs as needed.\n"
"\n"
"
(It's that easy!)
\n"
@@ -263,7 +263,7 @@ def test_presentation_3(self):
"
"
"\n"
"- Previous tutorials mentioned this method:
"
- "uc_click(selector)
"
+ "sb.uc_click(selector)
"
"
\n"
"Although this method can no longer click a
"
"CAPTCHA directly, it should be used when
"
@@ -281,7 +281,7 @@ def test_presentation_3(self):
url = "https://ahrefs.com/website-authority-checker"
input_field = 'input[placeholder="Enter domain"]'
submit_button = 'span:contains("Check Authority")'
- sb.uc_open_with_reconnect(url, 2) # The bot-check is later
+ 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)
@@ -349,7 +349,7 @@ def test_presentation_3(self):
' url = "https://steamdb.info/"\n'
" sb.uc_open_with_reconnect(url, 3)\n"
' sb.uc_click("a.header-login span", 3)\n\n'
- " uc_gui_click_captcha()\n"
+ " sb.uc_gui_click_captcha()\n"
' sb.assert_text("Sign in", "button#js-sign-in",'
' timeout=3)\n'
' sb.uc_click("button#js-sign-in", 2)\n'
@@ -726,7 +726,7 @@ def test_presentation_3(self):
"đ¤ The plan to handle real-time bot-scanning đ¤
"
"
"
""
- '
uc_gui_click_captcha(frame="iframe", retry=False,'
+ 'sb.uc_gui_click_captcha(frame="iframe", retry=False,'
' blind=True)
'
'Set the third arg, `blind`, to `True` to force a retry'
' (if the first click failed) by clicking at the last known'
diff --git a/examples/raw_ahrefs.py b/examples/raw_ahrefs.py
index f09cf78d322..55898298458 100644
--- a/examples/raw_ahrefs.py
+++ b/examples/raw_ahrefs.py
@@ -4,12 +4,12 @@
url = "https://ahrefs.com/website-authority-checker"
input_field = 'input[placeholder="Enter domain"]'
submit_button = 'span:contains("Check Authority")'
- sb.uc_open_with_reconnect(url, 2) # The bot-check is later
+ 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_gui_click_captcha()
- sb.wait_for_text_not_visible("Checking", timeout=10)
+ sb.wait_for_text_not_visible("Checking", timeout=12)
sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")')
sb.highlight('a:contains("Top 100 backlinks")')
sb.set_messenger_theme(location="bottom_center")
diff --git a/examples/raw_cf.py b/examples/raw_cf.py
index b8a79149773..58df9df8973 100644
--- a/examples/raw_cf.py
+++ b/examples/raw_cf.py
@@ -1,14 +1,14 @@
"""SB Manager using UC Mode & PyAutoGUI for bypassing CAPTCHAs."""
from seleniumbase import SB
-with SB(uc=True, test=True) as sb:
+with SB(uc=True, test=True, locale_code="en") as sb:
url = "https://www.cloudflare.com/login"
- sb.uc_open_with_reconnect(url, 5)
+ sb.uc_open_with_reconnect(url, 5.5)
sb.uc_gui_handle_captcha() # PyAutoGUI press Tab and Spacebar
sb.sleep(2.5)
-with SB(uc=True, test=True) as sb:
+with SB(uc=True, test=True, locale_code="en") as sb:
url = "https://www.cloudflare.com/login"
- sb.uc_open_with_reconnect(url, 5)
+ sb.uc_open_with_reconnect(url, 5.5)
sb.uc_gui_click_captcha() # PyAutoGUI click. (Linux needs it)
sb.sleep(2.5)
diff --git a/examples/raw_order_tickets.py b/examples/raw_order_tickets.py
index 58017837a15..caabfd1c036 100644
--- a/examples/raw_order_tickets.py
+++ b/examples/raw_order_tickets.py
@@ -1,7 +1,8 @@
from seleniumbase import SB
with SB(uc=True, test=True, ad_block=True) as sb:
- url = "https://www.thaiticketmajor.com/concert/"
+ 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()
+ sb.sleep(2)
diff --git a/examples/raw_pixelscan.py b/examples/raw_pixelscan.py
index 1868ddff3db..03a140019f6 100644
--- a/examples/raw_pixelscan.py
+++ b/examples/raw_pixelscan.py
@@ -3,12 +3,14 @@
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.assert_text("No automation framework detected", "pxlscn-bot-detection")
- not_masking = "You are not masking your fingerprint"
- sb.assert_text(not_masking, "pxlscn-fingerprint-masking")
+ no_automation_detected = "No automation framework detected"
+ sb.assert_text(no_automation_detected, "pxlscn-bot-detection")
+ not_masking_text = "You are not masking your fingerprint"
+ sb.assert_text(not_masking_text, "pxlscn-fingerprint-masking")
sb.highlight("span.text-success", loops=8)
sb.sleep(1)
- sb.highlight("pxlscn-fingerprint-masking div", loops=9, scroll=False)
+ fingerprint_masking_div = "pxlscn-fingerprint-masking div"
+ sb.highlight(fingerprint_masking_div, loops=9, scroll=False)
sb.sleep(1)
- sb.highlight("div.bot-detection-context", loops=10, scroll=False)
+ sb.highlight(".bot-detection-context", loops=10, scroll=False)
sb.sleep(2)
From 2acd684455eb9839ea079bec2a4bcf25b3c63f8c Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Wed, 4 Sep 2024 23:00:35 -0400
Subject: [PATCH 3/5] Update the docs
---
README.md | 4 +++-
help_docs/thank_you.md | 31 ++++++++++++++++++-------------
help_docs/uc_mode.md | 33 ++++++++++++++++++++++++++++++---
3 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
index 95a112f7473..241e0190770 100755
--- a/README.md
+++ b/README.md
@@ -54,13 +54,15 @@
+SeleniumBase is the professional toolkit for web automation activities. Built for testing websites, bypassing CAPTCHAs, enhancing productivity, completing tasks, and scaling your business.
+
--------
đ Learn from [**over 200 examples** in the **SeleniumBase/examples/** folder](https://github.com/seleniumbase/SeleniumBase/tree/master/examples).
đ¤ Note that SeleniumBase UC Mode (Stealth Mode) has its own ReadMe.
-âšī¸ Scripts can be called via python
, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover & collect tests automatically).
+âšī¸ Scripts can be called via python
, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover, collect, and run tests automatically).
đ Here's my_first_test.py, which tests login, shopping, and checkout:
diff --git a/help_docs/thank_you.md b/help_docs/thank_you.md
index 87a0d36fe6f..ec860135f81 100644
--- a/help_docs/thank_you.md
+++ b/help_docs/thank_you.md
@@ -1,31 +1,36 @@
-[](https://github.com/seleniumbase/SeleniumBase/blob/master/README.md)
+
-### Thank you for flying with SeleniumBase! đĻ
+
+đŦđĢ Thank you for flying with SeleniumBase! đĻ
đ
--------
-SeleniumBase Playlist on YouTube:
+đŠī¸ SeleniumBase Playlist on YouTube:
+
+
-
+đŠī¸ SeleniumBase GitHub Home Page:
-SeleniumBase GitHub Repo Link:
+
-
+đŠī¸ SeleniumBase Discord Channel:
-SeleniumBase Gitter Chat Link:
+
-
+đŠī¸ SeleniumBase Gitter Chat:
+
+
Other Social Media Links:
-
-
-
-
+
--------
-
+
diff --git a/help_docs/uc_mode.md b/help_docs/uc_mode.md
index 2c8c1915bf7..2cb24a48f65 100644
--- a/help_docs/uc_mode.md
+++ b/help_docs/uc_mode.md
@@ -99,12 +99,12 @@ with SB(uc=True, test=True, incognito=True, locale_code="en") as sb:
url = "https://ahrefs.com/website-authority-checker"
input_field = 'input[placeholder="Enter domain"]'
submit_button = 'span:contains("Check Authority")'
- sb.uc_open_with_reconnect(url, 2) # The bot-check is later
+ 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_gui_click_captcha()
- sb.wait_for_text_not_visible("Checking", timeout=10)
+ sb.wait_for_text_not_visible("Checking", timeout=12)
sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")')
sb.highlight('a:contains("Top 100 backlinks")')
sb.set_messenger_theme(location="bottom_center")
@@ -158,10 +158,29 @@ The 2nd `print()` should output "Virtual Manager", which means that the automati
* [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_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)
+```
+
+--------
+
### đ¤ 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)
@@ -170,6 +189,8 @@ The 2nd `print()` should output "Virtual Manager", which means that the automati
+--------
+
### đ¤ Here are the driver
-specific methods added by SeleniumBase for UC Mode: `--uc` / uc=True
```python
@@ -240,6 +261,8 @@ driver.reconnect("breakpoint")
(Note that while the special UC Mode
breakpoint is active, you can't use Selenium
commands in the browser, and the browser can't detect Selenium
.)
+--------
+
đ¤ On Linux, you may need to use `uc_gui_click_captcha()` to successfully bypass a Cloudflare CAPTCHA. If there's more than one Cloudflare iframe on that website, then put the CSS Selector of an element that's above the iframe as the first arg to `uc_gui_click_captcha()`. This method uses `pyautogui`. In order for `pyautogui` to focus on the correct element, use `xvfb=True` / `--xvfb` to activate a special virtual display on Linux.
đ¤ `uc_gui_click_captcha()` auto-detects the CAPTCHA type before trying to click it. This is a generic method for both CF Turnstile and Google reCAPTCHA. It will use the code from `uc_gui_click_cf()` and `uc_gui_click_rc()` as needed.
@@ -248,6 +271,8 @@ driver.reconnect("breakpoint")
đ¤ `uc_gui_click_rc(frame="iframe", retry=False, blind=False)` is for reCAPTCHA. This may only work a few times before not working anymore... not because Selenium was detected, but because reCAPTCHA uses advanced AI to detect unusual activity, unlike the CF Turnstile, which only uses basic detection.
+--------
+
đ¤ To find out if UC Mode will work at all on a specific site (before adjusting for timing), load your site with the following script:
```python
@@ -259,6 +284,8 @@ with SB(uc=True) as sb:
(If you remain undetected while loading the page and performing manual actions, then you know you can create a working script once you swap the breakpoint with a time and add special methods like sb.uc_click
as needed.)
+--------
+
đ¤ Multithreaded UC Mode:
If you're using pytest
for multithreaded UC Mode (which requires using one of the pytest
[syntax formats](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md)), then all you have to do is set the number of threads when your script runs. (`-n NUM`) Eg:
@@ -343,7 +370,7 @@ The above JS method is used within the SeleniumBase
-As an ethical hacker / cybersecurity researcher who builds bots that bypass CAPTCHAs for sport, the CAPTCHA service that I personally recommend for keeping bots out is Google's reCAPTCHA:
+As an ethical hacker / cybersecurity researcher who builds bots that bypass CAPTCHAs for sport, the CAPTCHA service that I personally recommend for keeping bots out is Google reCAPTCHA:
From ea0c2a6ba2d9856f55d7391f3e9a92fc40908a3a Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Wed, 4 Sep 2024 23:01:22 -0400
Subject: [PATCH 4/5] Refresh Python dependencies
---
setup.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/setup.py b/setup.py
index 9c13e687615..968f434b044 100755
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@
print("\nERROR! Publishing to PyPI requires Python>=3.9")
sys.exit()
print("\n*** Checking code health with flake8:\n")
- os.system("python -m pip install 'flake8==7.1.0'")
+ os.system("python -m pip install 'flake8==7.1.1'")
flake8_status = os.system("flake8 --exclude=recordings,temp")
if flake8_status != 0:
print("\nERROR! Fix flake8 issues before publishing to PyPI!\n")
@@ -265,7 +265,7 @@
'cryptography==39.0.2;python_version<"3.9"',
'cryptography==43.0.1;python_version>="3.9"',
'cffi==1.15.1;python_version<"3.8"',
- 'cffi==1.17.0;python_version>="3.8"',
+ 'cffi==1.17.1;python_version>="3.8"',
"pycparser==2.22",
],
# pip install -e .[pillow]
From 86868127a64e0ef05ab4b892939c92de56acf69c Mon Sep 17 00:00:00 2001
From: Michael Mintz
Date: Wed, 4 Sep 2024 23:01:49 -0400
Subject: [PATCH 5/5] Version 4.30.3
---
seleniumbase/__version__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index c7124640cc9..0305db40ed2 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.30.2"
+__version__ = "4.30.3"