Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions examples/cdp_mode/playwright/raw_cf_cap_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from playwright.sync_api import sync_playwright
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome(locale="en")
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
context = browser.contexts[0]
page = context.pages[0]
page.goto("https://www.cloudflare.com/login")
sb.sleep(3)
sb.solve_captcha()
sb.sleep(3)
22 changes: 22 additions & 0 deletions examples/cdp_mode/playwright/raw_nike_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from playwright.sync_api import sync_playwright
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
context = browser.contexts[0]
page = context.pages[0]
page.goto("https://www.nike.com/")
page.click('[data-testid="user-tools-container"] search')
search = "Pegasus"
page.fill('input[type="search"]', search)
sb.sleep(4)
details = 'ul[data-testid*="products"] figure .details'
items = page.locator(details)
if items:
print('**** Found results for "%s": ****' % search)
for i in range(items.count()):
item = items.nth(i)
print(item.inner_text())
32 changes: 32 additions & 0 deletions examples/cdp_mode/playwright/raw_nordstrom_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from playwright.sync_api import sync_playwright
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome(locale="en")
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
context = browser.contexts[0]
page = context.pages[0]
page.goto("https://www.nordstrom.com/")
sb.sleep(2)
page.click("input#keyword-search-input")
sb.sleep(0.8)
search = "cocktail dresses for women teal"
sb.press_keys("input#keyword-search-input", search + "\n")
sb.sleep(2.2)
for i in range(17):
sb.scroll_down(16)
sb.sleep(0.14)
print('*** Nordstrom Search for "%s":' % search)
unique_item_text = []
items = sb.find_elements("article")
for item in items:
description = item.querySelector("article h3")
if description and description.text not in unique_item_text:
unique_item_text.append(description.text)
price_text = ""
price = item.querySelector('div div span[aria-hidden="true"]')
if price:
price_text = price.text
print("* %s (%s)" % (description.text, price_text))
6 changes: 3 additions & 3 deletions examples/cdp_mode/raw_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

