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
22 changes: 22 additions & 0 deletions examples/cdp_mode/playwright/raw_stealth_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Three stealth tests in one script!
from playwright.sync_api import expect, sync_playwright
from seleniumbase import sb_cdp

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

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
page = browser.contexts[0].pages[0]
page.goto("https://browserscan.net/bot-detection")
expect(page.locator('strong:has-text("Normal")')).to_be_visible()
page.goto("https://bot.sannysoft.com/")
expect(page.locator(".passed").first).to_be_visible()
expect(page.locator(".failed")).not_to_be_visible()
page.goto("https://www.planetminecraft.com/account")
page.locator('[name="email"]').press_sequentially("Name123", delay=105)
page.locator('[name="password"]').press_sequentially("Pass", delay=105)
sb.solve_captcha()
expect(page.locator('input[name="login"]')).to_be_visible()
expect(page.locator("input[disabled]")).not_to_be_visible()
page.wait_for_timeout(1000)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_ad_blocking.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async def block_urls(tab):
]
))

with decorators.print_runtime("raw_ad_blocking.py"):
with decorators.print_runtime():
sb = sb_cdp.Chrome()
loop = sb.get_event_loop()
loop.run_until_complete(block_urls(sb.get_active_tab()))
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_basic_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ async def main():
driver.quit()

if __name__ == "__main__":
with decorators.print_runtime("raw_basic_async.py"):
with decorators.print_runtime():
asyncio.run(main())
17 changes: 17 additions & 0 deletions examples/cdp_mode/raw_cdp_cloudflare.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome()
sb.goto("https://dash.cloudflare.com/sign-up")
sb.sleep(3)
sb.solve_captcha()
sb.sleep(3)
cookie_value = None
for cookie in sb.get_all_cookies():
if cookie.name == "cf_clearance":
cookie_value = cookie.value
break
if cookie_value:
print("cf_clearance cookie: %s" % cookie_value)
else:
print("Didn't find the cf_clearance cookie!")
sb.quit()
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_cdp_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ def main():


if __name__ == "__main__":
with decorators.print_runtime("raw_cdp_login.py"):
with decorators.print_runtime():
main()
40 changes: 24 additions & 16 deletions examples/cdp_mode/raw_cdp_swag.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
from seleniumbase import decorators
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome()
sb.goto("https://www.saucedemo.com")
sb.type("#user-name", "standard_user")
sb.type("#password", "secret_sauce\n")
sb.assert_element("div.inventory_list")
sb.click('button[name*="backpack"]')
sb.click("#shopping_cart_container a")
sb.assert_text("Backpack", "div.cart_item")
sb.click("button#checkout")
sb.type("input#first-name", "SeleniumBase")
sb.type("input#last-name", "Automation")
sb.type("input#postal-code", "77123")
sb.click("input#continue")
sb.click("button#finish")
sb.assert_text("Thank you for your order!")
sb.quit()

def main():
sb = sb_cdp.Chrome(fast=True)
sb.goto("https://www.saucedemo.com")
sb.type("#user-name", "standard_user")
sb.type("#password", "secret_sauce\n")
sb.assert_element("div.inventory_list")
sb.click('button[name*="backpack"]')
sb.click("#shopping_cart_container a")
sb.assert_text("Backpack", "div.cart_item")
sb.click("button#checkout")
sb.type("input#first-name", "SeleniumBase")
sb.type("input#last-name", "Automation")
sb.type("input#postal-code", "77123")
sb.click("input#continue")
sb.click("button#finish")
sb.assert_text("Thank you for your order!")
sb.quit()


if __name__ == "__main__":
with decorators.print_runtime():
main()
9 changes: 3 additions & 6 deletions examples/cdp_mode/raw_cf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@
with SB(uc=True, test=True, guest=True) as sb:
url = "https://seleniumbase.io/apps/turnstile"
sb.activate_cdp_mode(url)
sb.sleep(3)
sb.uc_gui_handle_captcha() # PyAutoGUI Tabs + Spacebar
sb.sleep(3)
sb.sleep(2)

