Skip to content

Commit c97c68b

Browse files
authored
Merge pull request #2911 from seleniumbase/add_uc_mode_clicking_methods
Add UC Mode clicking methods that use PyAutoGUI
2 parents 1c526f1 + 120b1ae commit c97c68b

File tree

11 files changed

+291
-36
lines changed

11 files changed

+291
-36
lines changed

examples/raw_gui_click.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""
2+
UC Mode now has uc_gui_click_cf(), which uses PyAutoGUI.
3+
An incomplete UserAgent is used to force CAPTCHA-solving.
4+
"""
5+
import sys
6+
from seleniumbase import SB
7+
8+
agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0"
9+
if "linux" in sys.platform:
10+
agent = None # Use the default UserAgent
11+
12+
with SB(uc=True, test=True, rtf=True, agent=agent) as sb:
13+
url = "https://www.virtualmanager.com/en/login"
14+
sb.uc_open_with_reconnect(url, 4)
15+
sb.uc_gui_click_cf() # Ready if needed!
16+
sb.assert_element('input[name*="email"]')
17+
sb.assert_element('input[name*="login"]')
18+
sb.set_messenger_theme(location="bottom_center")
19+
sb.post_message("SeleniumBase wasn't detected!")

examples/raw_order_tickets.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from seleniumbase import SB
22

3-
with SB(uc=True, test=True, ad_block_on=True) as sb:
3+
with SB(uc=True, test=True, ad_block=True) as sb:
44
url = "https://www.thaiticketmajor.com/concert/"
5-
sb.driver.uc_open_with_reconnect(url, 6.111)
6-
sb.driver.uc_click("button.btn-signin", 4.1)
5+
sb.uc_open_with_reconnect(url, 6.111)
6+
sb.uc_click("button.btn-signin", 4.1)
77
sb.switch_to_frame('iframe[title*="Cloudflare"]')
8-
sb.assert_element("div#success svg#success-icon")
8+
if not sb.is_element_visible("svg#success-icon"):
9+
sb.uc_gui_handle_cf()
10+
sb.switch_to_frame('iframe[title*="Cloudflare"]')
11+
sb.assert_element("svg#success-icon")
912
sb.switch_to_default_content()
1013
sb.set_messenger_theme(location="top_center")
1114
sb.post_message("SeleniumBase wasn't detected!")

examples/raw_uc_mode.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33

44
with SB(uc=True, test=True) as sb:
55
url = "https://gitlab.com/users/sign_in"
6-
sb.driver.uc_open_with_reconnect(url, 3)
7-
if not sb.is_text_visible("Username", '[for="user_login"]'):
8-
sb.driver.uc_open_with_reconnect(url, 4)
6+
sb.uc_open_with_reconnect(url, 4)
7+
sb.uc_gui_click_cf()
98
sb.assert_text("Username", '[for="user_login"]', timeout=3)
109
sb.assert_element('label[for="user_login"]')
1110
sb.highlight('button:contains("Sign in")')

help_docs/method_summary.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,22 @@ self.execute_async_script(script, timeout=None)
223223

224224
self.safe_execute_script(script, *args, **kwargs)
225225

226+
self.get_gui_element_rect(selector, by="css selector")
227+
228+
self.get_gui_element_center(selector, by="css selector")
229+
230+
self.get_window_rect()
231+
232+
self.get_window_size()
233+
234+
self.get_window_position()
235+
226236
self.set_window_rect(x, y, width, height)
227237

228238
self.set_window_size(width, height)
229239

240+
self.set_window_position(x, y)
241+
230242
self.maximize_window()
231243

232244
self.switch_to_frame(frame="iframe", timeout=None)
@@ -1062,6 +1074,10 @@ driver.uc_gui_press_keys(keys) # Use PyAutoGUI to press a list of keys
10621074

10631075
driver.uc_gui_write(text) # Similar to uc_gui_press_keys(), but faster
10641076

1077+
driver.uc_gui_click_x_y(x, y, timeframe=0.25) # PyAutoGUI click screen
1078+
1079+
driver.uc_gui_click_cf(frame="iframe", retry=False, blind=False) # (*)
1080+
10651081
driver.uc_gui_handle_cf(frame="iframe") # PyAutoGUI click CF Turnstile
10661082

10671083
driver.uc_switch_to_frame(frame="iframe") # Stealthy switch_to_frame()

help_docs/uc_mode.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ from seleniumbase import SB
4242

4343
with SB(uc=True) as sb:
4444
url = "https://gitlab.com/users/sign_in"
45-
sb.driver.uc_open_with_reconnect(url, 3)
45+
sb.uc_open_with_reconnect(url, 3)
4646
```
4747

4848
👤 Here's a longer example, which includes a retry if the CAPTCHA isn't bypassed on the first attempt:
@@ -52,9 +52,9 @@ from seleniumbase import SB
5252

5353
with SB(uc=True, test=True) as sb:
5454
url = "https://gitlab.com/users/sign_in"
55-
sb.driver.uc_open_with_reconnect(url, 3)
55+
sb.uc_open_with_reconnect(url, 3)
5656
if not sb.is_text_visible("Username", '[for="user_login"]'):
57-
sb.driver.uc_open_with_reconnect(url, 4)
57+
sb.uc_open_with_reconnect(url, 4)
5858
sb.assert_text("Username", '[for="user_login"]', timeout=3)
5959
sb.highlight('label[for="user_login"]', loops=3)
6060
sb.post_message("SeleniumBase wasn't detected", duration=4)
@@ -78,6 +78,8 @@ with SB(uc=True, test=True) as sb:
7878

7979
<img src="https://seleniumbase.github.io/other/turnstile_click.jpg" title="SeleniumBase" width="440">
8080

81+
If running on a Linux server, `uc_gui_handle_cf()` might not be good enough. Switch to `uc_gui_click_cf()` to be more stealthy.
82+
8183
👤 Here's an example <b>where the CAPTCHA appears after submitting a form</b>:
8284

8385
```python
@@ -87,10 +89,10 @@ with SB(uc=True, test=True, locale_code="en") as sb:
8789
url = "https://ahrefs.com/website-authority-checker"
8890
input_field = 'input[placeholder="Enter domain"]'
8991
submit_button = 'span:contains("Check Authority")'
90-
sb.driver.uc_open_with_reconnect(url, 1) # The bot-check is later
92+
sb.uc_open_with_reconnect(url, 1) # The bot-check is later
9193
sb.type(input_field, "github.com/seleniumbase/SeleniumBase")
92-
sb.driver.reconnect(0.1)
93-
sb.driver.uc_click(submit_button, reconnect_time=4)
94+
sb.reconnect(0.1)
95+
sb.uc_click(submit_button, reconnect_time=4)
9496
sb.wait_for_text_not_visible("Checking", timeout=10)
9597
sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")')
9698
sb.highlight('a:contains("Top 100 backlinks")')
@@ -105,10 +107,10 @@ with SB(uc=True, test=True, locale_code="en") as sb:
105107
```python
106108
from seleniumbase import SB
107109

108-
with SB(uc=True, test=True, ad_block_on=True) as sb:
110+
with SB(uc=True, test=True, ad_block=True) as sb:
109111
url = "https://www.thaiticketmajor.com/concert/"
110-
sb.driver.uc_open_with_reconnect(url, 5.5)
111-
sb.driver.uc_click("button.btn-signin", 4)
112+
sb.uc_open_with_reconnect(url, 5.5)
113+
sb.uc_click("button.btn-signin", 4)
112114
sb.switch_to_frame('iframe[title*="Cloudflare"]')
113115
sb.assert_element("div#success svg#success-icon")
114116
sb.switch_to_default_content()
@@ -118,7 +120,7 @@ with SB(uc=True, test=True, ad_block_on=True) as sb:
118120

119121
<img src="https://seleniumbase.github.io/other/ttm_bypass.png" title="SeleniumBase" width="540">
120122

121-
👤 <b>On Linux</b>, use `sb.uc_gui_handle_cf()` to handle Cloudflare Turnstiles:
123+
👤 <b>On Linux</b>, use `sb.uc_gui_click_cf()` to handle Cloudflare Turnstiles:
122124

123125
```python
124126
from seleniumbase import SB
@@ -127,15 +129,15 @@ with SB(uc=True, test=True) as sb:
127129
url = "https://www.virtualmanager.com/en/login"
128130
sb.uc_open_with_reconnect(url, 4)
129131
print(sb.get_page_title())
130-
sb.uc_gui_handle_cf() # Ready if needed!
132+
sb.uc_gui_click_cf() # Ready if needed!
131133
print(sb.get_page_title())
132134
sb.assert_element('input[name*="email"]')
133135
sb.assert_element('input[name*="login"]')
134136
sb.set_messenger_theme(location="bottom_center")
135137
sb.post_message("SeleniumBase wasn't detected!")
136138
```
137139

138-
<a href="https://github.com/mdmintz/undetected-testing/actions/runs/9637461606/job/26576722411"><img width="540" alt="uc_gui_handle_cf on Linux" src="https://github.com/seleniumbase/SeleniumBase/assets/6788579/6aceb2a3-2a32-4521-b30a-f79446d2ce28"></a>
140+
<a href="https://github.com/mdmintz/undetected-testing/actions/runs/9637461606/job/26576722411"><img width="540" alt="uc_gui_click_cf on Linux" src="https://github.com/seleniumbase/SeleniumBase/assets/6788579/6aceb2a3-2a32-4521-b30a-f79446d2ce28"></a>
139141

140142
The 2nd `print()` should output "Virtual Manager", which means that the automation successfully passed the Turnstile.
141143

@@ -188,6 +190,10 @@ driver.uc_gui_press_keys(keys)
188190

189191
driver.uc_gui_write(text)
190192

193+
driver.uc_gui_click_x_y(x, y, timeframe=0.25)
194+
195+
driver.uc_gui_click_cf(frame="iframe", retry=False, blind=False)
196+
191197
driver.uc_gui_handle_cf(frame="iframe")
192198

193199
driver.uc_switch_to_frame(frame, reconnect_time=None)
@@ -225,7 +231,9 @@ driver.reconnect("breakpoint")
225231

226232
(Note that while the special <b><code translate="no">UC Mode</code></b> breakpoint is active, you can't use <b><code translate="no">Selenium</code></b> commands in the browser, and the browser can't detect <b><code translate="no">Selenium</code></b>.)
227233

228-
👤 On Linux, you may need to use `driver.uc_gui_handle_cf()` to successfully bypass a Cloudflare CAPTCHA. If there's more than one iframe on that website (and Cloudflare isn't the first one) then put the CSS Selector of that iframe as the first arg to `driver.uc_gui_handle_cf()`. 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.
234+
👤 On Linux, you may need to use `driver.uc_gui_click_cf()` to successfully bypass a Cloudflare CAPTCHA. If there's more than one iframe on that website (and Cloudflare isn't the first one) then put the CSS Selector of that iframe as the first arg to `driver.uc_gui_click_cf()`. 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.
235+
236+
👤 `driver.uc_gui_click_cf(frame="iframe", retry=False, blind=False)` has three args. (All optional). The first one, `frame`, lets you specify the iframe in case the CAPTCHA is not located in the first iframe on the page. The second one, `retry`, lets you retry the click after reloading the page if the first one didn't work (and a CAPTCHA is still present after the page reload). The third arg, `blind`, will retry after a page reload (if the first click failed) by clicking at the last known coordinates of the CAPTCHA checkbox without confirming first with Selenium that a CAPTCHA is still on the page.
229237

230238
👤 To find out if <b translate="no">UC Mode</b> will work at all on a specific site (before adjusting for timing), load your site with the following script:
231239

mkdocs_build/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ lxml==5.2.2
2020
pyquery==2.0.0
2121
readtime==3.0.0
2222
mkdocs==1.6.0
23-
mkdocs-material==9.5.27
23+
mkdocs-material==9.5.28
2424
mkdocs-exclude-search==0.6.6
2525
mkdocs-simple-hooks==0.1.5
2626
mkdocs-material-extensions==1.3.1

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ pip>=24.1.1;python_version>="3.8"
33
packaging>=24.0;python_version<"3.8"
44
packaging>=24.1;python_version>="3.8"
55
setuptools>=68.0.0;python_version<"3.8"
6-
setuptools>=70.1.1;python_version>="3.8"
6+
setuptools>=70.2.0;python_version>="3.8"
77
wheel>=0.42.0;python_version<"3.8"
88
wheel>=0.43.0;python_version>="3.8"
99
attrs>=23.2.0
10-
certifi>=2024.6.2
10+
certifi>=2024.7.4
1111
exceptiongroup>=1.2.1
1212
filelock>=3.12.2;python_version<"3.8"
1313
filelock>=3.15.4;python_version>="3.8"
@@ -29,7 +29,7 @@ sniffio==1.3.1
2929
h11==0.14.0
3030
outcome==1.3.0.post0
3131
trio==0.22.2;python_version<"3.8"
32-
trio==0.25.1;python_version>="3.8"
32+
trio==0.26.0;python_version>="3.8"
3333
trio-websocket==0.11.1
3434
wsproto==1.2.0
3535
websocket-client==1.8.0;python_version>="3.8"

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.28.3"
2+
__version__ = "4.28.4"

0 commit comments

Comments
 (0)