def get_canvas_pixel_colors_at_top_left(sb):
# Return the RGB colors of the canvas's top left pixel
color = sb.cdp.evaluate(
color = sb.evaluate(
"document.querySelector('canvas').getContext('2d')"
".getImageData(%s,%s,1,1).data;" % (0, 0)
)
Expand All @@ -19,7 +19,7 @@ def get_canvas_pixel_colors_at_top_left(sb):
sb.highlight("canvas")
rgb = get_canvas_pixel_colors_at_top_left(sb)
sb.assert_equal(rgb, [221, 242, 231]) # Looks greenish
sb.cdp.click_with_offset("canvas", 500, 350)
sb.click_with_offset("canvas", 500, 350)
sb.highlight("canvas", loops=5)
rgb = get_canvas_pixel_colors_at_top_left(sb)
sb.assert_equal(rgb, [39, 43, 56]) # Blue by hamburger
Expand All @@ -29,7 +29,7 @@ def get_canvas_pixel_colors_at_top_left(sb):
url = "https://seleniumbase.io/other/canvas"
sb.activate_cdp_mode(url)
sb.assert_title_contains("Canvas")
sb.cdp.click_with_offset("canvas", 0, 0, center=True)
sb.click_with_offset("canvas", 0, 0, center=True)
sb.sleep(1)
sb.uc_gui_press_key("ENTER")
sb.sleep(0.5)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_ralphlauren.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
sb.open(url)
sb.sleep(1.2)
if not sb.is_element_present('[title="Locate Stores"]'):
sb.cdp.evaluate("window.location.reload();")
sb.evaluate("window.location.reload();")
sb.sleep(1.2)
category = "women"
search = "Dresses"
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_totalwine.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
search_box = 'input[data-at="header-search-text"]'
search = "The Land by Psagot Cabernet"
if not sb.is_element_present(search_box):
sb.cdp.evaluate("window.location.reload();")
sb.evaluate("window.location.reload();")
sb.sleep(1.8)
sb.click_if_visible("#onetrust-close-btn-container button")
sb.sleep(0.5)
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_zoro.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
search = "Flir Thermal Camera"
required_text = "Camera"
if not sb.is_element_present(search_box):
sb.cdp.evaluate("window.location.reload();")
sb.evaluate("window.location.reload();")
sb.sleep(1.2)
sb.click(search_box)
sb.sleep(1.2)
Expand Down
1 change: 1 addition & 0 deletions help_docs/method_summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ self.load_html_string(html_string, new_page=True)
self.set_content(html_string, new_page=False)
self.load_html_file(html_file, new_page=True)
self.open_html_file(html_file)
self.evaluate(expression)
self.execute_script(script, *args, **kwargs)
self.execute_cdp_cmd(script, *args, **kwargs)
self.execute_async_script(script, timeout=None)
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.45.7"
__version__ = "4.45.8"
14 changes: 12 additions & 2 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -6011,8 +6011,18 @@ def get_local_driver(
time.sleep(0.003)
driver.switch_to.window(driver.window_handles[0])
time.sleep(0.003)
driver.connect()
time.sleep(0.003)
# seleniumbase/SeleniumBase/discussions/4190
if getattr(sb_config, "skip_133_patch", None):
# To skip the connect() patch for Chrome 133+:
# from seleniumbase import config as sb_config
# sb_config.skip_133_patch = True
# (Do the above before launching the browser.)
pass
else:
# This fixes an issue on Chrome 133+
# (Some people might not need it though.)
driver.connect()
time.sleep(0.003)
if mobile_emulator:
uc_metrics = {}
if (
Expand Down
4 changes: 3 additions & 1 deletion seleniumbase/core/sb_cdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,9 @@ def click(self, selector, timeout=None):
if tag_name:
tag_name = tag_name.lower().strip()
if (
tag_name in ["a", "button", "canvas", "div", "input", "li", "span"]
tag_name in [
"a", "button", "canvas", "div", "input", "li", "span", "label"
]
and "contains(" not in selector
):
try:
Expand Down
40 changes: 40 additions & 0 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -3446,6 +3446,46 @@ def open_html_file(self, html_file):
file_path = os.path.join(abs_path, html_file)
self.open("file://" + file_path)

def evaluate(self, expression):
"""Run a JavaScript expression and return the result."""
self.__check_scope()
if self.__is_cdp_swap_needed():
return self.cdp.evaluate(expression)
self._check_browser()
original_expression = expression
expression = expression.strip()
exp_list = expression.split("\n")
if exp_list and exp_list[-1].strip().startswith("return "):
expression = (
"\n".join(exp_list[0:-1]) + "\n"
+ exp_list[-1].strip()[len("return "):]
).strip()
evaluation = self.driver.execute_cdp_cmd(
"Runtime.evaluate",
{
"expression": expression
},
)
if "value" in evaluation["result"]:
return evaluation["result"]["value"]
elif evaluation["result"]["type"] == "undefined":
return None
elif "exceptionDetails" in evaluation:
raise Exception(evaluation["result"]["description"], expression)
elif evaluation["result"]["type"] == "object":
if "return " not in original_expression:
expression = "return " + original_expression.strip()
# Need to use execute_script() to return a WebDriver object.
# If this causes duplicate evaluation, don't use evaluate().
return self.execute_script(expression)
elif evaluation["result"]["type"] == "function":
return {} # This is what sb.cdp.evaluate returns
elif "description" in evaluation["result"]:
# At this point, the description is the exception
raise Exception(evaluation["result"]["description"], expression)
else: # Possibly an unhandled case if reached
return None

def execute_script(self, script, *args, **kwargs):
self.__check_scope()
if self.__is_cdp_swap_needed():
Expand Down
6 changes: 4 additions & 2 deletions seleniumbase/undetected/cdp_driver/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,12 +639,14 @@ async def listener_loop(self):
or inspect.iscoroutine(callback)
):
try:
asyncio.create_task(callback(event, self))
asyncio.create_task(
callback(event, self.connection)
)
except TypeError:
asyncio.create_task(callback(event))
else:
try:
callback(event, self)
callback(event, self.connection)
except TypeError:
callback(event)
except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
# (An optional library for parsing PDF files.)
"pdfminer": [
'pdfminer.six==20251107;python_version<"3.10"',
'pdfminer.six==20251229;python_version>="3.10"',
'pdfminer.six==20251230;python_version>="3.10"',
'cryptography==46.0.3',
'cffi==2.0.0',
'pycparser==2.23',
Expand Down