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 c963804

Browse files
authored
Merge pull request #3536 from seleniumbase/cdp-mode-patch-34
CDP Mode - Patch 34
2 parents 9c1909e + 0627037 commit c963804

File tree

14 files changed

+362
-60
lines changed

14 files changed

+362
-60
lines changed

‎examples/cdp_mode/ReadMe.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ sb.cdp.uncheck_if_checked(selector)
465465
sb.cdp.unselect_if_selected(selector)
466466
sb.cdp.is_element_present(selector)
467467
sb.cdp.is_element_visible(selector)
468+
sb.cdp.is_text_visible(text, selector="body")
469+
sb.cdp.is_exact_text_visible(text, selector="body")
470+
sb.cdp.wait_for_text(text, selector="body", timeout=None)
471+
sb.cdp.wait_for_text_not_visible(text, selector="body", timeout=None)
468472
sb.cdp.wait_for_element_visible(selector, timeout=None)
469473
sb.cdp.assert_element(selector, timeout=None)
470474
sb.cdp.assert_element_visible(selector, timeout=None)
@@ -478,6 +482,7 @@ sb.cdp.assert_url(url)
478482
sb.cdp.assert_url_contains(substring)
479483
sb.cdp.assert_text(text, selector="html", timeout=None)
480484
sb.cdp.assert_exact_text(text, selector="html", timeout=None)
485+
sb.cdp.assert_text_not_visible(text, selector="body", timeout=None)
481486
sb.cdp.assert_true()
482487
sb.cdp.assert_false()
483488
sb.cdp.assert_equal(first, second)
@@ -506,6 +511,7 @@ element.highlight_overlay()
506511
element.mouse_click()
507512
element.mouse_drag(destination)
508513
element.mouse_move()
514+
element.press_keys(text)
509515
element.query_selector(selector)
510516
element.querySelector(selector)
511517
element.query_selector_all(selector)

‎examples/cdp_mode/raw_ahrefs.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from seleniumbase import SB
2+
3+
with SB(uc=True, test=True, incognito=True, locale_code="en") as sb:
4+
url = "https://ahrefs.com/website-authority-checker"
5+
input_field = 'input[placeholder="Enter domain"]'
6+
submit_button = 'span:contains("Check Authority")'
7+
sb.activate_cdp_mode(url) # The bot-check is later
8+
sb.type(input_field, "github.com/seleniumbase/SeleniumBase")
9+
sb.cdp.scroll_down(36)
10+
sb.click(submit_button)
11+
sb.uc_gui_click_captcha()
12+
sb.wait_for_text_not_visible("Checking", timeout=15)
13+
sb.click_if_visible('button[data-cky-tag="close-button"]')
14+
sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")')
15+
sb.highlight('a:contains("Top 100 backlinks")')
16+
sb.set_messenger_theme(location="bottom_center")
17+
sb.post_message("SeleniumBase wasn't detected!")

‎examples/cdp_mode/raw_elal.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from seleniumbase import SB
2+
3+
with SB(uc=True, test=True, locale_code="en") as sb:
4+
url = "www.elal.com/flight-deals/en-us/flights-from-boston-to-tel-aviv"
5+
sb.activate_cdp_mode(url)
6+
sb.sleep(2)
7+
sb.cdp.click('button[data-att="search"]')
8+
sb.sleep(4)
9+
sb.cdp.click_if_visible("#onetrust-close-btn-container button")
10+
sb.sleep(0.5)
11+
view_other_dates = 'button[aria-label*="viewOtherDates.cta"]'
12+
if sb.cdp.is_element_visible(view_other_dates):
13+
sb.cdp.click(view_other_dates)
14+
sb.sleep(4.5)
15+
if sb.is_element_visible("flexible-search-calendar"):
16+
print("*** Flight Calendar for El Al (Boston to Tel Aviv): ***")
17+
print(sb.cdp.get_text("flexible-search-calendar"))
18+
prices = []
19+
elements = sb.cdp.find_elements("span.matric-cell__content__price")
20+
if elements:
21+
print("*** Prices List: ***")
22+
for element in elements:
23+
prices.append(element.text)
24+
for price in sorted(prices):
25+
print(price)
26+
print("*** Lowest Price: ***")
27+
lowest_price = sorted(prices)[0]
28+
print(lowest_price)
29+
sb.cdp.find_element_by_text(lowest_price).click()
30+
sb.sleep(1)
31+
search_cell = 'button[aria-label*="Search.cell.buttonTitle"]'
32+
sb.cdp.scroll_into_view(search_cell)
33+
sb.sleep(1)
34+
sb.cdp.click(search_cell)
35+
sb.sleep(5)
36+
else:
37+
elements = sb.cdp.find_elements("div.ui-bound__price__value")
38+
print("*** Lowest Prices: ***")
39+
first = True
40+
for element in elements:
41+
if "lowest price" in element.text:
42+
if first:
43+
print("Departure Flight:")
44+
print(element.text)
45+
first = False
46+
else:
47+
print("Return Flight:")
48+
print(element.text)
49+
break
50+
dates = sb.cdp.find_elements('div[class*="flight-date"]')
51+
if len(dates) == 2:
52+
print("*** Departure Date: ***")
53+
print(dates[0].text)
54+
print("*** Return Date: ***")
55+
print(dates[1].text)

