Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c909b1a

Browse files
authored
Merge pull request #3312 from seleniumbase/cdp-mode-patch-16
CDP Mode - Patch 16
2 parents 667602c + 23a5876 commit c909b1a

File tree

11 files changed

+95
-68
lines changed

11 files changed

+95
-68
lines changed

‎examples/cdp_mode/ReadMe.md

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,28 +22,30 @@
2222
* Backwards compatibility for existing UC Mode scripts.
2323
* More configuration options when launching browsers.
2424
* More methods. (And bug-fixes for existing methods.)
25+
* `PyAutoGUI` integration for advanced stealth abilities.
2526
* Faster response time for support. (Eg. [Discord Chat](https://discord.gg/EdhQTn3EyE))
2627

2728
--------
2829

29-
### 🐙 <b translate="no">CDP Mode</b> usage:
30+
### 🐙 <b translate="no">CDP Mode</b> Usage:
3031

3132
* **`sb.activate_cdp_mode(url)`**
3233

3334
> (Call that from a **UC Mode** script)
3435
3536
That disconnects WebDriver from Chrome (which prevents detection), and gives you access to `sb.cdp` methods (which don't trigger anti-bot checks).
3637

37-
### 🐙 Here are some common `sb.cdp` methods:
38+
### 🐙 Here are a few common `sb.cdp` methods:
3839

3940
* `sb.cdp.click(selector)`
4041
* `sb.cdp.click_if_visible(selector)`
42+
* `sb.cdp.gui_click_element(selector)`
4143
* `sb.cdp.type(selector, text)`
4244
* `sb.cdp.press_keys(selector, text)`
4345
* `sb.cdp.select_all(selector)`
4446
* `sb.cdp.get_text(selector)`
4547

46-
When `type()` is too fast, use the slower `press_keys()` to avoid detection. You can also use `sb.sleep(seconds)` to slow things down.
48+
When `type()` is too fast, use the slower `press_keys()` to avoid detection. You can also use `sb.sleep(seconds)` to slow things down. Methods that start with `sb.cdp.gui` use `PyAutoGUI` for interaction.
4749

4850
To use WebDriver methods again, call:
4951

@@ -63,17 +65,13 @@ To find out if WebDriver is connected or disconnected, call:
6365

6466
--------
6567

66-
### 🐙 <b translate="no">CDP Mode</b> examples:
68+
### 🐙 <b translate="no">CDP Mode</b> Examples ([SeleniumBase/examples/cdp_mode](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode))
6769

68-
> [SeleniumBase/examples/cdp_mode](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode)
69-
70-
### 🔖 Example 1: (Pokemon site using Incapsula/Imperva protection with invisible reCAPTCHA)
71-
72-
> [SeleniumBase/examples/cdp_mode/raw_pokemon.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_pokemon.py)
70+
<p><div /></p>
7371

7472
<div></div>
7573
<details>
76-
<summary> ▶️ (<b>Click to expand code preview</b>)</summary>
74+
<summary> ▶️ 🔖 <b>Example 1: (Pokemon site using Incapsula/Imperva protection with invisible reCAPTCHA)</b></summary>
7775

7876
```python
7977
from seleniumbase import SB
@@ -127,13 +125,12 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
127125

128126
</details>
129127

130-
### 🔖 Example 2: (Hyatt site using Kasada protection)
128+
> [SeleniumBase/examples/cdp_mode/raw_pokemon.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_pokemon.py)
131129
132-
> [SeleniumBase/examples/cdp_mode/raw_hyatt.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_hyatt.py)
133130

134131
<div></div>
135132
<details>
136-
<summary> ▶️ (<b>Click to expand code preview</b>)</summary>
133+
<summary> ▶️ 🔖 <b>Example 2: (Hyatt site using Kasada protection)</b></summary>
137134

138135
```python
139136
from seleniumbase import SB
@@ -157,30 +154,30 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
157154
sb.sleep(1)
158155
sb.cdp.click('button[data-locator="find-hotels"]')
159156
sb.sleep(5)
160-
hotel_names = sb.cdp.select_all(
161-
'div[data-booking-status="BOOKABLE"] [class*="HotelCard_header"]'
162-
)
163-
hotel_prices = sb.cdp.select_all(
164-
'div[data-booking-status="BOOKABLE"] div.rate'
165-
)
166-
sb.assert_true(len(hotel_names) == len(hotel_prices))
157+
card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]'
158+
hotels = sb.cdp.select_all(card_info)
167159
print("Hyatt Hotels in %s:" % location)
168160
print("(" + sb.cdp.get_text("ul.b-color_text-white") + ")")
169-
if len(hotel_names) == 0:
161+
if len(hotels) == 0:
170162
print("No availability over the selected dates!")
171-
for i, hotel in enumerate(hotel_names):
172-
print("* %s: %s => %s" % (i + 1, hotel.text, hotel_prices[i].text))
163+
for hotel in hotels:
164+
info = hotel.text.strip()
165+
if "Avg/Night" in info and not info.startswith("Rates from"):
166+
name = info.split(" (")[0].split(" + ")[0].split(" Award Cat")[0]
167+
price = "?"
168+
if "Rates from : " in info:
169+
price = info.split("Rates from : ")[1].split(" Avg/Night")[0]
170+
print("* %s => %s" % (name, price))
173171
```
174172

175173
</details>
176174

177-
### 🔖 Example 3: (BestWestern site using DataDome protection)
175+
> [SeleniumBase/examples/cdp_mode/raw_hyatt.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_hyatt.py)
178176
179-
* [SeleniumBase/examples/cdp_mode/raw_bestwestern.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_bestwestern.py)
180177

181178
<div></div>
182179
<details>
183-
<summary> ▶️ (<b>Click to expand code preview</b>)</summary>
180+
<summary> ▶️ 🔖 <b>Example 3: (BestWestern site using DataDome protection)</b></summary>
184181

185182
```python
186183
from seleniumbase import SB
@@ -218,13 +215,12 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
218215

219216
</details>
220217

221-
### 🔖 Example 4: (Walmart site using Akamai protection with PerimeterX)
218+
> [SeleniumBase/examples/cdp_mode/raw_bestwestern.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_bestwestern.py)
222219
223-
* [SeleniumBase/examples/cdp_mode/raw_walmart.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_walmart.py)
224220

225221
<div></div>
226222
<details>
227-
<summary> ▶️ (<b>Click to expand code preview</b>)</summary>
223+
<summary> ▶️ 🔖 <b>Example 4: (Walmart site using Akamai protection with PerimeterX)</b></summary>
228224

229225
```python
230226
from seleniumbase import SB
@@ -264,13 +260,12 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
264260

265261
</details>
266262

267-
### 🔖 Example 5: (Nike site using Shape Security)
263+
> [SeleniumBase/examples/cdp_mode/raw_walmart.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_walmart.py)
268264
269-
* [SeleniumBase/examples/cdp_mode/raw_nike.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_nike.py)
270265

271266
<div></div>
272267
<details>
273-
<summary> ▶️ (<b>Click to expand code preview</b>)</summary>
268+
<summary> ▶️ 🔖 <b>Example 5: (Nike site using Shape Security)</b></summary>
274269

275270
```python
276271
from seleniumbase import SB
@@ -294,13 +289,17 @@ with SB(uc=True, test=True, locale_code="en", ad_block=True) as sb:
294289

295290
</details>
296291

292+
> [SeleniumBase/examples/cdp_mode/raw_nike.py](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode/raw_nike.py)
293+
294+
<p><div /></p>
295+
297296
(<b>Note:</b> Extra <code translate="no">sb.sleep()</code> calls have been added to prevent bot-detection because some sites will flag you as a bot if you perform actions too quickly.)
298297

299298
(<b>Note:</b> Some sites may IP-block you for 36 hours or more if they catch you using regular <span translate="no">Selenium WebDriver</span>. Be extra careful when creating and/or modifying automation scripts that run on them.)
300299

301300
--------
302301

303-
### 🐙 CDP Mode API / Methods
302+
### 🐙 <btranslate="no">CDP Mode</b> API / Methods
304303

305304
(Some method args have been left out for simplicity. Eg: <code translate="no">timeout</code>)
306305

@@ -323,6 +322,9 @@ sb.cdp.find_visible_elements(selector)
323322
sb.cdp.click_nth_element(selector, number)
324323
sb.cdp.click_nth_visible_element(selector, number)
325324
sb.cdp.click_link(link_text)
325+
sb.cdp.go_back()
326+
sb.cdp.go_forward()
327+
sb.cdp.get_navigation_history()
326328
sb.cdp.tile_windows(windows=None, max_columns=0)
327329
sb.cdp.get_all_cookies(*args, **kwargs)
328330
sb.cdp.set_all_cookies(*args, **kwargs)
@@ -434,7 +436,7 @@ sb.cdp.save_screenshot(name, folder=None, selector=None)
434436

435437
--------
436438

437-
### 🐙 CDP Mode WebElement API / Methods
439+
### 🐙 <btranslate="no">CDP Mode</b> WebElement API / Methods
438440

439441
```python
440442
element.clear_input()

‎examples/cdp_mode/raw_hyatt.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@
1919
sb.sleep(1)
2020
sb.cdp.click('button[data-locator="find-hotels"]')
2121
sb.sleep(5)
22-
hotel_names = sb.cdp.select_all(
23-
'div[data-booking-status="BOOKABLE"] [class*="HotelCard_header"]'
24-
)
25-
hotel_prices = sb.cdp.select_all(
26-
'div[data-booking-status="BOOKABLE"] div.rate'
27-
)
28-
sb.assert_true(len(hotel_names) == len(hotel_prices))
22+
card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]'
23+
hotels = sb.cdp.select_all(card_info)
2924
print("Hyatt Hotels in %s:" % location)
3025
print("(" + sb.cdp.get_text("ul.b-color_text-white") + ")")
31-
if len(hotel_names) == 0:
26+
if len(hotels) == 0:
3227
print("No availability over the selected dates!")
33-
for i, hotel in enumerate(hotel_names):
34-
print("* %s: %s => %s" % (i + 1, hotel.text, hotel_prices[i].text))
28+
for hotel in hotels:
29+
info = hotel.text.strip()
30+
if "Avg/Night" in info and not info.startswith("Rates from"):
31+
name = info.split(" (")[0].split(" + ")[0].split(" Award Cat")[0]
32+
price = "?"
33+
if "Rates from : " in info:
34+
price = info.split("Rates from : ")[1].split(" Avg/Night")[0]
35+
print("* %s => %s" % (name, price))

‎examples/presenter/uc_presentation_4.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -695,24 +695,24 @@ def test_presentation_4(self):
695695
sb.sleep(1)
696696
sb.cdp.click('button[data-locator="find-hotels"]')
697697
sb.sleep(5)
698-
hotel_names = sb.cdp.select_all(
699-
'div[data-booking-status="BOOKABLE"]'
700-
' [class*="HotelCard_header"]'
698+
card_info = (
699+
'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]'
701700
)
702-
hotel_prices = sb.cdp.select_all(
703-
'div[data-booking-status="BOOKABLE"] div.rate'
704-
)
705-
sb.assert_true(len(hotel_names) == len(hotel_prices))
706-
print("\n\nHyatt Hotels in %s:" % location)
701+
hotels = sb.cdp.select_all(card_info)
702+
print("Hyatt Hotels in %s:" % location)
707703
print("(" + sb.cdp.get_text("ul.b-color_text-white") + ")")
708-
if len(hotel_names) == 0:
704+
if len(hotels) == 0:
709705
print("No availability over the selected dates!")
710-
for i, hotel in enumerate(hotel_names):
711-
with suppress(Exception):
712-
print(
713-
"* %s: %s => %s"
714-
% (i + 1, hotel.text, hotel_prices[i].text)
715-
)
706+
for hotel in hotels:
707+
info = hotel.text.strip()
708+
if "Avg/Night" in info and not info.startswith("Rates from"):
709+
name = info.split(" (")[0]
710+
name = name.split(" + ")[0].split(" Award Cat")[0]
711+
price = "?"
712+
if "Rates from : " in info:
713+
price = info.split("Rates from : ")[1]
714+
price = price.split(" Avg/Night")[0]
715+
print("* %s => %s" % (name, price))
716716

717717
self.create_presentation(theme="serif", transition="none")
718718
self.add_slide(

‎mkdocs_build/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ lxml==5.3.0
2020
pyquery==2.0.1
2121
readtime==3.0.0
2222
mkdocs==1.6.1
23-
mkdocs-material==9.5.46
23+
mkdocs-material==9.5.47
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ execnet==2.1.1
4444
iniconfig==2.0.0
4545
pluggy==1.5.0
4646
py==1.11.0
47-
pytest==8.3.3
47+
pytest==8.3.4
4848
pytest-html==2.0.1
4949
pytest-metadata==3.1.1
5050
pytest-ordering==0.6

‎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.33.2"
2+
__version__ = "4.33.3"

‎seleniumbase/core/browser_launcher.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,9 @@ def uc_open_with_cdp_mode(driver, url=None):
606606
cdp.click_nth_element = CDPM.click_nth_element
607607
cdp.click_nth_visible_element = CDPM.click_nth_visible_element
608608
cdp.click_link = CDPM.click_link
609+
cdp.go_back = CDPM.go_back
610+
cdp.go_forward = CDPM.go_forward
611+
cdp.get_navigation_history = CDPM.get_navigation_history
609612
cdp.tile_windows = CDPM.tile_windows
610613
cdp.get_all_cookies = CDPM.get_all_cookies
611614
cdp.set_all_cookies = CDPM.set_all_cookies
@@ -1419,11 +1422,8 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
14191422
page_actions.switch_to_window(
14201423
driver, driver.current_window_handle, 2, uc_lock=False
14211424
)
1422-
if (
1423-
IS_WINDOWS
1424-
and hasattr(pyautogui, "getActiveWindowTitle")
1425-
):
1426-
py_a_g_title = pyautogui.getActiveWindowTitle()
1425+
if IS_WINDOWS and hasattr(pyautogui, "getActiveWindowTitle"):
1426+
py_a_g_title = pyautogui.getActiveWindowTitle() or ""
14271427
window_title = driver.get_title()
14281428
if not py_a_g_title.startswith(window_title):
14291429
window_rect = driver.get_window_rect()

‎seleniumbase/core/sb_cdp.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ def click_nth_visible_element(self, selector, number):
289289
def click_link(self, link_text):
290290
self.find_elements_by_text(link_text, "a")[0].click()
291291

292+
def go_back(self):
293+
self.loop.run_until_complete(self.page.back())
294+
295+
def go_forward(self):
296+
self.loop.run_until_complete(self.page.forward())
297+
298+
def get_navigation_history(self):
299+
return self.loop.run_until_complete(self.page.get_navigation_history())
300+
292301
def __clear_input(self, element):
293302
return (
294303
self.loop.run_until_complete(element.clear_input_async())

‎seleniumbase/fixtures/base_case.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,9 @@ def get_locale_code(self):
13231323

13241324
def go_back(self):
13251325
self.__check_scope()
1326+
if self.__is_cdp_swap_needed():
1327+
self.cdp.go_back()
1328+
return
13261329
if hasattr(self, "recorder_mode") and self.recorder_mode:
13271330
self.save_recorded_actions()
13281331
pre_action_url = None
@@ -1348,6 +1351,9 @@ def go_back(self):
13481351

13491352
def go_forward(self):
13501353
self.__check_scope()
1354+
if self.__is_cdp_swap_needed():
1355+
self.cdp.go_forward()
1356+
return
13511357
if hasattr(self, "recorder_mode") and self.recorder_mode:
13521358
self.save_recorded_actions()
13531359
self.__last_page_load_url = None
@@ -1732,6 +1738,9 @@ def click_partial_link_text(self, partial_link_text, timeout=None):
17321738
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
17331739
timeout = self.__get_new_timeout(timeout)
17341740
partial_link_text = self.__get_type_checked_text(partial_link_text)
1741+
if self.__is_cdp_swap_needed():
1742+
self.cdp.find_element(partial_link_text, timeout=timeout).click()
1743+
return
17351744
if not self.is_partial_link_text_present(partial_link_text):
17361745
self.wait_for_partial_link_text_present(
17371746
partial_link_text, timeout=timeout
@@ -8133,6 +8142,8 @@ def is_connected(self):
81338142
def is_chromium(self):
81348143
"""Return True if the browser is Chrome or Edge."""
81358144
self.__check_scope()
8145+
if self.__is_cdp_swap_needed():
8146+
return True
81368147
chromium = False
81378148
if (
81388149
"chrome" in self.driver.capabilities

‎seleniumbase/undetected/cdp_driver/tab.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,10 @@ async def forward(self):
636636
"""History forward"""
637637
await self.send(cdp.runtime.evaluate("window.history.forward()"))
638638

639+
async def get_navigation_history(self):
640+
"""Get Navigation History"""
641+
return await self.send(cdp.page.get_navigation_history())
642+
639643
async def reload(
640644
self,
641645
ignore_cache: Optional[bool] = True,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /