Skip to content

Commit a84f5c3

Browse files
authoredMar 5, 2025
Merge pull request #3581 from seleniumbase/cdp-mode-patch-39
CDP Mode: Patch 39
2 parents aa0b70a + 17d5c36 commit a84f5c3

18 files changed

+131
-43
lines changed
 

‎examples/cdp_mode/ReadMe.md

+7
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,13 @@ sb.cdp.minimize()
420420
sb.cdp.medimize()
421421
sb.cdp.set_window_rect()
422422
sb.cdp.reset_window_size()
423+
sb.cdp.switch_to_window(window)
424+
sb.cdp.switch_to_newest_window()
425+
sb.cdp.switch_to_tab(tab)
426+
sb.cdp.switch_to_newest_tab()
427+
sb.cdp.close_active_tab()
428+
sb.cdp.get_active_tab()
429+
sb.cdp.get_tabs()
423430
sb.cdp.get_window()
424431
sb.cdp.get_text(selector)
425432
sb.cdp.get_title()

‎examples/cdp_mode/raw_async.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ async def main():
5151
location = "Amsterdam"
5252
where_to = 'div[data-automation*="experiences"] input'
5353
button = 'button[data-automation*="experiences-search"]'
54+
sb.wait_for_text("Where to?")
5455
sb.gui_click_element(where_to)
5556
sb.press_keys(where_to, location)
5657
sb.sleep(1)
5758
sb.gui_click_element(button)
5859
sb.sleep(3)
5960
print(sb.get_title())
6061
print("************")
61-
cards = sb.select_all('h2[data-automation*="product-list-card"]')
62+
cards = sb.select_all('span[data-automation*="product-list-card"]')
6263
for card in cards:
6364
print("* %s" % card.text)

‎examples/cdp_mode/raw_cdp.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def main():
1616
location = "Amsterdam"
1717
where_to = 'div[data-automation*="experiences"] input'
1818
button = 'button[data-automation*="experiences-search"]'
19+
sb.wait_for_text("Where to?")
1920
sb.gui_click_element(where_to)
2021
sb.press_keys(where_to, location)
2122
sb.sleep(1)
@@ -26,7 +27,7 @@ def main():
2627
for i in range(8):
2728
sb.scroll_down(50)
2829
sb.sleep(0.2)
29-
cards = sb.select_all('h2[data-automation*="product-list-card"]')
30+
cards = sb.select_all('span[data-automation*="product-list-card"]')
3031
for card in cards:
3132
print("* %s" % card.text)
3233