‎examples/raw_ahrefs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
sb.reconnect(0.1)
1010
sb.uc_click(submit_button, reconnect_time=3.25)
1111
sb.uc_gui_click_captcha()
12-
sb.wait_for_text_not_visible("Checking", timeout=11.5)
12+
sb.wait_for_text_not_visible("Checking", timeout=15)
1313
sb.click_if_visible('button[data-cky-tag="close-button"]')
1414
sb.highlight('p:contains("github.com/seleniumbase/SeleniumBase")')
1515
sb.highlight('a:contains("Top 100 backlinks")')

‎requirements.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ attrs>=25.1.0
77
certifi>=2025年1月31日
88
exceptiongroup>=1.2.2
99
websockets~=13.1;python_version<"3.9"
10-
websockets>=14.2;python_version>="3.9"
10+
websockets>=15.0;python_version>="3.9"
1111
filelock~=3.16.1;python_version<"3.9"
1212
filelock>=3.17.0;python_version>="3.9"
1313
fasteners>=0.19
@@ -38,8 +38,8 @@ sniffio==1.3.1
3838
h11==0.14.0
3939
outcome==1.3.0.post0
4040
trio==0.27.0;python_version<"3.9"
41-
trio==0.28.0;python_version>="3.9"
42-
trio-websocket==0.11.1
41+
trio==0.29.0;python_version>="3.9"
42+
trio-websocket==0.12.1
4343
wsproto==1.2.0
4444
websocket-client==1.8.0
4545
selenium==4.27.1;python_version<"3.9"
@@ -74,7 +74,7 @@ coverage>=7.6.12;python_version>="3.9"
7474
pytest-cov>=5.0.0;python_version<"3.9"
7575
pytest-cov>=6.0.0;python_version>="3.9"
7676
flake8==5.0.4;python_version<"3.9"
77-
flake8==7.1.1;python_version>="3.9"
77+
flake8==7.1.2;python_version>="3.9"
7878
mccabe==0.7.0
7979
pyflakes==2.5.0;python_version<"3.9"
8080
pyflakes==3.2.0;python_version>="3.9"

‎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.34.15"
2+
__version__ = "4.34.16"