with SB(uc=True, test=True, guest=True) as sb:
url = "https://seleniumbase.io/apps/turnstile"
sb.activate_cdp_mode(url)
sb.sleep(4)
sb.uc_gui_click_captcha() # PyAutoGUI mouse click
sb.sleep(3)
sb.sleep(2)

with SB(uc=True, test=True, guest=True) as sb:
url = "https://seleniumbase.io/apps/turnstile"
sb.activate_cdp_mode(url)
sb.sleep(4)
sb.solve_captcha() # CDP Input.dispatchMouseEvent
sb.sleep(3)
sb.sleep(2)
3 changes: 1 addition & 2 deletions examples/cdp_mode/raw_cf_clearance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@


def get_cf_clearance_cookie(sb):
all_cookies = sb.get_all_cookies()
for cookie in all_cookies:
for cookie in sb.get_all_cookies():
if cookie.name == "cf_clearance":
return cookie
return None
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_mobile_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ async def main():
driver.stop()

if __name__ == "__main__":
with decorators.print_runtime("raw_mobile_async.py"):
with decorators.print_runtime():
asyncio.run(main())
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_multi_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def run_main(url):

if __name__ == "__main__":
urls = ["https://seleniumbase.io/demo_page" for i in range(5)]
with decorators.print_runtime("raw_multi_async.py"):
with decorators.print_runtime():
with ThreadPoolExecutor(max_workers=len(urls)) as executor:
for url in urls:
executor.submit(run_main, url)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_multi_c_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def run_main(url):

if __name__ == "__main__":
urls = ["https://seleniumbase.io/apps/turnstile" for i in range(4)]
with decorators.print_runtime("raw_multi_c_async.py"):
with decorators.print_runtime():
with ThreadPoolExecutor(max_workers=len(urls)) as executor:
for url in urls:
executor.submit(run_main, url)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_multi_captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def main(url):

if __name__ == "__main__":
urls = ["https://www.bing.com/turing/captcha/challenge" for i in range(4)]
with decorators.print_runtime("raw_multi_captcha.py"):
with decorators.print_runtime():
with ThreadPoolExecutor(max_workers=len(urls)) as executor:
for url in urls:
executor.submit(main, url)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_multi_cdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def main(url):

if __name__ == "__main__":
urls = ["https://seleniumbase.io/demo_page" for i in range(5)]
with decorators.print_runtime("raw_multi_cdp.py"):
with decorators.print_runtime():
with ThreadPoolExecutor(max_workers=len(urls)) as executor:
for url in urls:
executor.submit(main, url)
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_tiktok.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
print("*** " + sb.get_text('h2[data-e2e="user-bio"]'))
sb.click_if_visible('button:contains("Refresh")')
sb.sleep(0.3)
for i in range(33):
for i in range(30):
sb.scroll_by_y(33)
sb.sleep(0.03)
items = sb.find_elements("picture img")
Expand Down
2 changes: 1 addition & 1 deletion mcp_servers/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "seleniumbase-mcp"
version = "1.5.1dev0"
version = "1.5.2dev0"
description = "MCP server exposing SeleniumBase CDP Mode as tools for MCP clients."
readme = "README.md"
requires-python = ">=3.10"
Expand Down
8 changes: 4 additions & 4 deletions mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# mkdocs dependencies for generating the seleniumbase.io website

