Skip to content

Commit 189daf3

Browse files
committed
Update CDP Mode
1 parent 2339e8d commit 189daf3

File tree

12 files changed

+201
-28
lines changed

12 files changed

+201
-28
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
<h2><img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="32" /> CHANGELOG</h2>
22

3-
### See: [SeleniumBase/releases](https://github.com/seleniumbase/SeleniumBase/releases)
3+
## See: [SeleniumBase/releases](https://github.com/seleniumbase/SeleniumBase/releases) 🗂️ 📋
4+
5+
### (For CDP updates, see the [CDP Mode docs](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md))

examples/cdp_mode/ReadMe.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -395,12 +395,17 @@ sb.cdp.uncheck_if_checked(selector)
395395
sb.cdp.unselect_if_selected(selector)
396396
sb.cdp.is_element_present(selector)
397397
sb.cdp.is_element_visible(selector)
398-
sb.cdp.assert_element_present(selector)
399-
sb.cdp.assert_element_absent(selector)
398+
sb.cdp.wait_for_element_visible(selector)
400399
sb.cdp.assert_element(selector)
401400
sb.cdp.assert_element_visible(selector)
401+
sb.cdp.assert_element_present(selector)
402+
sb.cdp.assert_element_absent(selector)
402403
sb.cdp.assert_element_not_visible(selector)
404+
sb.cdp.assert_element_attribute(selector, attribute, value=None)
403405
sb.cdp.assert_title(title)
406+
sb.cdp.assert_title_contains(substring)
407+
sb.cdp.assert_url(url)
408+
sb.cdp.assert_url_contains(substring)
404409
sb.cdp.assert_text(text, selector="html")
405410
sb.cdp.assert_exact_text(text, selector="html")
406411
sb.cdp.scroll_into_view(selector)

help_docs/method_summary.md

+2
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ self.get_cookie(name)
362362

363363
self.get_cookies()
364364

365+
self.get_cookie_string()
366+
365367
self.add_cookie(cookie_dict, expiry=False)
366368

367369
self.add_cookies(cookies, expiry=False)