‎seleniumbase/core/browser_launcher.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,10 @@ def uc_open_with_cdp_mode(driver, url=None):
718718
cdp.is_selected = CDPM.is_selected
719719
cdp.is_element_present = CDPM.is_element_present
720720
cdp.is_element_visible = CDPM.is_element_visible
721+
cdp.is_text_visible = CDPM.is_text_visible
722+
cdp.is_exact_text_visible = CDPM.is_exact_text_visible
723+
cdp.wait_for_text = CDPM.wait_for_text
724+
cdp.wait_for_text_not_visible = CDPM.wait_for_text_not_visible
721725
cdp.wait_for_element_visible = CDPM.wait_for_element_visible
722726
cdp.assert_element = CDPM.assert_element
723727
cdp.assert_element_visible = CDPM.assert_element_visible
@@ -731,6 +735,7 @@ def uc_open_with_cdp_mode(driver, url=None):
731735
cdp.assert_url_contains = CDPM.assert_url_contains
732736
cdp.assert_text = CDPM.assert_text
733737
cdp.assert_exact_text = CDPM.assert_exact_text
738+
cdp.assert_text_not_visible = CDPM.assert_text_not_visible
734739
cdp.assert_true = CDPM.assert_true
735740
cdp.assert_false = CDPM.assert_false
736741
cdp.assert_equal = CDPM.assert_equal
@@ -2280,6 +2285,7 @@ def _set_chrome_options(
22802285
or proxy_string
22812286
):
22822287
chrome_options.add_argument("--ignore-certificate-errors")
2288+
chrome_options.add_argument("--ignore-ssl-errors=yes")
22832289
if not enable_ws:
22842290
chrome_options.add_argument("--disable-web-security")
22852291
if (
@@ -4231,6 +4237,7 @@ def get_local_driver(
42314237
edge_options.add_argument("--log-level=3")
42324238
edge_options.add_argument("--no-first-run")
42334239
edge_options.add_argument("--ignore-certificate-errors")
4240+
edge_options.add_argument("--ignore-ssl-errors=yes")
42344241
if devtools and not headless:
42354242
edge_options.add_argument("--auto-open-devtools-for-tabs")
42364243
edge_options.add_argument("--allow-file-access-from-files")

‎seleniumbase/core/sb_cdp.py

Lines changed: 105 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def __add_sync_methods(self, element):
6262
lambda destination: self.__mouse_drag(element, destination)
6363
)
6464
element.mouse_move = lambda: self.__mouse_move(element)
65+
element.press_keys = lambda text: self.__press_keys(element, text)
6566
element.query_selector = (
6667
lambda selector: self.__query_selector(element, selector)
6768
)
@@ -211,7 +212,8 @@ def find_element_by_text(self, text, tag_name=None, timeout=None):
211212
element = self.__add_sync_methods(element.parent)
212213
return self.__add_sync_methods(element)
213214
elif (
214-
element.parent.parent
215+
element.parent
216+
and element.parent.parent
215217
and tag_name in element.parent.parent.tag_name.lower()
216218
and text.strip() in element.parent.parent.text
217219
):
@@ -272,7 +274,8 @@ def find_elements_by_text(self, text, tag_name=None):
272274
if element not in updated_elements:
273275
updated_elements.append(element)
274276
elif (
275-
element.parent.parent
277+
element.parent
278+
and element.parent.parent
276279
and tag_name in element.parent.parent.tag_name.lower()
277280
and text.strip() in element.parent.parent.text
278281
):
@@ -445,6 +448,23 @@ def __mouse_move(self, element):
445448
self.loop.run_until_complete(element.mouse_move_async())
446449
)
447450

