Skip to content

Commit 6cb8844

Browse files
committedDec 15, 2024
Update examples
1 parent 0d6c255 commit 6cb8844

10 files changed

+187
-27
lines changed
 

‎examples/ReadMe.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
* <b>SeleniumBase</b> tests are run with <b>pytest</b>.
88
* Chrome is the default browser if not specified.
9-
* Tests are structured using [23 unique syntax formats](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md).
9+
* Tests are structured using [25 unique syntax formats](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md).
1010
* Logs from test failures are saved to ``./latest_logs/``.
1111
* Tests can be run with [multiple command-line options](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md).
1212
* Examples can be found in: **[SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples)**.

‎examples/cdp_mode/ReadMe.md

+45-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## [<img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="32">](https://github.com/seleniumbase/SeleniumBase/) CDP Mode 🐙
44

5-
🐙 <b translate="no">SeleniumBase</b> <b translate="no">CDP Mode</b> (Chrome Devtools Protocol Mode) is a special mode inside of <b><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md" translate="no"><span translate="no">SeleniumBase UC Mode</span></a></b> that lets bots appear human while controlling the browser with the <b translate="no">CDP-Driver</b>. Although regular <span translate="no">UC Mode</span> can't perform <span translate="no">WebDriver</span> actions while the <code>driver</code> is disconnected from the browser, the <span translate="no">CDP-Driver</span> can still perform actions while maintaining its cover.
5+
🐙 <b translate="no">SeleniumBase</b> <b translate="no">CDP Mode</b> (Chrome Devtools Protocol Mode) is a special mode inside of <b><a href="https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/uc_mode.md" translate="no"><span translate="no">SeleniumBase UC Mode</span></a></b> that lets bots appear human while controlling the browser with the <b translate="no">CDP-Driver</b>. Although regular <b translate="no">UC Mode</b> can't perform <span translate="no">WebDriver</span> actions while the <code>driver</code> is disconnected from the browser, the <b translate="no">CDP-Driver</b> can.
66

77
--------
88

@@ -13,7 +13,7 @@
1313

