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.
Files changed (163) hide show
  1. {seleniumbase-4.49.1/seleniumbase.egg-info → seleniumbase-4.49.2}/PKG-INFO +48 -12
  2. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/README.md +43 -9
  3. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/requirements.txt +2 -2
  4. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__version__.py +1 -1
  5. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/browser_launcher.py +9 -0
  6. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/sb_cdp.py +18 -14
  7. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/sb_driver.py +18 -0
  8. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/base_case.py +58 -3
  9. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/browser.py +2 -0
  10. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/tab.py +7 -0
  11. {seleniumbase-4.49.1 → seleniumbase-4.49.2/seleniumbase.egg-info}/PKG-INFO +48 -12
  12. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/requires.txt +8 -2
  13. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/setup.py +5 -3
  14. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/.gitignore +0 -0
  15. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/LICENSE +0 -0
  16. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/MANIFEST.in +0 -0
  17. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/install.sh +0 -0
  18. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/pyproject.toml +0 -0
  19. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/pytest.ini +0 -0
  20. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/__init__.py +0 -0
  21. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/__main__.py +0 -0
  22. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/sbase/steps.py +0 -0
  23. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__init__.py +0 -0
  24. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/__main__.py +0 -0
  25. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/__init__.py +0 -0
  26. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/behave_helper.py +0 -0
  27. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/behave_sb.py +0 -0
  28. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/behave/steps.py +0 -0
  29. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/__init__.py +0 -0
  30. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/decorators.py +0 -0
  31. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/encryption.py +0 -0
  32. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/exceptions.py +0 -0
  33. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/obfuscate.py +0 -0
  34. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/common/unobfuscate.py +0 -0
  35. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/__init__.py +0 -0
  36. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/ad_block_list.py +0 -0
  37. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/proxy_list.py +0 -0
  38. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/config/settings.py +0 -0
  39. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/__init__.py +0 -0
  40. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/logo_helper.py +0 -0
  41. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/rich_helper.py +0 -0
  42. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/run.py +0 -0
  43. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
  44. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
  45. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_commander.py +0 -0
  46. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_install.py +0 -0
  47. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
  48. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
  49. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
  50. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
  51. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
  52. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_objectify.py +0 -0
  53. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_print.py +0 -0
  54. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/console_scripts/sb_recorder.py +0 -0
  55. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/__init__.py +0 -0
  56. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/application_manager.py +0 -0
  57. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/capabilities_parser.py +0 -0
  58. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/colored_traceback.py +0 -0
  59. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/create_db_tables.sql +0 -0
  60. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/detect_b_ver.py +0 -0
  61. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/download_helper.py +0 -0
  62. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/encoded_images.py +0 -0
  63. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/jqc_helper.py +0 -0
  64. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/log_helper.py +0 -0
  65. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/mysql.py +0 -0
  66. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/nest_asyncio.py +0 -0
  67. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/proxy_helper.py +0 -0
  68. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/recorder_helper.py +0 -0
  69. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/report_helper.py +0 -0
  70. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/s3_manager.py +0 -0
  71. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/session_helper.py +0 -0
  72. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/settings_parser.py +0 -0
  73. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/style_sheet.py +0 -0
  74. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/testcase_manager.py +0 -0
  75. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/tour_helper.py +0 -0
  76. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/core/visual_helper.py +0 -0
  77. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/__init__.py +0 -0
  78. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
  79. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
  80. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
  81. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
  82. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
  83. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
  84. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
  85. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/__init__.py +0 -0
  86. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/ad_block.zip +0 -0
  87. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/disable_csp.zip +0 -0
  88. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/recorder.zip +0 -0
  89. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/extensions/sbase_ext.zip +0 -0
  90. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/__init__.py +0 -0
  91. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/constants.py +0 -0
  92. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/css_to_xpath.py +0 -0
  93. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/errors.py +0 -0
  94. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/js_utils.py +0 -0
  95. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/page_actions.py +0 -0
  96. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/page_utils.py +0 -0
  97. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/shared_utils.py +0 -0
  98. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/unittest_helper.py +0 -0
  99. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/words.py +0 -0
  100. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/fixtures/xpath_to_css.py +0 -0
  101. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/__init__.py +0 -0
  102. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/active_css_js.py +0 -0
  103. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/live_js.py +0 -0
  104. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/js_code/recorder_js.py +0 -0
  105. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/masterqa/__init__.py +0 -0
  106. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/masterqa/master_qa.py +0 -0
  107. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/__init__.py +0 -0
  108. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/base_plugin.py +0 -0
  109. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/basic_test_info.py +0 -0
  110. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
  111. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/driver_manager.py +0 -0
  112. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/page_source.py +0 -0
  113. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/pytest_plugin.py +0 -0
  114. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
  115. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/sb_manager.py +0 -0
  116. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/screen_shots.py +0 -0
  117. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/plugins/selenium_plugin.py +0 -0
  118. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/resources/__init__.py +0 -0
  119. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/__init__.py +0 -0
  120. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/chinese.py +0 -0
  121. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/dutch.py +0 -0
  122. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/french.py +0 -0
  123. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/italian.py +0 -0
  124. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/japanese.py +0 -0
  125. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/korean.py +0 -0
  126. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/master_dict.py +0 -0
  127. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/portuguese.py +0 -0
  128. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/russian.py +0 -0
  129. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/spanish.py +0 -0
  130. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/translate/translator.py +0 -0
  131. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/__init__.py +0 -0
  132. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp.py +0 -0
  133. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
  134. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
  135. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
  136. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/config.py +0 -0
  137. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/connection.py +0 -0
  138. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/cdp_driver/element.py +0 -0
  139. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/dprocess.py +0 -0
  140. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/options.py +0 -0
  141. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/patcher.py +0 -0
  142. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/reactor.py +0 -0
  143. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/undetected/webelement.py +0 -0
  144. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/__init__.py +0 -0
  145. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
  146. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
  147. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/font_color +0 -0
  148. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
  149. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
  150. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
  151. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
  152. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
  153. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
  154. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
  155. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
  156. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
  157. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
  158. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/SOURCES.txt +0 -0
  159. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/dependency_links.txt +0 -0
  160. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/entry_points.txt +0 -0
  161. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/seleniumbase.egg-info/top_level.txt +0 -0
  162. {seleniumbase-4.49.1 → seleniumbase-4.49.2}/setup.cfg +0 -0
  163. {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.1
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.4.22
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.15
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 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.
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
- 📚 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).
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
- url = "https://www.browserscan.net/bot-detection"
277
- sb = sb_cdp.Chrome(url, locale="en", ad_block=True)
278
- sb.flash("Test Results", duration=3, pause=1)
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")', duration=3, pause=2)
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://www.browserscan.net/bot-detection")
331
+ page.goto("https://browserscan.net/bot-detection")
299
332
  page.wait_for_timeout(500)