help_docs/uc_mode.md

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
👤 <b translate="no">SeleniumBase</b> <b translate="no">UC Mode</b> (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.
66

7+
> #### (For the successor to default UC Mode, see **[CDP Mode 🐙](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md)**)
8+
79
---
810

911
<!-- YouTube View --><a href="https://www.youtube.com/watch?v=5dMFI3e85ig"><img src="http://img.youtube.com/vi/5dMFI3e85ig/0.jpg" title="SeleniumBase on YouTube" width="350" /></a>

sbase/steps.py

+7
Original file line numberDiff line numberDiff line change
@@ -1189,3 +1189,10 @@ def set_attributes(context, selector, attribute, value):
11891189
if attribute.endswith("'") or attribute.endswith('"'):
11901190
attribute = attribute[:-1]
11911191
sb.set_attributes(selector, attribute, value)
1192+
1193+
1194+
@step("Activate CDP Mode")
1195+
@step("User activates CDP Mode")
1196+
def activate_cdp_mode(context):
1197+
sb = context.sb
1198+
sb.activate_cdp_mode()

seleniumbase/console_scripts/sb_mkrec.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ def main():
144144
elif option.lower() in ("--gui", "--headed"):
145145
if "linux" in sys.platform:
146146
force_gui = True
147-
elif option.lower() in ("--uc", "--undetected", "--undetectable"):
147+
elif option.lower() in (
148+
"--uc", "--cdp", "--undetected", "--undetectable"
149+
):
148150
use_uc = True
149151
elif option.lower() in ("--rec-behave", "--behave", "--gherkin"):
150152
rec_behave = True

seleniumbase/console_scripts/sb_recorder.py

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
1010
Options:
1111
--uc / --undetected (Use undetectable mode.)
12+
--cdp (Same as "--uc" and "--undetectable".)
1213
--behave (Also output Behave/Gherkin files.)
1314
1415
Output:
@@ -151,6 +152,7 @@ def do_recording(file_name, url, overwrite_enabled, use_chrome, window):
151152
command += " --edge"
152153
if (
153154
"--uc" in command_args
155+
or "--cdp" in command_args
154156
or "--undetected" in command_args
155157
or "--undetectable" in command_args
156158
):
@@ -193,6 +195,7 @@ def do_playback(file_name, use_chrome, window, demo_mode=False):
193195
command_args = sys.argv[2:]
194196
if (
195197
"--uc" in command_args
198+
or "--cdp" in command_args
196199
or "--undetected" in command_args
197200
or "--undetectable" in command_args
198201
):

seleniumbase/core/browser_launcher.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -683,12 +683,17 @@ def uc_open_with_cdp_mode(driver, url=None):
683683
cdp.is_checked = CDPM.is_checked
684684
cdp.is_element_present = CDPM.is_element_present
685685
cdp.is_element_visible = CDPM.is_element_visible
686+
cdp.wait_for_element_visible = CDPM.wait_for_element_visible
687+
cdp.assert_element = CDPM.assert_element
688+
cdp.assert_element_visible = CDPM.assert_element_visible
686689
cdp.assert_element_present = CDPM.assert_element_present
687690
cdp.assert_element_absent = CDPM.assert_element_absent
688-
cdp.assert_element = CDPM.assert_element
689-
cdp.assert_element_visible = CDPM.assert_element
690691
cdp.assert_element_not_visible = CDPM.assert_element_not_visible
692+
cdp.assert_element_attribute = CDPM.assert_element_attribute
691693
cdp.assert_title = CDPM.assert_title
694+
cdp.assert_title_contains = CDPM.assert_title_contains
695+
cdp.assert_url = CDPM.assert_url
696+
cdp.assert_url_contains = CDPM.assert_url_contains
692697
cdp.assert_text = CDPM.assert_text
693698
cdp.assert_exact_text = CDPM.assert_exact_text
694699
cdp.scroll_into_view = CDPM.scroll_into_view

seleniumbase/core/sb_cdp.py

+110-14
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,16 @@ def __init__(self, loop, page, driver):
2020
self.driver = driver
2121

2222
def __slow_mode_pause_if_set(self):
23-
if hasattr(sb_config, "slow_mode") and sb_config.slow_mode:
24-
time.sleep(0.16)
23+
if (
24+
(hasattr(sb_config, "demo_mode") and sb_config.demo_mode)
25+
or "--demo" in sys.argv
26+
):
27+
time.sleep(0.48)
28+
elif (
29+
(hasattr(sb_config, "slow_mode") and sb_config.slow_mode)
30+
or "--slow" in sys.argv
31+
):
32+
time.sleep(0.24)
2533

2634
def __add_light_pause(self):
2735
time.sleep(0.007)
@@ -543,7 +551,7 @@ def click_visible_elements(self, selector, limit=0):
543551
if (width != 0 or height != 0):
544552
element.click()
545553
click_count += 1
546-
time.sleep(0.0375)
554+
time.sleep(0.042)
547555
self.__slow_mode_pause_if_set()
548556
self.loop.run_until_complete(self.page.wait())
549557
except Exception:
@@ -660,10 +668,10 @@ def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
660668
text = text[:-1]
661669
for key in text:
662670
element.send_keys(key)
663-
time.sleep(0.0375)
671+
time.sleep(0.042)
664672
if submit:
665673
element.send_keys("\r\n")
666-
time.sleep(0.0375)
674+
time.sleep(0.042)
667675
self.__slow_mode_pause_if_set()
668676
self.loop.run_until_complete(self.page.wait())
669677

@@ -733,7 +741,7 @@ def maximize(self):
733741
return
734742
elif self.get_window()[1].window_state.value == "minimized":
735743
self.loop.run_until_complete(self.page.maximize())
736-
time.sleep(0.0375)
744+
time.sleep(0.042)
737745
return self.loop.run_until_complete(self.page.maximize())
738746

739747
def minimize(self):
@@ -743,7 +751,7 @@ def minimize(self):
743751
def medimize(self):
744752
if self.get_window()[1].window_state.value == "minimized":
745753
self.loop.run_until_complete(self.page.medimize())
746-
time.sleep(0.0375)
754+
time.sleep(0.042)
747755
return self.loop.run_until_complete(self.page.medimize())
748756

749757
def set_window_rect(self, x, y, width, height):
@@ -752,7 +760,7 @@ def set_window_rect(self, x, y, width, height):
752760
self.page.set_window_size(
753761
left=x, top=y, width=width, height=height)
754762
)
755-
time.sleep(0.0375)
763+
time.sleep(0.042)
756764
return self.loop.run_until_complete(
757765
self.page.set_window_size(
758766
left=x, top=y, width=width, height=height)
@@ -1117,7 +1125,7 @@ def gui_press_key(self, key):
11171125
)
11181126
with gui_lock:
11191127
pyautogui.press(key)
1120-
time.sleep(0.0375)
1128+
time.sleep(0.042)
11211129
self.__slow_mode_pause_if_set()
11221130
self.loop.run_until_complete(self.page.wait())
11231131

@@ -1131,7 +1139,7 @@ def gui_press_keys(self, keys):
11311139
with gui_lock:
11321140
for key in keys:
11331141
pyautogui.press(key)
1134-
time.sleep(0.0375)
1142+
time.sleep(0.042)
11351143
self.__slow_mode_pause_if_set()
11361144
self.loop.run_until_complete(self.page.wait())
11371145

@@ -1472,25 +1480,53 @@ def is_element_visible(self, selector):
14721480
return True
14731481
return False
14741482