1414
👤 <b translate="no">UC Mode</b> avoids bot-detection by first disconnecting WebDriver from the browser at strategic times, calling special <code>PyAutoGUI</code> methods to bypass CAPTCHAs (as needed), and finally reconnecting the <code>driver</code> afterwards so that WebDriver actions can be performed again. Although this approach works for bypassing simple CAPTCHAs, more flexibility is needed for bypassing bot-detection on websites with advanced protection. (That's where <b translate="no">CDP Mode</b> comes in.)
1515

16-
🐙 <b translate="no">CDP Mode</b> is based on <a href="https://github.com/HyperionGray/python-chrome-devtools-protocol" translate="no">python-cdp</a>, <a href="https://github.com/HyperionGray/trio-chrome-devtools-protocol" translate="no">trio-cdp</a>, and <a href="https://github.com/ultrafunkamsterdam/nodriver" translate="no">nodriver</a>. <code>trio-cdp</code> is an early implementation of <code>python-cdp</code>, and <code>nodriver</code> is a modern implementation of <code>python-cdp</code>. (Refactored Python-CDP code is imported from <a href="https://github.com/mdmintz/MyCDP" translate="no">MyCDP</a>.)
16+
🐙 <b translate="no">CDP Mode</b> is based on <a href="https://github.com/HyperionGray/python-chrome-devtools-protocol" translate="no">python-cdp</a>, <a href="https://github.com/HyperionGray/trio-chrome-devtools-protocol" translate="no">trio-cdp</a>, and <a href="https://github.com/ultrafunkamsterdam/nodriver" translate="no">nodriver</a>. <code>trio-cdp</code> is an early implementation of <code>python-cdp</code>, and <code>nodriver</code> is a modern implementation of <code>python-cdp</code>. (Refactored <code>Python-CDP</code> code is imported from <a href="https://github.com/mdmintz/MyCDP" translate="no">MyCDP</a>.)
1717

1818
🐙 <b translate="no">CDP Mode</b> includes multiple updates to the above, such as:
1919

@@ -35,17 +35,52 @@
3535
3636
That disconnects WebDriver from Chrome (which prevents detection), and gives you access to `sb.cdp` methods (which don't trigger anti-bot checks).
3737

38+
Simple example: ([SeleniumBase/examples/cdp_mode/raw_planetmc.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_planetmc.py))
39+
40+
```python
41+
from seleniumbase import SB
42+
43+
with SB(uc=True, test=True) as sb:
44+
url = "www.planetminecraft.com/account/sign_in/"
45+
sb.activate_cdp_mode(url)
46+
sb.sleep(2)
47+
sb.cdp.gui_click_element("#turnstile-widget div")
48+
sb.sleep(2)
49+
```
50+
51+
<img src="https://seleniumbase.github.io/other/planet_mc.png" title="SeleniumBase" width="480">
52+
53+
(If the CAPTCHA wasn't initially bypassed, then the click gets the job done.)
54+
55+
Note that `PyAutoGUI` is an optional dependency. If calling a method that uses it when not already installed, then `SeleniumBase` will install it at run-time, which pauses the script briefly.
56+
57+
For standard Cloudflare pages, use `sb.uc_gui_click_captcha()` if Turnstiles aren't initially bypassed. Example: ([SeleniumBase/examples/cdp_mode/raw_gitlab.py](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_gitlab.py))
58+
59+
```python
60+
from seleniumbase import SB
61+
62+
with SB(uc=True, test=True, locale_code="en") as sb:
63+
url = "https://gitlab.com/users/sign_in"
64+
sb.activate_cdp_mode(url)
65+
sb.uc_gui_click_captcha()
66+
sb.sleep(2)
67+
```
68+
69+
<img src="https://seleniumbase.github.io/other/cf_sec.jpg" title="SeleniumBase" width="404"> <img src="https://seleniumbase.github.io/other/gitlab_bypass.png" title="SeleniumBase" width="350">
70+
71+
--------
72+
3873
### 🐙 Here are a few common `sb.cdp` methods:
3974

40-
* `sb.cdp.click(selector)`
75+
* `sb.cdp.click(selector)` (Uses the CDP API to click)
4176
* `sb.cdp.click_if_visible(selector)`
42-
* `sb.cdp.gui_click_element(selector)`
77+
* `sb.cdp.gui_click_element(selector)` (Uses `PyAutoGUI`)
4378
* `sb.cdp.type(selector, text)`
44-
* `sb.cdp.press_keys(selector, text)`
79+
* `sb.cdp.press_keys(selector, text)` (Human-speed `type`)
4580
* `sb.cdp.select_all(selector)`
4681
* `sb.cdp.get_text(selector)`
4782

48-
When `type()` is too fast, use the slower `press_keys()` to avoid detection. You can also use `sb.sleep(seconds)` to slow things down. Methods that start with `sb.cdp.gui` use `PyAutoGUI` for interaction.
83+
Methods that start with `sb.cdp.gui` use `PyAutoGUI` for interaction.
4984

5085
To use WebDriver methods again, call:
5186

@@ -57,15 +92,17 @@ To disconnect again, call:
5792

5893
* **`sb.disconnect()`**
5994

60-
While disconnected, if you accidentally call a WebDriver method, then SeleniumBase will attempt to use the CDP Mode version of that method (if available). For example, if you accidentally call `sb.click(selector)` instead of `sb.cdp.click(selector)`, then your WebDriver call will automatically be redirected to the CDP Mode version. Not all WebDriver methods have a matching CDP Mode method. In that scenario, calling a WebDriver method while disconnected could raise an error, or make WebDriver automatically reconnect first.
95+
While disconnected, if you accidentally call a WebDriver method, then <b translate="no">SeleniumBase</b> will attempt to use the <b translate="no">CDP Mode</b> version of that method (if available). For example, if you accidentally call `sb.click(selector)` instead of `sb.cdp.click(selector)`, then your WebDriver call will automatically be redirected to the <b translate="no">CDP Mode</b> version. Not all WebDriver methods have a matching <b translate="no">CDP Mode</b> method. In that scenario, calling a WebDriver method while disconnected could raise an error, or make WebDriver automatically reconnect first.
6196

6297
To find out if WebDriver is connected or disconnected, call:
6398

6499
* **`sb.is_connected()`**
65100

101+
<b>Note:</b> When <b translate="no">CDP Mode</b> is initialized from <b translate="no">UC Mode</b>, the WebDriver is disconnected from the browser. (The stealthy <b translate="no">CDP-Driver</b> takes over.)
102+
66103
--------
67104

68-
### 🐙 <b translate="no">CDP Mode</b> Examples ([SeleniumBase/examples/cdp_mode](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode))
105+
### 🐙 <b translate="no">CDP Mode</b> examples ([SeleniumBase/examples/cdp_mode](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode))
69106

70107
<p><div /></p>
71108

‎examples/cdp_mode/raw_planetmc.py

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

3-
with SB(uc=True, test=True, locale_code="en") as sb:
3+
with SB(uc=True, test=True) as sb:
44
url = "www.planetminecraft.com/account/sign_in/"
55
sb.activate_cdp_mode(url)
66
sb.sleep(2)

‎examples/cdp_mode/raw_tiktok.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
from seleniumbase import SB
22

3-
with SB(
4-
uc=True, test=True, locale_code="en", incognito=True, ad_block=True
5-
) as sb:
3+
with SB(uc=True, test=True, incognito=True, ad_block=True) as sb:
64
url = "https://www.tiktok.com/@startrek?lang=en"
75
sb.activate_cdp_mode(url)
86
sb.sleep(2.5)
9-
sb.cdp.click('button:contains("Refresh")')
7+
sb.cdp.click_if_visible('button:contains("Refresh")')
108
sb.sleep(1.5)
119
print(sb.cdp.get_text('h2[data-e2e="user-bio"]'))
12-
for i in range(55):
10+
for i in range(50):
1311
sb.cdp.scroll_down(12)
14-
sb.sleep(0.05)
1512
sb.sleep(1)

‎examples/presenter/uc_presentation_3.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ def test_presentation_3(self):
456456
"<hr /><h6><br /></h6>"
457457
"<p><mk-1>"
458458
"There are different ways of stucturing SeleniumBase scripts."
459-
' (Internally called: "The 23 Syntax Formats")'
459+
' (Internally called: "The 25 Syntax Formats")'
460460
"</mk-1><br /><br /><mk-2>"
461461
'Most examples use Syntax Format 1: "BaseCase direct class'
462462
' inheritance", which uses the "pytest" test runner.'

‎examples/raw_google.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from seleniumbase import SB
2+
3+
with SB(test=True, ad_block=True, locale_code="en") as sb:
4+
sb.open("https://google.com/ncr")
5+
sb.type('[title="Search"]', "SeleniumBase GitHub page\n")
6+
sb.click('[href*="github.com/seleniumbase/SeleniumBase"]')
7+
sb.save_screenshot_to_logs() # (See ./latest_logs folder)
8+
print(sb.get_page_title())

‎examples/test_download_files.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_download_files_from_pypi(self):
3131
self.assert_text("Download files", "a#files-tab")
3232
pkg_header = self.get_text("h1.package-header__name").strip()
3333
pkg_name = pkg_header.replace(" ", "-")
34-
whl_file = pkg_name + "-py2.py3-none-any.whl"
34+
whl_file = pkg_name + "-py3-none-any.whl"
3535
tar_gz_file = pkg_name + ".tar.gz"
3636

3737
# Click the links to download the files into: "./downloaded_files/"

‎examples/test_get_swag.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from seleniumbase import BaseCase
2+
BaseCase.main(__name__, __file__)
3+
4+
5+
class MyTestClass(BaseCase):
6+
def test_swag_labs(self):
7+
self.open("https://www.saucedemo.com")
8+
self.type("#user-name", "standard_user")
9+
self.type("#password", "secret_sauce\n")
10+
self.assert_element("div.inventory_list")
11+
self.click('button[name*="backpack"]')
12+
self.click("#shopping_cart_container a")
13+
self.assert_text("Backpack", "div.cart_item")
14+
self.click("button#checkout")
15+
self.type("input#first-name", "SeleniumBase")
16+
self.type("input#last-name", "Automation")
17+
self.type("input#postal-code", "77123")
18+
self.click("input#continue")
19+
self.click("button#finish")
20+
self.assert_text("Thank you for your order!")

‎examples/translations/italian_test_1.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ def test_esempio_1(self):
88
self.apri("https://it.wikipedia.org/wiki/")
99
self.verificare_testo("Wikipedia")
1010
self.verificare_elemento('a[title="Lingua italiana"]')
11-
self.digitare("#searchInput", "Pizza")
12-
self.fare_clic("#searchButton")
11+
self.digitare('input[name="search"]', "Pizza")
12+
self.fare_clic("#searchform button")
1313
self.verificare_testo("Pizza", "#firstHeading")
1414
self.verificare_elemento('figure img[src*="pizza"]')
15-
self.digitare("#searchInput", "Colosseo")
16-
self.fare_clic("#searchButton")
15+
self.digitare('input[name="search"]', "Colosseo")
16+
self.fare_clic("#searchform button")
1717
self.verificare_testo("Colosseo", "#firstHeading")
1818
self.verificare_elemento('figure img[src*="Colosseo"]')
1919
self.indietro()

‎help_docs/syntax_formats.md

+103-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<a id="syntax_formats"></a>
44

5-
<h2><img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="40"> The 23 Syntax Formats / Design Patterns</h2>
5+
<h2><img src="https://seleniumbase.github.io/img/logo6.png" title="SeleniumBase" width="40"> The 25 Syntax Formats / Design Patterns</h2>
66

77
<h3>🔠 SeleniumBase supports multiple ways of structuring tests:</h3>
88

@@ -32,6 +32,8 @@
3232
<li><a href="#sb_sf_21"><strong>21. SeleniumBase SB (Python context manager)</strong></a></li>
3333
<li><a href="#sb_sf_22"><strong>22. The driver manager (via context manager)</strong></a></li>
3434
<li><a href="#sb_sf_23"><strong>23. The driver manager (via direct import)</strong></a></li>
35+
<li><a href="#sb_sf_24"><strong>24. CDP driver (async/await API. No Selenium)</strong></a></li>
36+
<li><a href="#sb_sf_25"><strong>25. CDP driver (SB-CDP sync API. No Selenium)</strong></a></li>
3537
</ul>
3638
</blockquote>
3739

@@ -550,12 +552,12 @@ class MiaClasseDiTest(CasoDiProva):
550552
self.apri("https://it.wikipedia.org/wiki/")
551553
self.verificare_testo("Wikipedia")
552554
self.verificare_elemento('a[title="Lingua italiana"]')
553-
self.digitare("#searchInput", "Pizza")
554-
self.fare_clic("#searchButton")
555+
self.digitare('input[name="search"]', "Pizza")
556+
self.fare_clic("#searchform button")
555557
self.verificare_testo("Pizza", "#firstHeading")
556558
self.verificare_elemento('figure img[src*="pizza"]')
557-
self.digitare("#searchInput", "Colosseo")
558-
self.fare_clic("#searchButton")
559+
self.digitare('input[name="search"]', "Colosseo")
560+
self.fare_clic("#searchform button")
559561
self.verificare_testo("Colosseo", "#firstHeading")
560562
self.verificare_elemento('figure img[src*="Colosseo"]')
561563
self.indietro()
@@ -876,6 +878,21 @@ with SB(test=True, rtf=True, demo=True) as sb:
876878

877879
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/raw_test_scripts.py">examples/raw_test_scripts.py</a> for the test.)
878880

881+
Here's another example, which uses [CDP Mode](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/ReadMe.md) from the SeleniumBase SB format:
882+
883+
```python
884+
from seleniumbase import SB
885+
886+
with SB(uc=True, test=True) as sb:
887+
url = "www.planetminecraft.com/account/sign_in/"
888+
sb.activate_cdp_mode(url)
889+
sb.sleep(2)
890+
sb.cdp.gui_click_element("#turnstile-widget div")
891+
sb.sleep(2)
892+
```
893+
894+
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_planetmc.py">examples/cdp_mode/raw_planetmc.py</a> for the test.)
895+
879896
<a id="sb_sf_22"></a>
880897
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> 22. The driver manager (via context manager)</h2>
881898

@@ -994,6 +1011,87 @@ The ``Driver()`` manager format can be used as a drop-in replacement for virtual
9941011

9951012
When using the ``Driver()`` format, you may need to activate a Virtual Display on your own if you want to run headed tests in a headless Linux environment. (See https://github.com/mdmintz/sbVirtualDisplay for details.) One such example of this is using an authenticated proxy, which is configured via a Chrome extension that is generated at runtime. (Note that regular headless mode in Chrome doesn't support extensions.)
9961013

1014+
<a id="sb_sf_24"></a>
1015+
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> 24. CDP driver (async/await API. No Selenium)</h2>
1016+
1017+
This format provides a pure CDP way of using SeleniumBase (without Selenium or a test runner). The async/await API is used. Here's an example:
1018+
1019+
```python
1020+
import asyncio
1021+
import time
1022+
from seleniumbase.undetected import cdp_driver
1023+
1024+
1025+
async def main():
1026+
driver = await cdp_driver.cdp_util.start_async()
1027+
page = await driver.get("about:blank")
1028+
await page.set_locale("en")
1029+
await page.get("https://www.priceline.com/")
1030+
time.sleep(3)
1031+
print(await page.evaluate("document.title"))
1032+
element = await page.select('[data-testid*="endLocation"]')
1033+
await element.click_async()
1034+
time.sleep(1)
1035+
await element.send_keys_async("Boston")
1036+
time.sleep(2)
1037+
1038+
if __name__ == "__main__":
1039+
loop = asyncio.new_event_loop()
1040+
loop.run_until_complete(main())
1041+
```
1042+
1043+
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_async.py">examples/cdp_mode/raw_async.py</a> for the test.)
1044+
1045+
<a id="sb_sf_25"></a>
1046+
<h2><img src="https://seleniumbase.github.io/img/logo3b.png" title="SeleniumBase" width="32" /> 25. CDP driver (SB-CDP sync API. No Selenium)</h2>
1047+
1048+
This format provides a pure CDP way of using SeleniumBase (without Selenium or a test runner). The expanded SB-CDP sync API is used. Here's an example:
1049+
1050+
```python
1051+
import asyncio
1052+
from seleniumbase.core import sb_cdp
1053+
from seleniumbase.undetected import cdp_driver
1054+
1055+
1056+
def main():
1057+
url0 = "about:blank" # Set Locale code from here first
1058+
url1 = "https://www.priceline.com/" # (The "real" URL)
1059+
loop = asyncio.new_event_loop()
1060+
driver = cdp_driver.cdp_util.start_sync()
1061+
page = loop.run_until_complete(driver.get(url0))
1062+
sb = sb_cdp.CDPMethods(loop, page, driver)
1063+
sb.set_locale("en") # This test expects English locale
1064+
sb.open(url1)
1065+
sb.sleep(2.5)
1066+
sb.internalize_links() # Don't open links in a new tab
1067+
sb.click("#link_header_nav_experiences")
1068+
sb.sleep(3.5)
1069+
sb.remove_elements("msm-cookie-banner")
1070+
sb.sleep(1.5)
1071+
location = "Amsterdam"
1072+
where_to = 'div[data-automation*="experiences"] input'
1073+
button = 'button[data-automation*="experiences-search"]'
1074+
sb.gui_click_element(where_to)
1075+
sb.press_keys(where_to, location)
1076+
sb.sleep(1)
1077+
sb.gui_click_element(button)
1078+
sb.sleep(3)
1079+
print(sb.get_title())
1080+
print("************")
1081+
for i in range(8):
1082+
sb.scroll_down(50)
1083+
sb.sleep(0.2)
1084+
cards = sb.select_all('h2[data-automation*="product-list-card"]')
1085+
for card in cards:
1086+
print("* %s" % card.text)
1087+
1088+
1089+
if __name__ == "__main__":
1090+
main()
1091+
```
1092+
1093+
(See <a href="https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/raw_cdp.py">examples/cdp_mode/raw_cdp.py</a> for the test.)
1094+
9971095
--------
9981096

9991097
<h3 align="left"><a href="https://github.com/seleniumbase/SeleniumBase/"><img src="https://seleniumbase.github.io/img/sb_logo_10.png" title="SeleniumBase" width="280" /></a></h3>

0 commit comments

Comments
 (0)
Please sign in to comment.