300
- sb.flash("Test Results", duration=3, pause=1)
333
+ sb.flash("Test Results", duration=1.5, pause=0.5)
301
334
  sb.assert_element('strong:contains("Normal")')
302
- sb.flash('strong:contains("Normal")', duration=3, pause=2)
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 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.
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
- 📚 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).
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
- url = "https://www.browserscan.net/bot-detection"
77
- sb = sb_cdp.Chrome(url, locale="en", ad_block=True)
78
- sb.flash("Test Results", duration=3, pause=1)
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")', duration=3, pause=2)
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://www.browserscan.net/bot-detection")
129
+ page.goto("https://browserscan.net/bot-detection")
99
130
  page.wait_for_timeout(500)
100
- sb.flash("Test Results", duration=3, pause=1)
131
+ sb.flash("Test Results", duration=1.5, pause=0.5)
101
132
  sb.assert_element('strong:contains("Normal")')
102
- sb.flash('strong:contains("Normal")', duration=3, pause=2)
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.4.22
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.15
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.1"
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
- if element.tag_name.lower() in ["input", "textarea"]:
8865
- self.js_update_text(selector, text, by=by, timeout=timeout)
8866
- return
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.1
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.4.22
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.15
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 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.
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
- 📚 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).
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
- url = "https://www.browserscan.net/bot-detection"
277
- sb = sb_cdp.Chrome(url, locale="en", ad_block=True)
278
- sb.flash("Test Results", duration=3, pause=1)
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")', duration=3, pause=2)
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://www.browserscan.net/bot-detection")
331
+ page.goto("https://browserscan.net/bot-detection")
299
332
  page.wait_for_timeout(500)
300
- sb.flash("Test Results", duration=3, pause=1)
333
+ sb.flash("Test Results", duration=1.5, pause=0.5)
301
334
  sb.assert_element('strong:contains("Normal")')
302
- sb.flash('strong:contains("Normal")', duration=3, pause=2)
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.22
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.15
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