regex>=2026.9.29
pipdeptree>=4.2.7
platformdirs>=4.13.0
nab>=0.0.19
pipdeptree>=4.2.8
platformdirs>=4.13.3
nab>=0.0.21
backrefs>=8.1
pymdown-extensions>=12.2
pymdown-extensions>=12.3
python-dateutil>=2.8.2
click>=8.5.0
Markdown==3.11.1
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ exceptiongroup>=1.3.1
websockets~=16.1.1;python_version=="3.10"
websockets>=16.1.1;python_version>="3.11"
filelock==4.1.0;python_version=="3.10"
filelock>=4.1.1;python_version>="3.11"
filelock>=4.2.0;python_version>="3.11"
fasteners>=0.20
mycdp>=1.4.0
pynose>=1.5.5
Expand Down Expand Up @@ -43,7 +43,8 @@ cssselect>=1.6.0,<2;python_version>="3.11"
sortedcontainers==2.4.0
execnet==2.1.2
iniconfig~=2.3.1
pluggy==1.6.0
pluggy==1.6.0;python_version<"3.11"
pluggy>=1.6.0,<1.8;python_version>="3.11"
pytest==8.4.2;python_version<"3.11"
pytest==9.1.1;python_version>="3.11"
pytest-html==4.0.2
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.56.1"
__version__ = "4.56.2"
18 changes: 17 additions & 1 deletion seleniumbase/common/decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import colorama
import logging
import math
import os
import sys
import time
import warnings
Expand Down Expand Up @@ -34,7 +35,22 @@ def my_method():
# code ...
# code ... """
if not description:
description = "Code Block"
frame = sys._getframe()
current_file = "decorators.py"
if "__file__" in globals():
current_file = os.path.basename(__file__)
while frame:
filename = frame.f_code.co_filename
base_name = os.path.basename(filename)
if base_name not in ("contextlib.py", current_file):
break
frame = frame.f_back
if frame:
filename = os.path.basename(frame.f_code.co_filename)
lineno = frame.f_lineno
description = f"{filename}:{lineno}"
else:
description = "Code Block"
description = str(description)
if limit:
limit = float("%.2f" % limit)
Expand Down
4 changes: 2 additions & 2 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "io.github.seleniumbase/seleniumbase",
"title": "SeleniumBase MCP",
"description": "Stealthy browser automation, testing, and web-scraping via CDP Mode.",
"version": "4.56.1",
"version": "4.56.2",
"repository": {
"url": "https://github.com/seleniumbase/SeleniumBase",
"source": "github"
Expand All @@ -13,7 +13,7 @@
{
"registryType": "pypi",
"identifier": "seleniumbase",
"version": "4.56.1",
"version": "4.56.2",
"transport": {
"type": "stdio"
},
Expand Down
12 changes: 7 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
'websockets~=16.1.1;python_version=="3.10"',
'websockets>=16.1.1;python_version>="3.11"',
'filelock==4.1.0;python_version=="3.10"',
'filelock>=4.1.1;python_version>="3.11"',
'filelock>=4.2.0;python_version>="3.11"',
'fasteners>=0.20',
'mycdp>=1.4.0',
'pynose>=1.5.5',
Expand Down Expand Up @@ -209,7 +209,8 @@
'sortedcontainers==2.4.0',
'execnet==2.1.2',
'iniconfig~=2.3.1',
'pluggy==1.6.0',
'pluggy==1.6.0;python_version<"3.11"',
'pluggy>=1.6.0,<1.8;python_version>="3.11"',
'pytest==8.4.2;python_version<"3.11"',
'pytest==9.1.1;python_version>="3.11"',
'pytest-html==4.0.2', # Newer ones had issues
Expand Down Expand Up @@ -293,9 +294,10 @@
# pip install -e .[playwright]
# (For the Playwright integration.)
"playwright": [
'playwright>=1.63.0',
'playwright>=1.64.0',
'greenlet>=3.5.6',
'pyee>=13.0.1',
'pyee>=13.0.1;python_version<"3.12"',
'pyee>=14.0.0;python_version>="3.12"',
],
# pip install -e .[pyautogui]
# (Already a required dependency on Linux now.)
Expand All @@ -305,7 +307,7 @@
# pip install -e .[uv]
# (For the MCP integration and more.)
"uv": [
"uv>=0.13.0"
"uv>=0.13.1"
],
},
packages=[
Expand Down
Loading