451+
def __press_keys(self, element, text):
452+
element.scroll_into_view()
453+
submit = False
454+
if text.endswith("\n") or text.endswith("\r"):
455+
submit = True
456+
text = text[:-1]
457+
for key in text:
458+
element.send_keys(key)
459+
time.sleep(0.044)
460+
if submit:
461+
element.send_keys("\r\n")
462+
time.sleep(0.044)
463+
self.__slow_mode_pause_if_set()
464+
return (
465+
self.loop.run_until_complete(self.page.wait())
466+
)
467+
448468
def __query_selector(self, element, selector):
449469
selector = self.__convert_to_css_if_xpath(selector)
450470
element2 = self.loop.run_until_complete(
@@ -1681,21 +1701,79 @@ def is_element_visible(self, selector):
16811701
return True
16821702
return False
16831703

1684-
def wait_for_element_visible(self, selector, timeout=None):
1704+
def is_text_visible(self, text, selector="body"):
1705+
selector = self.__convert_to_css_if_xpath(selector)
1706+
text = text.strip()
1707+
element = None
1708+
try:
1709+
element = self.find_element(selector, timeout=0.1)
1710+
except Exception:
1711+
return False
1712+
with suppress(Exception):
1713+
if text in element.text_all:
1714+
return True
1715+
return False
1716+
1717+
def is_exact_text_visible(self, text, selector="body"):
1718+
selector = self.__convert_to_css_if_xpath(selector)
1719+
text = text.strip()
1720+
element = None
1721+
try:
1722+
element = self.find_element(selector, timeout=0.1)
1723+
except Exception:
1724+
return False
1725+
with suppress(Exception):
1726+
if text == element.text_all.strip():
1727+
return True
1728+
return False
1729+
1730+
def wait_for_text(self, text, selector="body", timeout=None):
16851731
if not timeout:
16861732
timeout = settings.SMALL_TIMEOUT
1733+
start_ms = time.time() * 1000.0
1734+
stop_ms = start_ms + (timeout * 1000.0)
1735+
text = text.strip()
1736+
element = None
16871737
try:
1688-
self.select(selector, timeout=timeout)
1738+
element=self.find_element(selector, timeout=timeout)
16891739
except Exception:
1690-
raise Exception("Element {%s} was not found!" % selector)
1691-
for i in range(30):
1692-
if self.is_element_visible(selector):
1693-
return self.select(selector)
1740+
raise Exception("Element {%s} not found!" % selector)
1741+
for i in range(int(timeout * 10)):
1742+
with suppress(Exception):
1743+
element = self.find_element(selector, timeout=0.1)
1744+
if text in element.text_all:
1745+
return True
1746+
now_ms = time.time() * 1000.0
1747+
if now_ms >= stop_ms:
1748+
break
16941749
time.sleep(0.1)
1695-
raise Exception("Element {%s} was not visible!" % selector)
1750+
raise Exception(
1751+
"Text {%s} not found in {%s}! Actual text: {%s}"
1752+
% (text, selector, element.text_all)
1753+
)
16961754

1697-
def assert_element(self, selector, timeout=None):
1698-
"""Same as assert_element_visible()"""
1755+
def wait_for_text_not_visible(self, text, selector="body", timeout=None):
1756+
if not timeout:
1757+
timeout = settings.SMALL_TIMEOUT
1758+
text = text.strip()
1759+
start_ms = time.time() * 1000.0
1760+
stop_ms = start_ms + (timeout * 1000.0)
1761+
for i in range(int(timeout * 10)):
1762+
if not self.is_text_visible(text, selector):
1763+
return True
1764+
now_ms = time.time() * 1000.0
1765+
if now_ms >= stop_ms:
1766+
break
1767+
time.sleep(0.1)
1768+
plural = "s"
1769+
if timeout == 1:
1770+
plural = ""
1771+
raise Exception(
1772+
"Text {%s} in {%s} was still visible after %s second%s!"
1773+
% (text, selector, timeout, plural)
1774+
)
1775+
1776+
def wait_for_element_visible(self, selector, timeout=None):
16991777
if not timeout:
17001778
timeout = settings.SMALL_TIMEOUT
17011779
try:
@@ -1704,10 +1782,15 @@ def assert_element(self, selector, timeout=None):
17041782
raise Exception("Element {%s} was not found!" % selector)
17051783
for i in range(30):
17061784
if self.is_element_visible(selector):
1707-
return True
1785+
return self.select(selector)
17081786
time.sleep(0.1)
17091787
raise Exception("Element {%s} was not visible!" % selector)
17101788

1789+
def assert_element(self, selector, timeout=None):
1790+
"""Same as assert_element_visible()"""
1791+
self.assert_element_visible(selector, timeout=timeout)
1792+
return True
1793+
17111794
def assert_element_visible(self, selector, timeout=None):
17121795
"""Same as assert_element()"""
17131796
if not timeout:
@@ -1852,29 +1935,9 @@ def assert_url_contains(self, substring):
18521935
raise Exception(error % (expected, actual))
18531936

18541937
def assert_text(self, text, selector="body", timeout=None):
1855-
if not timeout:
1856-
timeout = settings.SMALL_TIMEOUT
1857-
start_ms = time.time() * 1000.0
1858-
stop_ms = start_ms + (timeout * 1000.0)
1859-
text = text.strip()
1860-
element = None
1861-
try:
1862-
element = self.find_element(selector, timeout=timeout)
1863-
except Exception:
1864-
raise Exception("Element {%s} not found!" % selector)
1865-
for i in range(int(timeout * 10)):
1866-
with suppress(Exception):
1867-
element = self.find_element(selector, timeout=0.1)
1868-
if text in element.text_all:
1869-
return True
1870-
now_ms = time.time() * 1000.0
1871-
if now_ms >= stop_ms:
1872-
break
1873-
time.sleep(0.1)
1874-
raise Exception(
1875-
"Text {%s} not found in {%s}! Actual text: {%s}"
1876-
% (text, selector, element.text_all)
1877-
)
1938+
"""Same as wait_for_text()"""
1939+
self.wait_for_text(text, selector=selector, timeout=timeout)
1940+
return True
18781941

18791942
def assert_exact_text(self, text, selector="body", timeout=None):
18801943
if not timeout:
@@ -1904,6 +1967,13 @@ def assert_exact_text(self, text, selector="body", timeout=None):
19041967
% (text, element.text_all, selector)
19051968
)
19061969

1970+
def assert_text_not_visible(self, text, selector="body", timeout=None):
1971+
"""Raises an exception if the text is still visible after timeout."""
1972+
self.wait_for_text_not_visible(
1973+
text, selector=selector, timeout=timeout
1974+
)
1975+
return True
1976+
19071977
def assert_true(self, expression):
19081978
if not expression:
19091979
raise AssertionError("%s is not true" % expression)

0 commit comments

Comments
(0)

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