seleniumbase 4.49.1__tar.gz → 4.49.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {seleniumbase-4.49.1/seleniumbase.egg-info → seleniumbase-4.49.2}/PKG-INFO +48 -12
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/README.md +43 -9
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/requirements.txt +2 -2
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__version__.py +1 -1
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/browser_launcher.py +9 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/sb_cdp.py +18 -14
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/sb_driver.py +18 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/base_case.py +58 -3
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/browser.py +2 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/tab.py +7 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2/seleniumbase.egg-info}/PKG-INFO +48 -12
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/requires.txt +8 -2
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/setup.py +5 -3
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/.gitignore +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/LICENSE +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/MANIFEST.in +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/install.sh +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/pyproject.toml +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/pytest.ini +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/__main__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/steps.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__main__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/behave_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/behave_sb.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/steps.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/decorators.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/encryption.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/exceptions.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/obfuscate.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/unobfuscate.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/ad_block_list.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/proxy_list.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/settings.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/logo_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/rich_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/run.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_commander.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_install.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_objectify.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_print.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_recorder.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/application_manager.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/capabilities_parser.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/colored_traceback.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/create_db_tables.sql +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/detect_b_ver.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/download_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/encoded_images.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/jqc_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/log_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/mysql.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/nest_asyncio.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/proxy_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/recorder_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/report_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/s3_manager.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/session_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/settings_parser.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/style_sheet.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/testcase_manager.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/tour_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/visual_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/ad_block.zip +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/disable_csp.zip +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/recorder.zip +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/sbase_ext.zip +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/constants.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/css_to_xpath.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/errors.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/js_utils.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/page_actions.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/page_utils.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/shared_utils.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/unittest_helper.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/words.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/xpath_to_css.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/active_css_js.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/live_js.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/recorder_js.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/masterqa/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/masterqa/master_qa.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/base_plugin.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/basic_test_info.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/driver_manager.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/page_source.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/pytest_plugin.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/sb_manager.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/screen_shots.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/selenium_plugin.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/resources/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/chinese.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/dutch.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/french.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/italian.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/japanese.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/korean.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/master_dict.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/portuguese.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/russian.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/spanish.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/translator.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/config.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/connection.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/element.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/dprocess.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/options.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/patcher.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/reactor.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/webelement.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/font_color +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/SOURCES.txt +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/dependency_links.txt +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/entry_points.txt +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/top_level.txt +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/setup.cfg +0 -0
- {seleniumbase-4.49.1 → seleniumbase-4.49.2}/virtualenv_install.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seleniumbase
|
|
3
|
-
Version: 4.49.
|
|
3
|
+
Version: 4.49.2
|
|
4
4
|
Summary: A framework for stealthy Chromium automation with CDP Mode. Includes CAPTCHA-bypass, E2E Testing, and a Playwright integration.
|
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
|
6
6
|
Author: Michael Mintz
|
|
@@ -65,7 +65,7 @@ Requires-Dist: setuptools~=70.2; python_version < "3.10"
|
|
|
65
65
|
Requires-Dist: setuptools>=82.0.1; python_version >= "3.10"
|
|
66
66
|
Requires-Dist: wheel>=0.47.0
|
|
67
67
|
Requires-Dist: attrs>=26.1.0
|
|
68
|
-
Requires-Dist: certifi>=2026.
|
|
68
|
+
Requires-Dist: certifi>=2026.5.20
|
|
69
69
|
Requires-Dist: exceptiongroup>=1.3.1
|
|
70
70
|
Requires-Dist: websockets~=15.0.1; python_version < "3.10"
|
|
71
71
|
Requires-Dist: websockets>=16.0; python_version >= "3.10"
|
|
@@ -90,7 +90,7 @@ Requires-Dist: pygments>=2.20.0
|
|
|
90
90
|
Requires-Dist: pyreadline3>=3.5.4; platform_system == "Windows"
|
|
91
91
|
Requires-Dist: tabcompleter>=1.4.1
|
|
92
92
|
Requires-Dist: pdbp>=1.8.2
|
|
93
|
-
Requires-Dist: idna>=3.
|
|
93
|
+
Requires-Dist: idna>=3.16
|
|
94
94
|
Requires-Dist: charset-normalizer<4,>=3.4.7
|
|
95
95
|
Requires-Dist: urllib3<2,>=1.26.20; python_version < "3.10"
|
|
96
96
|
Requires-Dist: urllib3<3,>=2.7.0; python_version >= "3.10"
|
|
@@ -168,6 +168,8 @@ Provides-Extra: proxy
|
|
|
168
168
|
Requires-Dist: proxy.py==2.4.3; extra == "proxy"
|
|
169
169
|
Provides-Extra: playwright
|
|
170
170
|
Requires-Dist: playwright>=1.60.0; extra == "playwright"
|
|
171
|
+
Requires-Dist: greenlet>=3.2.5; python_version < "3.10" and extra == "playwright"
|
|
172
|
+
Requires-Dist: greenlet>=3.5.1; python_version >= "3.10" and extra == "playwright"
|
|
171
173
|
Provides-Extra: pyautogui
|
|
172
174
|
Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
|
|
173
175
|
Provides-Extra: selenium-stealth
|
|
@@ -250,9 +252,40 @@ Dynamic: summary
|
|
|
250
252
|
<br />
|
|
251
253
|
</p>
|
|
252
254
|
|
|
253
|
-
🐙 <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
|
|
255
|
+
🐙 <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.
|
|
254
256
|
|
|
255
|
-
|
|
257
|
+
<b>Python sync version of SeleniumBase's CDP Mode: (<code>sb_cdp</code>)</b>
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
from seleniumbase import sb_cdp
|
|
261
|
+
|
|
262
|
+
sb = sb_cdp.Chrome()
|
|
263
|
+
sb.open("https://demo.fingerprint.com/playground")
|
|
264
|
+
sb.sleep(3)
|
|
265
|
+
sb.driver.quit()
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
<b>Playwright can use SeleniumBase's stealth browser:</b>
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from playwright.sync_api import sync_playwright
|
|
272
|
+
from seleniumbase import sb_cdp
|
|
273
|
+
|
|
274
|
+
sb = sb_cdp.Chrome()
|
|
275
|
+
endpoint_url = sb.get_endpoint_url()
|
|
276
|
+
|
|
277
|
+
with sync_playwright() as p:
|
|
278
|
+
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
279
|
+
page = browser.contexts[0].pages[0]
|
|
280
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
281
|
+
|
|
282
|
+
sb.sleep(3)
|
|
283
|
+
sb.driver.quit()
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
--------
|
|
287
|
+
|
|
288
|
+
📚 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).
|
|
256
289
|
|
|
257
290
|
🥷 Stealthy CDP Mode examples are located in [./examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).
|
|
258
291
|
|
|
@@ -273,12 +306,12 @@ Dynamic: summary
|
|
|
273
306
|
```python
|
|
274
307
|
from seleniumbase import sb_cdp
|
|
275
308
|
|
|
276
|
-
|
|
277
|
-
sb
|
|
278
|
-
sb.flash("Test Results", duration=
|
|
309
|
+
sb = sb_cdp.Chrome(locale="en", ad_block=True)
|
|
310
|
+
sb.open("https://browserscan.net/bot-detection")
|
|
311
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
279
312
|
sb.assert_element('strong:contains("Normal")')
|
|
280
313
|
print("Bot Not Detected")
|
|
281
|
-
sb.flash('strong:contains("Normal")',
|
|
314
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
282
315
|
```
|
|
283
316
|
|
|
284
317
|
<img src="https://seleniumbase.github.io/other/b_scan_results.jpg" width="628" alt="Stealthy architecture flowchart" />
|
|
@@ -295,15 +328,18 @@ endpoint_url = sb.get_endpoint_url()
|
|
|
295
328
|
with sync_playwright() as p:
|
|
296
329
|
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
297
330
|
page = browser.contexts[0].pages[0]
|
|
298
|
-
page.goto("https://
|
|
331
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
299
332
|
page.wait_for_timeout(500)
|
|
300
|
-
sb.flash("Test Results", duration=
|
|
333
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
301
334
|
sb.assert_element('strong:contains("Normal")')
|
|
302
|
-
|
|
335
|
+
print("Bot Not Detected")
|
|
336
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
303
337
|
```
|
|
304
338
|
|
|
305
339
|
--------
|
|
306
340
|
|
|
341
|
+
<h3 align="left">🌐 CLI Options for Supported Chromium Browsers</h3>
|
|
342
|
+
|
|
307
343
|
💡 You can set which Chromium browser to use via command-line options:
|
|
308
344
|
|
|
309
345
|
```zsh
|
|
@@ -50,9 +50,40 @@
|
|
|
50
50
|
<br />
|
|
51
51
|
</p>
|
|
52
52
|
|
|
53
|
-
🐙 <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
|
|
53
|
+
🐙 <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.
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
<b>Python sync version of SeleniumBase's CDP Mode: (<code>sb_cdp</code>)</b>
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from seleniumbase import sb_cdp
|
|
59
|
+
|
|
60
|
+
sb = sb_cdp.Chrome()
|
|
61
|
+
sb.open("https://demo.fingerprint.com/playground")
|
|
62
|
+
sb.sleep(3)
|
|
63
|
+
sb.driver.quit()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
<b>Playwright can use SeleniumBase's stealth browser:</b>
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from playwright.sync_api import sync_playwright
|
|
70
|
+
from seleniumbase import sb_cdp
|
|
71
|
+
|
|
72
|
+
sb = sb_cdp.Chrome()
|
|
73
|
+
endpoint_url = sb.get_endpoint_url()
|
|
74
|
+
|
|
75
|
+
with sync_playwright() as p:
|
|
76
|
+
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
77
|
+
page = browser.contexts[0].pages[0]
|
|
78
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
79
|
+
|
|
80
|
+
sb.sleep(3)
|
|
81
|
+
sb.driver.quit()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
--------
|
|
85
|
+
|
|
86
|
+
📚 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).
|
|
56
87
|
|
|
57
88
|
🥷 Stealthy CDP Mode examples are located in [./examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).
|
|
58
89
|
|
|
@@ -73,12 +104,12 @@
|
|
|
73
104
|
```python
|
|
74
105
|
from seleniumbase import sb_cdp
|
|
75
106
|
|
|
76
|
-
|
|
77
|
-
sb
|
|
78
|
-
sb.flash("Test Results", duration=
|
|
107
|
+
sb = sb_cdp.Chrome(locale="en", ad_block=True)
|
|
108
|
+
sb.open("https://browserscan.net/bot-detection")
|
|
109
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
79
110
|
sb.assert_element('strong:contains("Normal")')
|
|
80
111
|
print("Bot Not Detected")
|
|
81
|
-
sb.flash('strong:contains("Normal")',
|
|
112
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
82
113
|
```
|
|
83
114
|
|
|
84
115
|
<img src="https://seleniumbase.github.io/other/b_scan_results.jpg" width="628" alt="Stealthy architecture flowchart" />
|
|
@@ -95,15 +126,18 @@ endpoint_url = sb.get_endpoint_url()
|
|
|
95
126
|
with sync_playwright() as p:
|
|
96
127
|
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
97
128
|
page = browser.contexts[0].pages[0]
|
|
98
|
-
page.goto("https://
|
|
129
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
99
130
|
page.wait_for_timeout(500)
|
|
100
|
-
sb.flash("Test Results", duration=
|
|
131
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
101
132
|
sb.assert_element('strong:contains("Normal")')
|
|
102
|
-
|
|
133
|
+
print("Bot Not Detected")
|
|
134
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
103
135
|
```
|
|
104
136
|
|
|
105
137
|
--------
|
|
106
138
|
|
|
139
|
+
<h3 align="left">🌐 CLI Options for Supported Chromium Browsers</h3>
|
|
140
|
+
|
|
107
141
|
💡 You can set which Chromium browser to use via command-line options:
|
|
108
142
|
|
|
109
143
|
```zsh
|
|
@@ -5,7 +5,7 @@ setuptools~=70.2;python_version<"3.10"
|
|
|
5
5
|
setuptools>=82.0.1;python_version>="3.10"
|
|
6
6
|
wheel>=0.47.0
|
|
7
7
|
attrs>=26.1.0
|
|
8
|
-
certifi>=2026.
|
|
8
|
+
certifi>=2026.5.20
|
|
9
9
|
exceptiongroup>=1.3.1
|
|
10
10
|
websockets~=15.0.1;python_version<"3.10"
|
|
11
11
|
websockets>=16.0;python_version>="3.10"
|
|
@@ -30,7 +30,7 @@ pygments>=2.20.0
|
|
|
30
30
|
pyreadline3>=3.5.4;platform_system=="Windows"
|
|
31
31
|
tabcompleter>=1.4.1
|
|
32
32
|
pdbp>=1.8.2
|
|
33
|
-
idna>=3.
|
|
33
|
+
idna>=3.16
|
|
34
34
|
charset-normalizer>=3.4.7,<4
|
|
35
35
|
urllib3>=1.26.20,<2;python_version<"3.10"
|
|
36
36
|
urllib3>=2.7.0,<3;python_version>="3.10"
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# seleniumbase package
|
|
2
|
-
__version__ = "4.49.
|
|
2
|
+
__version__ = "4.49.2"
|
|
@@ -176,8 +176,11 @@ def extend_driver(
|
|
|
176
176
|
driver.forward = DM.forward
|
|
177
177
|
driver.refresh = DM.refresh
|
|
178
178
|
driver.locator = DM.locator
|
|
179
|
+
driver.select = DM.select
|
|
180
|
+
driver.select_all = DM.select_all
|
|
179
181
|
page = types.SimpleNamespace()
|
|
180
182
|
page.open = DM.open_url
|
|
183
|
+
page.goto = DM.open_url
|
|
181
184
|
page.click = DM.click
|
|
182
185
|
page.click_link = DM.click_link
|
|
183
186
|
page.click_if_visible = DM.click_if_visible
|
|
@@ -210,6 +213,8 @@ def extend_driver(
|
|
|
210
213
|
page.find_element = DM.find_element
|
|
211
214
|
page.find_elements = DM.find_elements
|
|
212
215
|
page.locator = DM.locator
|
|
216
|
+
page.select = DM.select
|
|
217
|
+
page.select_all = DM.select_all
|
|
213
218
|
page.get_current_url = DM.get_current_url
|
|
214
219
|
page.get_page_source = DM.get_page_source
|
|
215
220
|
page.get_title = DM.get_title
|
|
@@ -231,6 +236,7 @@ def extend_driver(
|
|
|
231
236
|
js.highlight = DM.highlight
|
|
232
237
|
driver.js = js
|
|
233
238
|
driver.open = DM.open_url
|
|
239
|
+
driver.goto = DM.open_url
|
|
234
240
|
driver.click = DM.click
|
|
235
241
|
driver.click_link = DM.click_link
|
|
236
242
|
driver.click_if_visible = DM.click_if_visible
|
|
@@ -291,6 +297,7 @@ def extend_driver(
|
|
|
291
297
|
driver.switch_to_default_window = DM.switch_to_default_window
|
|
292
298
|
driver.switch_to_newest_window = DM.switch_to_newest_window
|
|
293
299
|
driver.open_new_window = DM.open_new_window
|
|
300
|
+
driver.switch_to_newest_tab = DM.switch_to_newest_tab
|
|
294
301
|
driver.open_new_tab = DM.open_new_tab
|
|
295
302
|
driver.switch_to_window = DM.switch_to_window
|
|
296
303
|
driver.switch_to_tab = DM.switch_to_tab
|
|
@@ -759,6 +766,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
759
766
|
CDPM = sb_cdp.CDPMethods(loop, page, driver)
|
|
760
767
|
cdp.get = CDPM.get
|
|
761
768
|
cdp.open = CDPM.open
|
|
769
|
+
cdp.goto = CDPM.goto
|
|
762
770
|
cdp.reload = CDPM.reload
|
|
763
771
|
cdp.refresh = CDPM.refresh
|
|
764
772
|
cdp.add_handler = CDPM.add_handler
|
|
@@ -972,6 +980,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
972
980
|
driver.solve_captcha = CDPM.solve_captcha
|
|
973
981
|
driver.click_captcha = CDPM.click_captcha
|
|
974
982
|
driver.find_element_by_text = CDPM.find_element_by_text
|
|
983
|
+
driver.flash = CDPM.flash
|
|
975
984
|
driver._is_using_cdp = True
|
|
976
985
|
if (
|
|
977
986
|
getattr(sb_config, "_cdp_proxy", None)
|
|
@@ -155,6 +155,9 @@ class CDPMethods():
|
|
|
155
155
|
def open(self, url, **kwargs):
|
|
156
156
|
self.get(url, **kwargs)
|
|
157
157
|
|
|
158
|
+
def goto(self, url, **kwargs):
|
|
159
|
+
self.get(url, **kwargs)
|
|
160
|
+
|
|
158
161
|
def reload(self, ignore_cache=True, script_to_evaluate_on_load=None):
|
|
159
162
|
self.loop.run_until_complete(
|
|
160
163
|
self.page.reload(
|
|
@@ -2033,6 +2036,13 @@ class CDPMethods():
|
|
|
2033
2036
|
self.__slow_mode_pause_if_set()
|
|
2034
2037
|
self.loop.run_until_complete(self.page.wait(0.2))
|
|
2035
2038
|
|
|
2039
|
+
def quit(self):
|
|
2040
|
+
"""Quit the browser in the Pure CDP Mode Sync format."""
|
|
2041
|
+
driver = self.driver
|
|
2042
|
+
if hasattr(driver, "cdp_base"):
|
|
2043
|
+
driver = driver.cdp_base
|
|
2044
|
+
driver.quit()
|
|
2045
|
+
|
|
2036
2046
|
def _on_a_cf_turnstile_page(self, source=None):
|
|
2037
2047
|
if not source or len(source) < 400:
|
|
2038
2048
|
time.sleep(0.2)
|
|
@@ -2325,28 +2335,22 @@ class CDPMethods():
|
|
|
2325
2335
|
'form div:not([class]):has(input[name*="cf-turn"])'
|
|
2326
2336
|
):
|
|
2327
2337
|
selector = 'form div:not([class]):has(input[name*="cf-turn"])'
|
|
2328
|
-
elif self.is_element_present("form div:not(:has(*))"):
|
|
2329
|
-
selector = "form div:not(:has(*))"
|
|
2330
2338
|
elif self.is_element_present("body > div#check > div:not([class])"):
|
|
2331
2339
|
selector = "body > div#check > div:not([class])"
|
|
2332
2340
|
elif self.is_element_present(".cf-turnstile-wrapper"):
|
|
2333
2341
|
selector = ".cf-turnstile-wrapper"
|
|
2334
|
-
elif self.is_element_present(
|
|
2335
|
-
'[id*="turnstile"] div:not([class])'
|
|
2336
|
-
):
|
|
2342
|
+
elif self.is_element_present('[id*="turnstile"] div:not([class])'):
|
|
2337
2343
|
selector = '[id*="turnstile"] div:not([class])'
|
|
2338
|
-
elif self.is_element_present(
|
|
2339
|
-
'[class*="turnstile"] div:not([class])'
|
|
2340
|
-
):
|
|
2344
|
+
elif self.is_element_present('[class*="turnstile"] div:not([class])'):
|
|
2341
2345
|
selector = '[class*="turnstile"] div:not([class])'
|
|
2342
|
-
elif self.is_element_present(
|
|
2343
|
-
"iframe[data-hcaptcha-widget-id]"
|
|
2344
|
-
):
|
|
2346
|
+
elif self.is_element_present("iframe[data-hcaptcha-widget-id]"):
|
|
2345
2347
|
selector = "iframe[data-hcaptcha-widget-id]"
|
|
2346
|
-
elif self.is_element_present(
|
|
2347
|
-
'[data-callback="onCaptchaSuccess"]'
|
|
2348
|
-
):
|
|
2348
|
+
elif self.is_element_present('[data-callback="onCaptchaSuccess"]'):
|
|
2349
2349
|
selector = '[data-callback="onCaptchaSuccess"]'
|
|
2350
|
+
elif self.is_element_present('[class*="captcha"] div:not([class])'):
|
|
2351
|
+
selector = '[class*="captcha"] div:not([class])'
|
|
2352
|
+
elif self.is_element_present("form div:not(:has(*))"):
|
|
2353
|
+
selector = "form div:not(:has(*))"
|
|
2350
2354
|
elif self.is_element_present(
|
|
2351
2355
|
"div:not([class]):not([id]):not([aria-label]) > "
|
|
2352
2356
|
"div:not([class]):not([id]):not([aria-label])"
|
|
@@ -41,6 +41,18 @@ class DriverMethods(WebDriver):
|
|
|
41
41
|
value, by = page_utils.swap_selector_and_by_if_reversed(value, by)
|
|
42
42
|
return self.driver.default_find_elements(by=by, value=value)
|
|
43
43
|
|
|
44
|
+
def select(self, *args, **kwargs):
|
|
45
|
+
if self.__is_cdp_swap_needed():
|
|
46
|
+
return self.driver.cdp.select(*args, **kwargs)
|
|
47
|
+
else:
|
|
48
|
+
return self.find_element(*args, **kwargs)
|
|
49
|
+
|
|
50
|
+
def select_all(self, *args, **kwargs):
|
|
51
|
+
if self.__is_cdp_swap_needed():
|
|
52
|
+
return self.driver.cdp.select_all(*args, **kwargs)
|
|
53
|
+
else:
|
|
54
|
+
return self.find_elements(*args, **kwargs)
|
|
55
|
+
|
|
44
56
|
def add_cookie(self, *args, **kwargs):
|
|
45
57
|
page_actions._reconnect_if_disconnected(self.driver)
|
|
46
58
|
self.driver.default_add_cookie(*args, **kwargs)
|
|
@@ -372,6 +384,12 @@ class DriverMethods(WebDriver):
|
|
|
372
384
|
def switch_to_window(self, *args, **kwargs):
|
|
373
385
|
page_actions.switch_to_window(self.driver, *args, **kwargs)
|
|
374
386
|
|
|
387
|
+
def switch_to_newest_tab(self):
|
|
388
|
+
if self.__is_cdp_swap_needed():
|
|
389
|
+
self.driver.cdp.switch_to_newest_tab()
|
|
390
|
+
return
|
|
391
|
+
self.switch_to_newest_window()
|
|
392
|
+
|
|
375
393
|
def switch_to_tab(self, *args, **kwargs):
|
|
376
394
|
self.switch_to_window(*args, **kwargs)
|
|
377
395
|
|
|
@@ -5096,8 +5096,32 @@ class BaseCase(unittest.TestCase):
|
|
|
5096
5096
|
self.solve_captcha = self.cdp.solve_captcha
|
|
5097
5097
|
if hasattr(self.cdp, "click_captcha"):
|
|
5098
5098
|
self.click_captcha = self.cdp.click_captcha
|
|
5099
|
+
if hasattr(self.cdp, "add_handler"):
|
|
5100
|
+
self.add_handler = self.cdp.add_handler
|
|
5101
|
+
if hasattr(self.cdp, "close_active_tab"):
|
|
5102
|
+
self.close_active_tab = self.cdp.close_active_tab
|
|
5099
5103
|
if hasattr(self.cdp, "find_element_by_text"):
|
|
5100
5104
|
self.find_element_by_text = self.cdp.find_element_by_text
|
|
5105
|
+
if hasattr(self.cdp, "flash"):
|
|
5106
|
+
self.flash = self.cdp.flash
|
|
5107
|
+
if hasattr(self.cdp, "get_active_tab"):
|
|
5108
|
+
self.get_active_tab = self.cdp.get_active_tab
|
|
5109
|
+
if hasattr(self.cdp, "get_endpoint_url"):
|
|
5110
|
+
self.get_endpoint_url = self.cdp.get_endpoint_url
|
|
5111
|
+
if hasattr(self.cdp, "get_event_loop"):
|
|
5112
|
+
self.get_event_loop = self.cdp.get_event_loop
|
|
5113
|
+
if hasattr(self.cdp, "get_tabs"):
|
|
5114
|
+
self.get_tabs = self.cdp.get_tabs
|
|
5115
|
+
if hasattr(self.cdp, "gui_click_and_hold"):
|
|
5116
|
+
self.gui_click_and_hold = self.cdp.gui_click_and_hold
|
|
5117
|
+
if hasattr(self.cdp, "gui_click_element"):
|
|
5118
|
+
self.gui_click_element = self.cdp.gui_click_element
|
|
5119
|
+
if hasattr(self.cdp, "gui_drag_and_drop"):
|
|
5120
|
+
self.gui_drag_and_drop = self.cdp.gui_drag_and_drop
|
|
5121
|
+
if hasattr(self.cdp, "gui_drag_drop_points"):
|
|
5122
|
+
self.gui_drag_drop_points = self.cdp.gui_drag_drop_points
|
|
5123
|
+
if hasattr(self.cdp, "highlight_overlay"):
|
|
5124
|
+
self.highlight_overlay = self.cdp.highlight_overlay
|
|
5101
5125
|
if getattr(self.driver, "_is_using_auth", None):
|
|
5102
5126
|
with suppress(Exception):
|
|
5103
5127
|
self.cdp.loop.run_until_complete(self.cdp.page.wait(0.25))
|
|
@@ -8861,9 +8885,22 @@ class BaseCase(unittest.TestCase):
|
|
|
8861
8885
|
element = page_actions.wait_for_element_present(
|
|
8862
8886
|
self.driver, selector, by, timeout
|
|
8863
8887
|
)
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8888
|
+
try:
|
|
8889
|
+
if element.tag_name.lower() in ["input", "textarea"]:
|
|
8890
|
+
self.js_update_text(selector, text, by=by, timeout=timeout)
|
|
8891
|
+
return
|
|
8892
|
+
except (Stale_Exception, ENI_Exception):
|
|
8893
|
+
time.sleep(0.16)
|
|
8894
|
+
if self.__is_cdp_swap_needed():
|
|
8895
|
+
element = self.cdp.select(selector, timeout=timeout)
|
|
8896
|
+
else:
|
|
8897
|
+
self.wait_for_ready_state_complete()
|
|
8898
|
+
element = page_actions.wait_for_element_present(
|
|
8899
|
+
self.driver, selector, by, timeout
|
|
8900
|
+
)
|
|
8901
|
+
if element.tag_name.lower() in ["input", "textarea"]:
|
|
8902
|
+
self.js_update_text(selector, text, by=by, timeout=timeout)
|
|
8903
|
+
return
|
|
8867
8904
|
original_selector = selector
|
|
8868
8905
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
|
8869
8906
|
if scroll:
|
|
@@ -9340,6 +9377,9 @@ class BaseCase(unittest.TestCase):
|
|
|
9340
9377
|
|
|
9341
9378
|
def switch_to_newest_tab(self):
|
|
9342
9379
|
"""Same as self.switch_to_newest_window()"""
|
|
9380
|
+
if self.__is_cdp_swap_needed():
|
|
9381
|
+
self.cdp.switch_to_newest_tab()
|
|
9382
|
+
return
|
|
9343
9383
|
self.switch_to_newest_window()
|
|
9344
9384
|
|
|
9345
9385
|
def save_as_html(self, name, folder=None):
|
|
@@ -9976,6 +10016,8 @@ class BaseCase(unittest.TestCase):
|
|
|
9976
10016
|
self, selector, by="css selector", timeout=None
|
|
9977
10017
|
):
|
|
9978
10018
|
"""Waits for an element to appear in the HTML of a page.
|
|
10019
|
+
Returns the element once it exists in the HTML.
|
|
10020
|
+
Raises an exception if the element doesn't come in time.
|
|
9979
10021
|
The element does not need be visible (it may be hidden)."""
|
|
9980
10022
|
self.__check_scope()
|
|
9981
10023
|
if not timeout:
|
|
@@ -10022,6 +10064,19 @@ class BaseCase(unittest.TestCase):
|
|
|
10022
10064
|
self.driver, selector, by, timeout
|
|
10023
10065
|
)
|
|
10024
10066
|
|
|
10067
|
+
def select(self, selector, by="css selector", timeout=None):
|
|
10068
|
+
"""Returns the element once it appears in the HTML.
|
|
10069
|
+
Raises an exception if the element doesn't come in time.
|
|
10070
|
+
The element does not need be visible (it may be hidden).
|
|
10071
|
+
If CDP Mode has been activated: Calls self.cdp.select().
|
|
10072
|
+
Otherwise: Same as self.wait_for_element_present()."""
|
|
10073
|
+
if self.__is_cdp_swap_needed():
|
|
10074
|
+
return self.cdp.select(selector, timeout=timeout)
|
|
10075
|
+
else:
|
|
10076
|
+
return self.wait_for_element_present(
|
|
10077
|
+
selector, by=by, timeout=timeout
|
|
10078
|
+
)
|
|
10079
|
+
|
|
10025
10080
|
def get_element(self, selector, by="css selector", timeout=None):
|
|
10026
10081
|
"""Same as wait_for_element_present() - returns the element.
|
|
10027
10082
|
The element does not need be visible (it may be hidden)."""
|
|
@@ -455,11 +455,13 @@ class Browser:
|
|
|
455
455
|
"*.google-analytics.com*",
|
|
456
456
|
"*.amazon-adsystem.com*",
|
|
457
457
|
"*.adsafeprotected.com*",
|
|
458
|
+
"*.m.media-amazon.com*",
|
|
458
459
|
"*.ads.linkedin.com*",
|
|
459
460
|
"*.casalemedia.com*",
|
|
460
461
|
"*.doubleclick.net*",
|
|
461
462
|
"*.admanmedia.com*",
|
|
462
463
|
"*.quantserve.com*",
|
|
464
|
+
"*.ads.simpli.fi*",
|
|
463
465
|
"*.fastclick.net*",
|
|
464
466
|
"*.snigelweb.com*",
|
|
465
467
|
"*.bidswitch.net*",
|
|
@@ -378,6 +378,9 @@ class Tab(Connection):
|
|
|
378
378
|
async def open(self, url="about:blank"):
|
|
379
379
|
return await self.get(url=url)
|
|
380
380
|
|
|
381
|
+
async def goto(self, url="about:blank"):
|
|
382
|
+
return await self.get(url=url)
|
|
383
|
+
|
|
381
384
|
async def query_selector_all(
|
|
382
385
|
self,
|
|
383
386
|
selector: str,
|
|
@@ -1745,6 +1748,10 @@ class Tab(Connection):
|
|
|
1745
1748
|
'[data-callback="onCaptchaSuccess"]'
|
|
1746
1749
|
):
|
|
1747
1750
|
selector = '[data-callback="onCaptchaSuccess"]'
|
|
1751
|
+
elif await self.is_element_present(
|
|
1752
|
+
'[class*="captcha"] div:not([class])'
|
|
1753
|
+
):
|
|
1754
|
+
selector = '[class*="captcha"] div:not([class])'
|
|
1748
1755
|
elif await self.is_element_present(
|
|
1749
1756
|
"div:not([class]):not([id]):not([aria-label]) > "
|
|
1750
1757
|
"div:not([class]):not([id]):not([aria-label])"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seleniumbase
|
|
3
|
-
Version: 4.49.
|
|
3
|
+
Version: 4.49.2
|
|
4
4
|
Summary: A framework for stealthy Chromium automation with CDP Mode. Includes CAPTCHA-bypass, E2E Testing, and a Playwright integration.
|
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
|
6
6
|
Author: Michael Mintz
|
|
@@ -65,7 +65,7 @@ Requires-Dist: setuptools~=70.2; python_version < "3.10"
|
|
|
65
65
|
Requires-Dist: setuptools>=82.0.1; python_version >= "3.10"
|
|
66
66
|
Requires-Dist: wheel>=0.47.0
|
|
67
67
|
Requires-Dist: attrs>=26.1.0
|
|
68
|
-
Requires-Dist: certifi>=2026.
|
|
68
|
+
Requires-Dist: certifi>=2026.5.20
|
|
69
69
|
Requires-Dist: exceptiongroup>=1.3.1
|
|
70
70
|
Requires-Dist: websockets~=15.0.1; python_version < "3.10"
|
|
71
71
|
Requires-Dist: websockets>=16.0; python_version >= "3.10"
|
|
@@ -90,7 +90,7 @@ Requires-Dist: pygments>=2.20.0
|
|
|
90
90
|
Requires-Dist: pyreadline3>=3.5.4; platform_system == "Windows"
|
|
91
91
|
Requires-Dist: tabcompleter>=1.4.1
|
|
92
92
|
Requires-Dist: pdbp>=1.8.2
|
|
93
|
-
Requires-Dist: idna>=3.
|
|
93
|
+
Requires-Dist: idna>=3.16
|
|
94
94
|
Requires-Dist: charset-normalizer<4,>=3.4.7
|
|
95
95
|
Requires-Dist: urllib3<2,>=1.26.20; python_version < "3.10"
|
|
96
96
|
Requires-Dist: urllib3<3,>=2.7.0; python_version >= "3.10"
|
|
@@ -168,6 +168,8 @@ Provides-Extra: proxy
|
|
|
168
168
|
Requires-Dist: proxy.py==2.4.3; extra == "proxy"
|
|
169
169
|
Provides-Extra: playwright
|
|
170
170
|
Requires-Dist: playwright>=1.60.0; extra == "playwright"
|
|
171
|
+
Requires-Dist: greenlet>=3.2.5; python_version < "3.10" and extra == "playwright"
|
|
172
|
+
Requires-Dist: greenlet>=3.5.1; python_version >= "3.10" and extra == "playwright"
|
|
171
173
|
Provides-Extra: pyautogui
|
|
172
174
|
Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
|
|
173
175
|
Provides-Extra: selenium-stealth
|
|
@@ -250,9 +252,40 @@ Dynamic: summary
|
|
|
250
252
|
<br />
|
|
251
253
|
</p>
|
|
252
254
|
|
|
253
|
-
🐙 <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
|
|
255
|
+
🐙 <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.
|
|
254
256
|
|
|
255
|
-
|
|
257
|
+
<b>Python sync version of SeleniumBase's CDP Mode: (<code>sb_cdp</code>)</b>
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
from seleniumbase import sb_cdp
|
|
261
|
+
|
|
262
|
+
sb = sb_cdp.Chrome()
|
|
263
|
+
sb.open("https://demo.fingerprint.com/playground")
|
|
264
|
+
sb.sleep(3)
|
|
265
|
+
sb.driver.quit()
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
<b>Playwright can use SeleniumBase's stealth browser:</b>
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
from playwright.sync_api import sync_playwright
|
|
272
|
+
from seleniumbase import sb_cdp
|
|
273
|
+
|
|
274
|
+
sb = sb_cdp.Chrome()
|
|
275
|
+
endpoint_url = sb.get_endpoint_url()
|
|
276
|
+
|
|
277
|
+
with sync_playwright() as p:
|
|
278
|
+
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
279
|
+
page = browser.contexts[0].pages[0]
|
|
280
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
281
|
+
|
|
282
|
+
sb.sleep(3)
|
|
283
|
+
sb.driver.quit()
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
--------
|
|
287
|
+
|
|
288
|
+
📚 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).
|
|
256
289
|
|
|
257
290
|
🥷 Stealthy CDP Mode examples are located in [./examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).
|
|
258
291
|
|
|
@@ -273,12 +306,12 @@ Dynamic: summary
|
|
|
273
306
|
```python
|
|
274
307
|
from seleniumbase import sb_cdp
|
|
275
308
|
|
|
276
|
-
|
|
277
|
-
sb
|
|
278
|
-
sb.flash("Test Results", duration=
|
|
309
|
+
sb = sb_cdp.Chrome(locale="en", ad_block=True)
|
|
310
|
+
sb.open("https://browserscan.net/bot-detection")
|
|
311
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
279
312
|
sb.assert_element('strong:contains("Normal")')
|
|
280
313
|
print("Bot Not Detected")
|
|
281
|
-
sb.flash('strong:contains("Normal")',
|
|
314
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
282
315
|
```
|
|
283
316
|
|
|
284
317
|
<img src="https://seleniumbase.github.io/other/b_scan_results.jpg" width="628" alt="Stealthy architecture flowchart" />
|
|
@@ -295,15 +328,18 @@ endpoint_url = sb.get_endpoint_url()
|
|
|
295
328
|
with sync_playwright() as p:
|
|
296
329
|
browser = p.chromium.connect_over_cdp(endpoint_url)
|
|
297
330
|
page = browser.contexts[0].pages[0]
|
|
298
|
-
page.goto("https://
|
|
331
|
+
page.goto("https://browserscan.net/bot-detection")
|
|
299
332
|
page.wait_for_timeout(500)
|
|
300
|
-
sb.flash("Test Results", duration=
|
|
333
|
+
sb.flash("Test Results", duration=1.5, pause=0.5)
|
|
301
334
|
sb.assert_element('strong:contains("Normal")')
|
|
302
|
-
|
|
335
|
+
print("Bot Not Detected")
|
|
336
|
+
sb.flash('strong:contains("Normal")', pause=1)
|
|
303
337
|
```
|
|
304
338
|
|
|
305
339
|
--------
|
|
306
340
|
|
|
341
|
+
<h3 align="left">🌐 CLI Options for Supported Chromium Browsers</h3>
|
|
342
|
+
|
|
307
343
|
💡 You can set which Chromium browser to use via command-line options:
|
|
308
344
|
|
|
309
345
|
```zsh
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
packaging>=26.2
|
|
2
2
|
wheel>=0.47.0
|
|
3
3
|
attrs>=26.1.0
|
|
4
|
-
certifi>=2026.
|
|
4
|
+
certifi>=2026.5.20
|
|
5
5
|
exceptiongroup>=1.3.1
|
|
6
6
|
fasteners>=0.20
|
|
7
7
|
mycdp>=1.3.7
|
|
@@ -19,7 +19,7 @@ pyyaml>=6.0.3
|
|
|
19
19
|
pygments>=2.20.0
|
|
20
20
|
tabcompleter>=1.4.1
|
|
21
21
|
pdbp>=1.8.2
|
|
22
|
-
idna>=3.
|
|
22
|
+
idna>=3.16
|
|
23
23
|
charset-normalizer<4,>=3.4.7
|
|
24
24
|
sniffio==1.3.1
|
|
25
25
|
h11==0.16.0
|
|
@@ -142,6 +142,12 @@ pip-system-certs==4.0
|
|
|
142
142
|
[playwright]
|
|
143
143
|
playwright>=1.60.0
|
|
144
144
|
|
|
145
|
+
[playwright:python_version < "3.10"]
|
|
146
|
+
greenlet>=3.2.5
|
|
147
|
+
|
|
148
|
+
[playwright:python_version >= "3.10"]
|
|
149
|
+
greenlet>=3.5.1
|
|
150
|
+
|
|
145
151
|
[proxy]
|
|
146
152
|
proxy.py==2.4.3
|
|
147
153
|
|