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
52 changes: 43 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,40 @@
<br />
</p>

🐙 <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md"><b>CDP Mode</b></a> bypasses bot-detection and handles CAPTCHAs by driving the browser directly through the <a href="https://chromedevtools.github.io/devtools-protocol/" translate="no">Chrome DevTools Protocol</a>. Includes <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/playwright/ReadMe.md"><b><span translate="no">Stealthy Playwright Mode</span></b></a>, which extends these advanced anti-detection patches to Playwright scripts.
🐙 <a translate="no" href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md"><b>CDP Mode</b></a> <b>bypasses bot-detection</b> and handles CAPTCHAs with the <a href="https://chromedevtools.github.io/devtools-protocol/" translate="no">Chrome DevTools Protocol</a>. Includes <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/playwright/ReadMe.md"><b><span translate="no">Stealthy Playwright Mode</span></b></a>, which extends CDP Mode's anti-detection to <b>Playwright</b> scripts. <b><code>sb.solve_captcha()</code></b> handles CAPTCHAs that aren't bypassed automatically.

📚 The [SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder includes over 100 ready-to-run examples of E2E testing. Examples that start with `test_` or end with `_test.py`/`_tests.py` are specifically designed to run with `pytest`. Other examples run directly with raw `python` (those files generally start with `raw_` to avoid confusion).
<b>Python sync version of SeleniumBase's CDP Mode: (<code>sb_cdp</code>)</b>

```python
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome()
sb.open("https://demo.fingerprint.com/playground")
sb.sleep(3)
sb.driver.quit()
```

<b>Playwright can use SeleniumBase's stealth browser:</b>

```python
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)
page = browser.contexts[0].pages[0]
page.goto("https://browserscan.net/bot-detection")

sb.sleep(3)
sb.driver.quit()
```

--------

📚 The [SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples) folder includes over 150 ready-to-run examples of E2E testing. Examples that start with `test_` or end with `_test.py`/`_tests.py` run with `pytest`. Other examples run directly with raw `python` (those generally start with `raw_` to avoid confusion).

🥷 Stealthy CDP Mode examples are located in [./examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).

Expand All @@ -73,12 +104,12 @@
```python
from seleniumbase import sb_cdp

url = "https://www.browserscan.net/bot-detection"
sb = sb_cdp.Chrome(url, locale="en", ad_block=True)
sb.flash("Test Results", duration=3, pause=1)
sb = sb_cdp.Chrome(locale="en", ad_block=True)
sb.open("https://browserscan.net/bot-detection")
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.flash('strong:contains("Normal")', duration=3, pause=2)
sb.flash('strong:contains("Normal")', pause=1)
```

<img src="https://seleniumbase.github.io/other/b_scan_results.jpg" width="628" alt="Stealthy architecture flowchart" />
Expand All @@ -95,15 +126,18 @@ 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://www.browserscan.net/bot-detection")
page.goto("https://browserscan.net/bot-detection")
page.wait_for_timeout(500)
sb.flash("Test Results", duration=3, pause=1)
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
sb.flash('strong:contains("Normal")', duration=3, pause=2)
print("Bot Not Detected")
sb.flash('strong:contains("Normal")', pause=1)
```

--------

<h3 align="left">🌐 CLI Options for Supported Chromium Browsers</h3>

💡 You can set which Chromium browser to use via command-line options:

```zsh
Expand Down
22 changes: 11 additions & 11 deletions examples/cdp_mode/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
sb.assert_element('img[alt="Pikachu"]')
sb.scroll_into_view("div.pokemon-ability-info")
sb.sleep(1.2)
sb.cdp.flash('div[class*="title"]')
sb.cdp.flash('img[alt="Pikachu"]')
sb.cdp.flash("div.pokemon-ability-info")
sb.flash('div[class*="title"]')
sb.flash('img[alt="Pikachu"]')
sb.flash("div.pokemon-ability-info")
name = sb.get_text("label.styled-select")
info = sb.get_text("div.version-descriptions p.active")
print("*** %s: ***\n* %s" % (name, info))
sb.sleep(2)
sb.cdp.highlight_overlay("div.pokemon-ability-info")
sb.highlight_overlay("div.pokemon-ability-info")
sb.sleep(2)
sb.open("https://events.pokemon.com/EventLocator/")
sb.sleep(2)
Expand All @@ -186,10 +186,10 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
```python
from seleniumbase import SB

with SB(uc=True, test=True, locale="en") as sb:
with SB(uc=True, test=True, locale="en", guest=True) as sb:
url = "https://www.hyatt.com/"
sb.activate_cdp_mode(url)
sb.sleep(3.2)
sb.sleep(3.4)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.1)
sb.click_if_visible("#onetrust-reject-all-handler")
Expand All @@ -200,11 +200,11 @@ with SB(uc=True, test=True, locale="en") as sb:
sb.click('li[data-js="suggestion"]')
sb.sleep(0.6)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.6)
sb.sleep(0.8)
sb.click("button.be-button-shop")
sb.sleep(1)
sb.click_if_visible('[label="Find Hotels"]')
sb.sleep(5)
sb.sleep(5.5)
card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]'
hotels = sb.select_all(card_info)
print("Hyatt Hotels in %s:" % location)
Expand Down Expand Up @@ -285,7 +285,7 @@ with SB(uc=True, test=True, ad_block=True) as sb:
sb.sleep(1.8)
continue_button = 'button:contains("Continue shopping")'
if sb.is_element_visible(continue_button):
sb.cdp.gui_click_element(continue_button)
sb.gui_click_element(continue_button)
sb.sleep(0.6)
sb.click('input[aria-label="Search"]')
sb.sleep(1.2)
Expand All @@ -294,10 +294,10 @@ with SB(uc=True, test=True, ad_block=True) as sb:
sb.press_keys('input[aria-label="Search"]', search + "\n")
sb.sleep(3.8)
if sb.is_element_visible("#px-captcha"):
sb.cdp.gui_click_and_hold("#px-captcha", 7.2)
sb.gui_click_and_hold("#px-captcha", 7.2)
sb.sleep(4.2)
if sb.is_element_visible("#px-captcha"):
sb.cdp.gui_click_and_hold("#px-captcha", 4.2)
sb.gui_click_and_hold("#px-captcha", 4.2)
sb.sleep(3.2)
sb.remove_elements('[data-testid="skyline-ad"]')
sb.remove_elements('[data-testid="sba-container"]')
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ from seleniumbase import SB

with SB(uc=True) as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/raw_basic_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

with SB(uc=True) as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/raw_bing_cap_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

with SB(uc=True, locale="en") as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
8 changes: 4 additions & 4 deletions examples/cdp_mode/playwright/raw_browserscan_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

with SB(uc=True, locale="en", ad_block=True) as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
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://www.browserscan.net/bot-detection")
page.goto("https://browserscan.net/bot-detection")
page.wait_for_timeout(500)
sb.cdp.flash("Test Results", duration=3, pause=1)
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.cdp.flash('strong:contains("Normal")', duration=3, pause=2)
sb.flash('strong:contains("Normal")', pause=1)
6 changes: 3 additions & 3 deletions examples/cdp_mode/playwright/raw_browserscan_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
page = browser.contexts[0].pages[0]
page.goto("https://www.browserscan.net/bot-detection")
page.goto("https://browserscan.net/bot-detection")
page.wait_for_timeout(500)
sb.flash("Test Results", duration=3, pause=1)
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.flash('strong:contains("Normal")', duration=3, pause=2)
sb.flash('strong:contains("Normal")', pause=1)
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/raw_copilot_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

with SB(uc=True) as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
6 changes: 3 additions & 3 deletions examples/cdp_mode/playwright/raw_fingerprint_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

with SB(uc=True, locale="en") as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
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://demo.fingerprint.com/playground")
page.wait_for_timeout(500)
sb.cdp.flash('a[href*="browser-bot-detection"]', duration=3, pause=1)
sb.flash('a[href*="browser-bot-detection"]', duration=3, pause=1)
bot_row_selector = 'table:contains("Bot") tr:nth-of-type(3)'
print(sb.get_text(bot_row_selector))
sb.assert_text("Bot Not detected", bot_row_selector)
sb.cdp.flash(bot_row_selector, duration=3, pause=2)
sb.flash(bot_row_selector, duration=3, pause=2)
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/raw_gitlab_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

with SB(uc=True, locale="en") as sb:
sb.activate_cdp_mode()
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/playwright/raw_idealista_nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
sb.sleep(1)
sb.solve_captcha()
sb.sleep(2)
endpoint_url = sb.cdp.get_endpoint_url()
endpoint_url = sb.get_endpoint_url()

with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(endpoint_url)
Expand Down
2 changes: 1 addition & 1 deletion examples/cdp_mode/raw_amazon.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
sb.press_keys('input[role="searchbox"]', "TI-89\n")
sb.sleep(3)
for i in range(16):
sb.cdp.scroll_down(16)
sb.scroll_down(16)
print(sb.get_page_title())
sb.save_as_pdf_to_logs()
sb.save_page_source_to_logs()
Expand Down
6 changes: 3 additions & 3 deletions examples/cdp_mode/raw_browserscan.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from seleniumbase import SB

with SB(uc=True, test=True, locale="en", ad_block=True) as sb:
url = "https://www.browserscan.net/bot-detection"
url = "https://browserscan.net/bot-detection"
sb.activate_cdp_mode(url)
sb.cdp.flash("Test Results", duration=3, pause=1)
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.cdp.flash('strong:contains("Normal")', duration=3, pause=2)
sb.flash('strong:contains("Normal")', pause=1)
4 changes: 2 additions & 2 deletions examples/cdp_mode/raw_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def get_canvas_pixel_colors_at_top_left(sb):


with SB(uc=True, test=True) as sb:
# Testing sb.cdp.click_with_offset()
# Testing click_with_offset()
url = "https://seleniumbase.io/canvas/"
sb.activate_cdp_mode(url)
sb.assert_title_contains("Canvas")
Expand All @@ -25,7 +25,7 @@ def get_canvas_pixel_colors_at_top_left(sb):
sb.assert_equal(rgb, [39, 43, 56]) # Blue by hamburger

with SB(uc=True, test=True) as sb:
# Testing sb.cdp.gui_click_with_offset()
# Testing gui_click_with_offset()
url = "https://seleniumbase.io/other/canvas"
sb.activate_cdp_mode(url)
sb.assert_title_contains("Canvas")
Expand Down
8 changes: 4 additions & 4 deletions examples/cdp_mode/raw_cdp_browserscan.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from seleniumbase import sb_cdp

url = "https://www.browserscan.net/bot-detection"
sb = sb_cdp.Chrome(url, locale="en", ad_block=True)
sb.flash("Test Results", duration=3, pause=1)
sb = sb_cdp.Chrome(locale="en", ad_block=True)
sb.open("https://browserscan.net/bot-detection")
sb.flash("Test Results", duration=1.5, pause=0.5)
sb.assert_element('strong:contains("Normal")')
print("Bot Not Detected")
sb.flash('strong:contains("Normal")', duration=3, pause=2)
sb.flash('strong:contains("Normal")', pause=1)
4 changes: 2 additions & 2 deletions examples/cdp_mode/raw_cdp_fingerprint.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from seleniumbase import sb_cdp

url = "https://demo.fingerprint.com/playground"
sb = sb_cdp.Chrome(url)
sb = sb_cdp.Chrome()
sb.open("https://demo.fingerprint.com/playground")
sb.wait_for_element('a[href*="browser-bot-detection"]')
sb.flash('a[href*="browser-bot-detection"]', duration=3, pause=1)
bot_row_selector = 'table:contains("Bot") tr:nth-of-type(3)'
Expand Down
6 changes: 5 additions & 1 deletion examples/cdp_mode/raw_cdp_hyatt.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
sb.type('input[id="search-term"]', location)
sb.sleep(1.2)
sb.click('li[data-js="suggestion"]')
sb.sleep(1.2)
sb.sleep(0.6)
sb.click_if_visible('button[aria-label="Close"]')
sb.sleep(0.8)
sb.click("button.be-button-shop")
sb.sleep(1)
sb.click_if_visible('[label="Find Hotels"]')
sb.sleep(6)
card_info = 'div[data-booking-status="BOOKABLE"] [class*="HotelCard_info"]'
hotels = sb.select_all(card_info)
Expand Down
9 changes: 9 additions & 0 deletions examples/cdp_mode/raw_cdp_patent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from seleniumbase import sb_cdp

url = "https://www.lens.org/lens/patent/135-034-272-112-366/frontpage"
sb = sb_cdp.Chrome(url)
sb.sleep(3.5)
sb.solve_captcha()
sb.flash('[ng-if*="patent.title"]', duration=3, pause=2)
print("* " + sb.get_text('[ng-if*="patent.title"]') + " *")
print(sb.get_text("ol.claims"))
15 changes: 7 additions & 8 deletions examples/cdp_mode/raw_cdp_pixelscan.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
from seleniumbase import sb_cdp

url = "https://pixelscan.net/fingerprint-check"
sb = sb_cdp.Chrome(url, incognito=True)
sb = sb_cdp.Chrome(incognito=True)
sb.open("https://pixelscan.net/fingerprint-check")
sb.sleep(1)
sb.wait_for_element("pxlscn-dynamic-ad")
sb.sleep(0.5)
sb.remove_elements("pxlscn-dynamic-ad")
sb.sleep(2)
sb.assert_text("No masking detected", "pxlscn-fingerprint-masking")
sb.assert_text("No automated behavior", "pxlscn-bot-detection")
sb.highlight('span.status-success')
sb.sleep(1)
sb.assert_text("No automated behavior", "pxlscn-bot-detection")
sb.wait_for_element("span.status-success")
sb.assert_text("No masking detected", "pxlscn-fingerprint-masking")
sb.highlight("span.status-success")
sb.highlight("pxlscn-fingerprint-masking p")
sb.sleep(1)
sb.highlight("pxlscn-bot-detection p")
sb.sleep(2)
16 changes: 16 additions & 0 deletions examples/cdp_mode/raw_cdp_timezone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from seleniumbase import sb_cdp

sb = sb_cdp.Chrome(ad_block=True, incognito=True)
url = "https://www.randymajors.org/what-time-zone-am-i-in"
sb.open(url, tzone="Asia/Kolkata", geoloc=(26.863, 80.94))
sb.remove_elements("#right-sidebar")
sb.sleep(2.5)
sb.remove_elements('[data-google-query-id]')
sb.remove_elements("iframe:not(#embedMapFrame)")
sb.sleep(2.5)
sb.open(url, tzone="Asia/Tokyo", geoloc=(35.050681, 136.844728))
sb.remove_elements("#right-sidebar")
sb.sleep(2.5)
sb.remove_elements('[data-google-query-id]')
sb.remove_elements("iframe:not(#embedMapFrame)")
sb.sleep(2.5)
Loading