‎examples/cdp_mode/raw_cdp_with_sb.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
location = "Amsterdam"
1515
where_to = 'div[data-automation*="experiences"] input'
1616
button = 'button[data-automation*="experiences-search"]'
17+
sb.wait_for_text("Where to?")
1718
sb.cdp.gui_click_element(where_to)
1819
sb.press_keys(where_to, location)
1920
sb.sleep(1)
@@ -24,6 +25,6 @@
2425
for i in range(8):
2526
sb.cdp.scroll_down(50)
2627
sb.sleep(0.2)
27-
cards = sb.select_all('h2[data-automation*="product-list-card"]')
28+
cards = sb.select_all('span[data-automation*="product-list-card"]')
2829
for card in cards:
2930
print("* %s" % card.text)
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""A script that loads cookies to bypass login."""
2+
import asyncio
3+
import time
4+
from seleniumbase import cdp_driver
5+
6+
7+
# Log in to Swag Labs and save cookies
8+
async def get_login_cookies():
9+
url = "https://www.saucedemo.com"
10+
driver = await cdp_driver.start_async(incognito=True)
11+
page = await driver.get(url)
12+
element = await page.select("#user-name")
13+
await element.send_keys_async("standard_user")
14+
element = await page.select("#password")
15+
await element.send_keys_async("secret_sauce")
16+
element = await page.select('input[type="submit"]')
17+
await element.click_async()
18+
cookies = await driver.cookies.get_all()
19+
await page.close()
20+
return cookies
21+
22+
23+
# Load previously saved cookies to bypass login
24+
async def login_with_cookies(cookies):
25+
url_1 = "https://www.saucedemo.com"
26+
url_2 = "https://www.saucedemo.com/inventory.html"
27+
driver = await cdp_driver.start_async()
28+
page = await driver.get(url_1)
29+
await driver.cookies.set_all(cookies)
30+
await driver.get(url_2)
31+
await page.select("div.inventory_list")
32+
time.sleep(2)
33+
34+
35+
if __name__ == "__main__":
36+
loop = asyncio.new_event_loop()
37+
cookies = loop.run_until_complete(get_login_cookies())
38+
loop.run_until_complete(login_with_cookies(cookies))

‎examples/cdp_mode/raw_priceline.py

+4-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from seleniumbase import SB
22

33
with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
4-
window_handle = sb.driver.current_window_handle
54
url = "https://www.priceline.com"
65
sb.activate_cdp_mode(url)
76
sb.sleep(2.5)
@@ -17,17 +16,14 @@
1716
sb.sleep(1.5)
1817
sb.cdp.click('button[aria-label="Dismiss calendar"]')
1918
sb.sleep(4.5)
20-
sb.connect()
21-
if len(sb.driver.window_handles) > 1:
22-
sb.switch_to_window(window_handle)
23-
sb.driver.close()
24-
sb.sleep(0.2)
25-
sb.switch_to_newest_window()
19+
if len(sb.cdp.get_tabs()) > 1:
20+
sb.cdp.close_active_tab()
21+
sb.cdp.switch_to_newest_tab()
2622
sb.sleep(0.6)
2723
sb.sleep(0.8)
2824
for y in range(1, 9):
2925
sb.scroll_to_y(y * 400)
30-
sb.sleep(0.75)
26+
sb.sleep(0.5)
3127
hotel_names = sb.find_elements('a[data-autobot-element-id*="HOTEL_NAME"]')
3228
hotel_prices = sb.find_elements('span[font-size="4,,,5"]')
3329
print("Priceline Hotels in %s:" % location)

‎examples/presenter/uc_presentation_4.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,6 @@ def test_presentation_4(self):
770770
self.begin_presentation(filename="uc_presentation.html")
771771

772772
with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
773-
window_handle = sb.driver.current_window_handle
774773
url = "https://www.priceline.com"
775774
sb.activate_cdp_mode(url)
776775
sb.sleep(2.5)
@@ -786,22 +785,19 @@ def test_presentation_4(self):
786785
sb.sleep(1.5)
787786
sb.cdp.click('button[aria-label="Dismiss calendar"]')
788787
sb.sleep(4.5)
789-
sb.connect()
790-
if len(sb.driver.window_handles) > 1:
791-
sb.switch_to_window(window_handle)
792-
sb.driver.close()
793-
sb.sleep(0.2)
794-
sb.switch_to_newest_window()
788+
if len(sb.cdp.get_tabs()) > 1:
789+
sb.cdp.close_active_tab()
790+
sb.cdp.switch_to_newest_tab()
795791
sb.sleep(0.6)
796792
sb.sleep(0.8)
797793
for y in range(1, 9):
798794
sb.scroll_to_y(y * 400)
799-
sb.sleep(0.75)
795+
sb.sleep(0.5)
800796
hotel_names = sb.find_elements(
801797
'a[data-autobot-element-id*="HOTEL_NAME"]'
802798
)
803799
hotel_prices = sb.find_elements('span[font-size="4,,,5"]')
804-
print("\n\nPriceline Hotels in %s:" % location)
800+
print("Priceline Hotels in %s:" % location)
805801
print(sb.get_text('[data-testid="POPOVER-DATE-PICKER"]'))
806802
if len(hotel_names) == 0:
807803
print("No availability over the selected dates!")

‎help_docs/syntax_formats.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,7 @@ def main():
10721072
for i in range(8):
10731073
sb.scroll_down(50)
10741074
sb.sleep(0.2)
1075-
cards = sb.select_all('h2[data-automation*="product-list-card"]')
1075+
cards = sb.select_all('span[data-automation*="product-list-card"]')
10761076
for card in cards:
10771077
print("* %s" % card.text)
10781078

‎mkdocs_build/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pathspec==0.12.1
1414
Babel==2.17.0
1515
paginate==0.5.7
1616
mkdocs==1.6.1
17-
mkdocs-material==9.6.5
17+
mkdocs-material==9.6.7
1818
mkdocs-exclude-search==0.6.6
1919
mkdocs-simple-hooks==0.1.5
2020
mkdocs-material-extensions==1.3.1

‎requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ sortedcontainers==2.4.0
4949
execnet==2.1.1
5050
iniconfig==2.0.0
5151
pluggy==1.5.0
52-
pytest==8.3.4
52+
pytest==8.3.5
5353
pytest-html==4.0.2
5454
pytest-metadata==3.1.1
5555
pytest-ordering==0.6

‎seleniumbase/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.35.2"
2+
__version__ = "4.35.3"

‎seleniumbase/core/browser_launcher.py

+8
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,13 @@ def uc_open_with_cdp_mode(driver, url=None):
682682
cdp.gui_hover_element = CDPM.gui_hover_element
683683
cdp.gui_hover_and_click = CDPM.gui_hover_and_click
684684
cdp.internalize_links = CDPM.internalize_links
685+
cdp.switch_to_window = CDPM.switch_to_window
686+
cdp.switch_to_newest_window = CDPM.switch_to_newest_window
687+
cdp.switch_to_tab = CDPM.switch_to_tab
688+
cdp.switch_to_newest_tab = CDPM.switch_to_newest_tab
689+
cdp.close_active_tab = CDPM.close_active_tab
690+
cdp.get_active_tab = CDPM.get_active_tab
691+
cdp.get_tabs = CDPM.get_tabs
685692
cdp.get_window = CDPM.get_window
686693
cdp.get_element_attributes = CDPM.get_element_attributes
687694
cdp.get_element_attribute = CDPM.get_element_attribute
@@ -2033,6 +2040,7 @@ def _set_chrome_options(
20332040
prefs["download.default_directory"] = downloads_path
20342041
prefs["download.directory_upgrade"] = True
20352042
prefs["download.prompt_for_download"] = False
2043+
prefs["download_bubble.partial_view_enabled"] = False
20362044
prefs["credentials_enable_service"] = False
20372045
prefs["local_discovery.notifications_enabled"] = False
20382046
prefs["safebrowsing.enabled"] = False # Prevent PW "data breach" pop-ups

‎seleniumbase/core/sb_cdp.py

+46-9
Original file line numberDiff line numberDiff line change
@@ -1014,10 +1014,51 @@ def reset_window_size(self):
10141014
self.set_window_rect(x, y, width, height)
10151015
self.__add_light_pause()
10161016

1017+
def switch_to_window(self, window):
1018+
self.switch_to_tab(window)
1019+
1020+
def switch_to_newest_window(self):
1021+
self.switch_to_tab(-1)
1022+
1023+
def switch_to_tab(self, tab):
1024+
driver = self.driver
1025+
if hasattr(driver, "cdp_base"):
1026+
driver = driver.cdp_base
1027+
if isinstance(tab, int):
1028+
self.page = driver.tabs[tab]
1029+
elif isinstance(tab, cdp_util.Tab):
1030+
self.page = tab
1031+
else:
1032+
raise Exception("`tab` must be an int or a Tab type!")
1033+
self.bring_active_window_to_front()
1034+
1035+
def switch_to_newest_tab(self):
1036+
self.switch_to_tab(-1)
1037+
1038+
def close_active_tab(self):
1039+
"""Close the active tab.
1040+
The active tab is the one currenly controlled by CDP.
1041+
The active tab MIGHT NOT be the currently visible tab!
1042+
(If a page opens a new tab, the new tab WON'T be active)
1043+
To switch the active tab, call: sb.switch_to_tab(tab)"""
1044+
return self.loop.run_until_complete(self.page.close())
1045+
1046+
def get_active_tab(self):
1047+
"""Return the active tab.
1048+
The active tab is the one currenly controlled by CDP.
1049+
The active tab MIGHT NOT be the currently visible tab!
1050+
(If a page opens a new tab, the new tab WON'T be active)
1051+
To switch the active tab, call: sb.switch_to_tab(tab)"""
1052+
return self.page
1053+
1054+
def get_tabs(self):
1055+
driver = self.driver
1056+
if hasattr(driver, "cdp_base"):
1057+
driver = driver.cdp_base
1058+
return driver.tabs
1059+
10171060
def get_window(self):
1018-
return self.loop.run_until_complete(
1019-
self.page.get_window()
1020-
)
1061+
return self.loop.run_until_complete(self.page.get_window())
10211062

10221063
def get_text(self, selector):
10231064
return self.find_element(selector).text_all
@@ -1211,14 +1252,10 @@ def get_gui_element_center(self, selector, timeout=None):
12111252
return ((e_x + e_width / 2.0) + 0.5, (e_y + e_height / 2.0) + 0.5)
12121253

12131254
def get_document(self):
1214-
return self.loop.run_until_complete(
1215-
self.page.get_document()
1216-
)
1255+
return self.loop.run_until_complete(self.page.get_document())
12171256

12181257
def get_flattened_document(self):
1219-
return self.loop.run_until_complete(
1220-
self.page.get_flattened_document()
1221-
)
1258+
return self.loop.run_until_complete(self.page.get_flattened_document())
12221259

12231260
def get_element_attributes(self, selector):
12241261
selector = self.__convert_to_css_if_xpath(selector)

‎seleniumbase/fixtures/base_case.py

+3
Original file line numberDiff line numberDiff line change
@@ -3918,6 +3918,9 @@ def switch_to_window(self, window, timeout=None):
39183918
timeout = settings.SMALL_TIMEOUT
39193919
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
39203920
timeout = self.__get_new_timeout(timeout)
3921+
if self.__is_cdp_swap_needed() and not isinstance(window, str):
3922+
self.cdp.switch_to_tab(window)
3923+
return
39213924
page_actions.switch_to_window(self.driver, window, timeout)
39223925

39233926
def switch_to_default_window(self):

‎seleniumbase/undetected/cdp_driver/browser.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ async def get_all(
660660
break
661661
else:
662662
connection = self._browser.connection
663-
cookies = await connection.send(cdp.storage.get_cookies())
663+
cookies = await connection.send(cdp.network.get_cookies())
664664
if requests_cookie_format:
665665
import requests.cookies
666666

@@ -690,8 +690,7 @@ async def set_all(self, cookies: List[cdp.network.CookieParam]):
690690
break
691691
else:
692692
connection = self._browser.connection
693-
cookies = await connection.send(cdp.storage.get_cookies())
694-
await connection.send(cdp.storage.set_cookies(cookies))
693+
await connection.send(cdp.network.set_cookies(cookies))
695694

696695
async def save(self, file: PathLike = ".session.dat", pattern: str = ".*"):
697696
"""
@@ -718,7 +717,7 @@ async def save(self, file: PathLike = ".session.dat", pattern: str = ".*"):
718717
break
719718
else:
720719
connection = self._browser.connection
721-
cookies = await connection.send(cdp.storage.get_cookies())
720+
cookies = await connection.send(cdp.network.get_cookies())
722721
# if not connection:
723722
# return
724723
# if not connection.websocket:
@@ -776,7 +775,7 @@ async def load(self, file: PathLike = ".session.dat", pattern: str = ".*"):
776775
cookie.value,
777776
)
778777
break
779-
await connection.send(cdp.storage.set_cookies(included_cookies))
778+
await connection.send(cdp.network.set_cookies(included_cookies))
780779

781780
async def clear(self):
782781
"""
@@ -791,9 +790,9 @@ async def clear(self):
791790
break
792791
else:
793792
connection = self._browser.connection
794-
cookies = await connection.send(cdp.storage.get_cookies())
793+
cookies = await connection.send(cdp.network.get_cookies())
795794
if cookies:
796-
await connection.send(cdp.storage.clear_cookies())
795+
await connection.send(cdp.network.clear_cookies())
797796

798797

799798
class HTTPApi:

‎seleniumbase/undetected/cdp_driver/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ async def update_target(self):
382382
async def send(
383383
self,
384384
cdp_obj: Generator[dict[str, Any], dict[str, Any], Any],
385-
_is_update=False,
385+
_is_update=True,
386386
) -> Any:
387387
"""
388388
Send a protocol command.

‎seleniumbase/undetected/cdp_driver/tab.py

+1
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,7 @@ async def close(self):
852852
await self.send(
853853
cdp.target.close_target(target_id=self.target.target_id)
854854
)
855+
await asyncio.sleep(0.1)
855856

856857
async def get_window(self) -> Tuple[
857858
cdp.browser.WindowID, cdp.browser.Bounds

‎setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@
198198
'execnet==2.1.1',
199199
'iniconfig==2.0.0',
200200
'pluggy==1.5.0',
201-
'pytest==8.3.4',
201+
'pytest==8.3.5',
202202
"pytest-html==4.0.2", # Newer ones had issues
203203
'pytest-metadata==3.1.1',
204204
"pytest-ordering==0.6",
@@ -259,7 +259,7 @@
259259
"pdfminer": [
260260
'pdfminer.six==20240706',
261261
'cryptography==39.0.2;python_version<"3.9"',
262-
'cryptography==44.0.1;python_version>="3.9"',
262+
'cryptography==44.0.2;python_version>="3.9"',
263263
'cffi==1.17.1',
264264
"pycparser==2.22",
265265
],

0 commit comments

Comments
 (0)
Failed to load comments.