1483+
def wait_for_element_visible(
1484+
self, selector, timeout=settings.SMALL_TIMEOUT
1485+
):
1486+
try:
1487+
self.select(selector, timeout=timeout)
1488+
except Exception:
1489+
raise Exception("Element {%s} was not found!" % selector)
1490+
for i in range(30):
1491+
if self.is_element_visible(selector):
1492+
return self.select(selector)
1493+
time.sleep(0.1)
1494+
raise Exception("Element {%s} was not visible!" % selector)
1495+
14751496
def assert_element(self, selector, timeout=settings.SMALL_TIMEOUT):
1497+
"""Same as assert_element_visible()"""
14761498
try:
14771499
self.select(selector, timeout=timeout)
14781500
except Exception:
1479-
raise Exception("Element {%s} not found!" % selector)
1501+
raise Exception("Element {%s} was not found!" % selector)
14801502
for i in range(30):
14811503
if self.is_element_visible(selector):
14821504
return True
14831505
time.sleep(0.1)
1484-
raise Exception("Element {%s} not visible!" % selector)
1506+
raise Exception("Element {%s} was not visible!" % selector)
1507+
1508+
def assert_element_visible(self, selector, timeout=settings.SMALL_TIMEOUT):
1509+
"""Same as assert_element()"""
1510+
try:
1511+
self.select(selector, timeout=timeout)
1512+
except Exception:
1513+
raise Exception("Element {%s} was not found!" % selector)
1514+
for i in range(30):
1515+
if self.is_element_visible(selector):
1516+
return True
1517+
time.sleep(0.1)
1518+
raise Exception("Element {%s} was not visible!" % selector)
14851519

14861520
def assert_element_present(self, selector, timeout=settings.SMALL_TIMEOUT):
1521+
"""Assert element is present in the DOM. (Visibility NOT required)"""
14871522
try:
14881523
self.select(selector, timeout=timeout)
14891524
except Exception:
1490-
raise Exception("Element {%s} not found!" % selector)
1525+
raise Exception("Element {%s} was not found!" % selector)
14911526
return True
14921527

14931528
def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT):
1529+
"""Assert element is not present in the DOM."""
14941530
start_ms = time.time() * 1000.0
14951531
stop_ms = start_ms + (timeout * 1000.0)
14961532
for i in range(int(timeout * 10)):
@@ -1511,6 +1547,7 @@ def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT):
15111547
def assert_element_not_visible(
15121548
self, selector, timeout=settings.SMALL_TIMEOUT
15131549
):
1550+
"""Assert element is not visible on page. (May still be in DOM)"""
15141551
start_ms = time.time() * 1000.0
15151552
stop_ms = start_ms + (timeout * 1000.0)
15161553
for i in range(int(timeout * 10)):
@@ -1530,6 +1567,21 @@ def assert_element_not_visible(
15301567
% (selector, timeout, plural)
15311568
)
15321569

1570+
def assert_element_attribute(self, selector, attribute, value=None):
1571+
attributes = self.get_element_attributes(selector)
1572+
if attribute not in attributes:
1573+
raise Exception(
1574+
"Attribute {%s} was not found in element {%s}!"
1575+
% (attribute, selector)
1576+
)
1577+
if value and attributes[attribute] != value:
1578+
raise Exception(
1579+
"Expected value {%s} of attribute {%s} "
1580+
"was not found in element {%s}! "
1581+
"(Actual value was {%s})"
1582+
% (value, attribute, selector, attributes[attribute])
1583+
)
1584+
15331585
def assert_title(self, title):
15341586
expected = title.strip()
15351587
actual = self.get_title().strip()
@@ -1541,11 +1593,55 @@ def assert_title(self, title):
15411593
raise Exception(error % (expected, actual))
15421594
except Exception:
15431595
time.sleep(2)
1544-
expected = title.strip()
15451596
actual = self.get_title().strip()
15461597
if expected != actual:
15471598
raise Exception(error % (expected, actual))
15481599

1600+
def assert_title_contains(self, substring):
1601+
expected = substring.strip()
1602+
actual = self.get_title().strip()
1603+
error = (
1604+
"Expected title substring [%s] does not appear "
1605+
"in the actual page title [%s]!"
1606+
)
1607+
try:
1608+
if expected not in actual:
1609+
raise Exception(error % (expected, actual))
1610+
except Exception:
1611+
time.sleep(2)
1612+
actual = self.get_title().strip()
1613+
if expected not in actual:
1614+
raise Exception(error % (expected, actual))
1615+
1616+
def assert_url(self, url):
1617+
expected = url.strip()
1618+
actual = self.get_current_url().strip()
1619+
error = "Expected URL [%s] does not match the actual URL [%s]!"
1620+
try:
1621+
if expected != actual:
1622+
raise Exception(error % (expected, actual))
1623+
except Exception:
1624+
time.sleep(2)
1625+
actual = self.get_current_url().strip()
1626+
if expected != actual:
1627+
raise Exception(error % (expected, actual))
1628+
1629+
def assert_url_contains(self, substring):
1630+
expected = substring.strip()
1631+
actual = self.get_current_url().strip()
1632+
error = (
1633+
"Expected URL substring [%s] does not appear "
1634+
"in the full URL [%s]!"
1635+
)
1636+
try:
1637+
if expected not in actual:
1638+
raise Exception(error % (expected, actual))
1639+
except Exception:
1640+
time.sleep(2)
1641+
actual = self.get_current_url().strip()
1642+
if expected not in actual:
1643+
raise Exception(error % (expected, actual))
1644+
15491645
def assert_text(
15501646
self, text, selector="html", timeout=settings.SMALL_TIMEOUT
15511647
):

0 commit comments

Comments
 (0)