seleniumbase 4.54.5__tar.gz → 4.54.7__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 (164) hide show
  1. {seleniumbase-4.54.5/seleniumbase.egg-info → seleniumbase-4.54.7}/PKG-INFO +6 -6
  2. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/mcp_servers/server.py +253 -52
  3. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/requirements.txt +2 -2
  4. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/__version__.py +1 -1
  5. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/tab.py +19 -11
  6. {seleniumbase-4.54.5 → seleniumbase-4.54.7/seleniumbase.egg-info}/PKG-INFO +6 -6
  7. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase.egg-info/requires.txt +5 -5
  8. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/setup.py +5 -5
  9. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/.gitignore +0 -0
  10. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/LICENSE +0 -0
  11. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/MANIFEST.in +0 -0
  12. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/README.md +0 -0
  13. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/install.sh +0 -0
  14. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/mcp_servers/__init__.py +0 -0
  15. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/pyproject.toml +0 -0
  16. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/pytest.ini +0 -0
  17. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/sbase/__init__.py +0 -0
  18. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/sbase/__main__.py +0 -0
  19. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/sbase/steps.py +0 -0
  20. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/__init__.py +0 -0
  21. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/__main__.py +0 -0
  22. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/behave/__init__.py +0 -0
  23. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/behave/behave_helper.py +0 -0
  24. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/behave/behave_sb.py +0 -0
  25. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/behave/steps.py +0 -0
  26. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/__init__.py +0 -0
  27. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/decorators.py +0 -0
  28. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/encryption.py +0 -0
  29. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/exceptions.py +0 -0
  30. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/obfuscate.py +0 -0
  31. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/common/unobfuscate.py +0 -0
  32. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/config/__init__.py +0 -0
  33. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/config/ad_block_list.py +0 -0
  34. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/config/proxy_list.py +0 -0
  35. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/config/settings.py +0 -0
  36. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/__init__.py +0 -0
  37. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/logo_helper.py +0 -0
  38. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/rich_helper.py +0 -0
  39. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/run.py +0 -0
  40. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
  41. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
  42. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_commander.py +0 -0
  43. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_install.py +0 -0
  44. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
  45. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
  46. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_mkfile.py +0 -0
  47. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
  48. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_mkrec.py +0 -0
  49. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_objectify.py +0 -0
  50. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_print.py +0 -0
  51. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/console_scripts/sb_recorder.py +0 -0
  52. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/__init__.py +0 -0
  53. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/application_manager.py +0 -0
  54. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/browser_launcher.py +0 -0
  55. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/capabilities_parser.py +0 -0
  56. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/colored_traceback.py +0 -0
  57. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/create_db_tables.sql +0 -0
  58. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/detect_b_ver.py +0 -0
  59. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/download_helper.py +0 -0
  60. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/encoded_images.py +0 -0
  61. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/jqc_helper.py +0 -0
  62. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/log_helper.py +0 -0
  63. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/mysql.py +0 -0
  64. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/nest_asyncio.py +0 -0
  65. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/proxy_helper.py +0 -0
  66. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/recorder_helper.py +0 -0
  67. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/report_helper.py +0 -0
  68. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/s3_manager.py +0 -0
  69. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/sb_cdp.py +0 -0
  70. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/sb_driver.py +0 -0
  71. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/session_helper.py +0 -0
  72. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/settings_parser.py +0 -0
  73. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/style_sheet.py +0 -0
  74. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/testcase_manager.py +0 -0
  75. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/tour_helper.py +0 -0
  76. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/core/visual_helper.py +0 -0
  77. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/__init__.py +0 -0
  78. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
  79. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
  80. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
  81. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
  82. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
  83. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
  84. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/extensions/__init__.py +0 -0
  85. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/extensions/ad_block.zip +0 -0
  86. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/extensions/disable_csp.zip +0 -0
  87. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/extensions/recorder.zip +0 -0
  88. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/extensions/sbase_ext.zip +0 -0
  89. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/__init__.py +0 -0
  90. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/base_case.py +0 -0
  91. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/constants.py +0 -0
  92. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/css_to_xpath.py +0 -0
  93. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/errors.py +0 -0
  94. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/js_utils.py +0 -0
  95. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/page_actions.py +0 -0
  96. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/page_utils.py +0 -0
  97. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/shared_utils.py +0 -0
  98. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/unittest_helper.py +0 -0
  99. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/words.py +0 -0
  100. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/fixtures/xpath_to_css.py +0 -0
  101. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/js_code/__init__.py +0 -0
  102. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/js_code/active_css_js.py +0 -0
  103. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/js_code/live_js.py +0 -0
  104. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/js_code/recorder_js.py +0 -0
  105. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/masterqa/__init__.py +0 -0
  106. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/masterqa/master_qa.py +0 -0
  107. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/__init__.py +0 -0
  108. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/base_plugin.py +0 -0
  109. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/basic_test_info.py +0 -0
  110. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
  111. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/driver_manager.py +0 -0
  112. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/page_source.py +0 -0
  113. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/pytest_plugin.py +0 -0
  114. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
  115. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/sb_manager.py +0 -0
  116. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/screen_shots.py +0 -0
  117. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/plugins/selenium_plugin.py +0 -0
  118. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/resources/__init__.py +0 -0
  119. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/__init__.py +0 -0
  120. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/chinese.py +0 -0
  121. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/dutch.py +0 -0
  122. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/french.py +0 -0
  123. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/italian.py +0 -0
  124. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/japanese.py +0 -0
  125. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/korean.py +0 -0
  126. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/master_dict.py +0 -0
  127. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/portuguese.py +0 -0
  128. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/russian.py +0 -0
  129. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/spanish.py +0 -0
  130. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/translate/translator.py +0 -0
  131. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/__init__.py +0 -0
  132. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp.py +0 -0
  133. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
  134. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
  135. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/browser.py +0 -0
  136. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
  137. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/config.py +0 -0
  138. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/connection.py +0 -0
  139. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/cdp_driver/element.py +0 -0
  140. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/dprocess.py +0 -0
  141. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/options.py +0 -0
  142. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/patcher.py +0 -0
  143. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/reactor.py +0 -0
  144. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/undetected/webelement.py +0 -0
  145. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/__init__.py +0 -0
  146. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
  147. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
  148. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/font_color +0 -0
  149. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
  150. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
  151. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
  152. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
  153. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
  154. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
  155. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
  156. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
  157. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
  158. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
  159. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase.egg-info/SOURCES.txt +0 -0
  160. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase.egg-info/dependency_links.txt +0 -0
  161. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase.egg-info/entry_points.txt +0 -0
  162. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/seleniumbase.egg-info/top_level.txt +0 -0
  163. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/setup.cfg +0 -0
  164. {seleniumbase-4.54.5 → seleniumbase-4.54.7}/virtualenv_install.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seleniumbase
3
- Version: 4.54.5
3
+ Version: 4.54.7
4
4
  Summary: SeleniumBase is a framework for web crawling, scraping, and testing. Supports pytest. CDP Mode adds stealth. Includes many tools.
5
5
  Home-page: https://github.com/seleniumbase/SeleniumBase
6
6
  Author: Michael Mintz
@@ -67,7 +67,7 @@ Requires-Dist: certifi>=2026.7.22
67
67
  Requires-Dist: exceptiongroup>=1.3.1
68
68
  Requires-Dist: websockets~=16.1.1; python_version == "3.10"
69
69
  Requires-Dist: websockets>=16.1.1; python_version >= "3.11"
70
- Requires-Dist: filelock>=3.32.6
70
+ Requires-Dist: filelock>=3.32.7
71
71
  Requires-Dist: fasteners>=0.20
72
72
  Requires-Dist: mycdp>=1.4.0
73
73
  Requires-Dist: pynose>=1.5.5
@@ -88,7 +88,7 @@ Requires-Dist: tabcompleter>=1.4.1
88
88
  Requires-Dist: pdbp>=1.8.2
89
89
  Requires-Dist: idna>=3.19
90
90
  Requires-Dist: charset-normalizer<4,>=3.5.1
91
- Requires-Dist: urllib3<3,>=2.7.0
91
+ Requires-Dist: urllib3<3,>=2.8.0
92
92
  Requires-Dist: requests~=2.34.2
93
93
  Requires-Dist: sniffio==1.3.1
94
94
  Requires-Dist: h11==0.16.0
@@ -149,13 +149,13 @@ Requires-Dist: pip-system-certs>=4.0; platform_system == "Windows" and extra ==
149
149
  Provides-Extra: proxy
150
150
  Requires-Dist: proxy.py==2.4.3; extra == "proxy"
151
151
  Provides-Extra: playwright
152
- Requires-Dist: playwright>=1.62.0; extra == "playwright"
153
- Requires-Dist: greenlet>=3.5.5; extra == "playwright"
152
+ Requires-Dist: playwright>=1.63.0; extra == "playwright"
153
+ Requires-Dist: greenlet>=3.5.6; extra == "playwright"
154
154
  Requires-Dist: pyee>=13.0.1; extra == "playwright"
155
155
  Provides-Extra: pyautogui
156
156
  Requires-Dist: PyAutoGUI>=0.9.54; platform_system != "Linux" and extra == "pyautogui"
157
157
  Provides-Extra: uv
158
- Requires-Dist: uv>=0.12.12; extra == "uv"
158
+ Requires-Dist: uv>=0.12.15; extra == "uv"
159
159
  Dynamic: author
160
160
  Dynamic: author-email
161
161
  Dynamic: classifier
@@ -51,6 +51,17 @@ Tool-selection philosophy:
51
51
  - Use 'focus_element' for element positioning and visual focus.
52
52
  - Use 'solve_captcha' for clicking the checkbox of a CAPTCHA on the page.
53
53
  - Use 'save_page' for saving page output as a PNG, a PDF, or an HTML file.
54
+
55
+ Tool annotations:
56
+ Where a tool has one consistent behavior, it declares MCP tool annotations
57
+ (title + read_only_hint/destructive_hint/idempotent_hint/open_world_hint)
58
+ so clients can make informed UX/confirmation decisions without calling it.
59
+ Several tools here consolidate multiple related actions behind a single
60
+ `action`/`mode` parameter (e.g. manage_cookies: get_all/clear/save/load).
61
+ Where those actions genuinely differ in kind -- some read-only, some
62
+ destructive, some writing to disk -- no single annotation value would be
63
+ honest for the whole tool, so annotations are intentionally omitted for
64
+ those (title is still provided). See the per-tool comments below.
54
65
  """
55
66
  from __future__ import annotations
56
67
  import atexit
@@ -59,6 +70,7 @@ from functools import wraps
59
70
  from typing import Any, Literal
60
71
  from mcp.server import MCPServer
61
72
  from mcp.server.mcpserver.exceptions import ToolError
73
+ from mcp.types import ToolAnnotations
62
74
  from seleniumbase import sb_cdp
63
75
 
64
76
  mcp = MCPServer("seleniumbase-mcp")
@@ -99,7 +111,17 @@ def handle_sb_errors(func):
99
111
  # Session lifecycle
100
112
  # ---------------------------------------------------------------------------
101
113
 
102
- @mcp.tool()
114
+ @mcp.tool(
115
+ title="Start Browser",
116
+ annotations=ToolAnnotations(
117
+ # Single, consistent behavior: launches (or no-ops if already
118
+ # running) a persistent browser session.
119
+ read_only_hint=False,
120
+ destructive_hint=False,
121
+ idempotent_hint=True, # No-ops with the same message if already up.
122
+ open_world_hint=True, # Launches a real browser onto the open web.
123
+ ),
124
+ )
103
125
  def start_browser(
104
126
  url: str | None = None,
105
127
  headless: Literal[False, True, None] = None,
@@ -245,7 +267,17 @@ def start_browser(
245
267
  )
246
268
 
247
269
 
248
- @mcp.tool()
270
+ @mcp.tool(
271
+ title="Close Browser",
272
+ annotations=ToolAnnotations(
273
+ # Single, consistent behavior: Ends the persistent browser session
274
+ # (or no-ops if already stopped).
275
+ read_only_hint=False,
276
+ idempotent_hint=True, # Once closed, repeated calls have no further
277
+ # effect.
278
+ open_world_hint=False, # Local teardown of a server-owned resource.
279
+ ),
280
+ )
249
281
  def close_browser() -> str:
250
282
  """Close the active browser session and release browser resources.
251
283
 
@@ -278,7 +310,15 @@ def close_browser() -> str:
278
310
  # Page information
279
311
  # ---------------------------------------------------------------------------
280
312
 
281
- @mcp.tool()
313
+ @mcp.tool(
314
+ title="Get Page Info",
315
+ annotations=ToolAnnotations(
316
+ read_only_hint=True,
317
+ destructive_hint=False,
318
+ idempotent_hint=True,
319
+ open_world_hint=True,
320
+ ),
321
+ )
282
322
  @handle_sb_errors
283
323
  def get_page_info() -> dict[str, Any]:
284
324
  """Get current browser session and page metadata.
@@ -287,7 +327,7 @@ def get_page_info() -> dict[str, Any]:
287
327
  is after navigation, clicks, form submissions, redirects, reloads, or
288
328
  tab switches.
289
329
 
290
- This is a READ-ONLY metadata operation. It does not inspect arbitrary
330
+ This is a read-only metadata operation: It does not inspect arbitrary
291
331
  page content, find elements, check visibility, wait for conditions, or
292
332
  assert expected values.
293
333
 
@@ -337,7 +377,15 @@ def get_page_info() -> dict[str, Any]:
337
377
  # Navigation
338
378
  # ---------------------------------------------------------------------------
339
379
 
340
- @mcp.tool()
380
+ @mcp.tool(
381
+ title="Open URL",
382
+ annotations=ToolAnnotations(
383
+ read_only_hint=False,
384
+ destructive_hint=False,
385
+ idempotent_hint=False,
386
+ open_world_hint=True,
387
+ ),
388
+ )
341
389
  @handle_sb_errors
342
390
  def open_url(url: str) -> str:
343
391
  """Navigate the current browser tab to the URL provided.
@@ -372,15 +420,18 @@ def open_url(url: str) -> str:
372
420
  return f"Navigated to {url}"
373
421
 
374
422
 
375
- @mcp.tool()
423
+ @mcp.tool(title="Manage History")
424
+ # Annotations intentionally omitted: 'list' is a pure read, while
425
+ # 'back'/'forward'/'reload' each navigate and modify browser state -- no
426
+ # single read_only_hint value would be accurate for the whole tool.
376
427
  @handle_sb_errors
377
428
  def manage_history(
378
429
  action: Literal["back", "forward", "reload", "list"] = "list",
379
430
  ) -> str | dict[str, Any]:
380
431
  """Manage or inspect the current browser tab's navigation history.
381
432
 
382
- Use 'back' or 'forward' for history navigation, 'reload' to refresh
383
- while bypassing the cache, or 'list' to inspect history.
433
+ Use "back", "forward", or "reload" actions for history navigation.
434
+ Use "list" to inspect history. (This one is read-only.)
384
435
  Use 'open_url' for navigation to an arbitrary URL.
385
436
 
386
437
  Args:
@@ -391,7 +442,7 @@ def manage_history(
391
442
  - "list": Return the current history position and entries.
392
443
 
393
444
  Navigation actions can trigger page loads or redirects.
394
- Use get_page_info afterward to verify the resulting URL or title.
445
+ Use 'get_page_info' afterward to verify the resulting URL or title.
395
446
  """
396
447
  sb = _get_sb()
397
448
 
@@ -433,7 +484,15 @@ def manage_history(
433
484
  # Finding & reading
434
485
  # ---------------------------------------------------------------------------
435
486
 
436
- @mcp.tool()
487
+ @mcp.tool(
488
+ title="Find Elements",
489
+ annotations=ToolAnnotations(
490
+ read_only_hint=True,
491
+ destructive_hint=False,
492
+ idempotent_hint=True,
493
+ open_world_hint=True,
494
+ ),
495
+ )
437
496
  @handle_sb_errors
438
497
  def find_elements(
439
498
  selector: str,
@@ -514,17 +573,22 @@ def find_elements(
514
573
  }
515
574
 
516
575
 
517
- @mcp.tool()
576
+ @mcp.tool(
577
+ title="Get Content",
578
+ annotations=ToolAnnotations(
579
+ read_only_hint=True,
580
+ destructive_hint=False,
581
+ idempotent_hint=True,
582
+ open_world_hint=True,
583
+ ),
584
+ )
518
585
  @handle_sb_errors
519
586
  def get_content(
520
587
  selector: str = "body",
521
588
  output_format: Literal["text", "html", "urls"] = "text",
522
589
  timeout: float = 5,
523
590
  ) -> str | list[str]:
524
- """Read visible text, HTML, or discovered URLs from the selected element.
525
-
526
- Use this tool when you need to get actual page content or URL information
527
- rather than page metadata.
591
+ """Get visible text, HTML, or discovered URLs from the selected element.
528
592
 
529
593
  Args:
530
594
  selector: CSS selector or SeleniumBase-supported XPath selector.
@@ -567,18 +631,24 @@ def get_content(
567
631
  )
568
632
 
569
633
 
570
- @mcp.tool()
634
+ @mcp.tool(
635
+ title="Get Attributes",
636
+ annotations=ToolAnnotations(
637
+ read_only_hint=True,
638
+ destructive_hint=False,
639
+ idempotent_hint=True,
640
+ open_world_hint=True,
641
+ ),
642
+ )
571
643
  @handle_sb_errors
572
644
  def get_attributes(
573
645
  selector: str,
574
646
  attribute: str | None = None,
575
647
  timeout: float = 5,
576
648
  ) -> str | dict[str, Any] | None:
577
- """Read HTML attributes from the first matching element.
578
-
579
- Use this tool when you need the value of a specific HTML attribute,
580
- or all HTML attributes of an element. Attributes could be something
581
- such as href, src, value, class, id, name, type, aria-label, etc.
649
+ """Get a specific HTML attribute (or all attributes) from the
650
+ first-matching element. Examples of possible attributes include
651
+ href, src, value, class, id, name, type, aria-label, etc.
582
652
 
583
653
  Args:
584
654
  selector: CSS selector or SeleniumBase-supported XPath selector.
@@ -597,8 +667,6 @@ def get_attributes(
597
667
  - Need to check element presence/visibility ->
598
668
  use 'check_if_condition'.
599
669
 
600
- This is a read-only operation.
601
-
602
670
  If there's no matching element found within the timeout,
603
671
  then @handle_sb_errors returns details from the exception raised.
604
672
  """
@@ -610,7 +678,15 @@ def get_attributes(
610
678
  return sb.get_element_attributes(selector, timeout=timeout)
611
679
 
612
680
 
613
- @mcp.tool()
681
+ @mcp.tool(
682
+ title="Check Condition",
683
+ annotations=ToolAnnotations(
684
+ read_only_hint=True,
685
+ destructive_hint=False,
686
+ idempotent_hint=True,
687
+ open_world_hint=True,
688
+ ),
689
+ )
614
690
  @handle_sb_errors
615
691
  def check_if_condition(
616
692
  check: Literal["present", "visible"] = "visible",
@@ -659,8 +735,6 @@ def check_if_condition(
659
735
  This tool does not intentionally wait for elements or text to appear.
660
736
  It is intended for checking the current state only. If page timing or
661
737
  asynchronous loading matters, use wait_for_condition instead.
662
-
663
- When `text` is provided, `check` is ignored.
664
738
  """
665
739
  sb = _get_sb()
666
740
 
@@ -682,7 +756,20 @@ def check_if_condition(
682
756
  # Interacting with elements
683
757
  # ---------------------------------------------------------------------------
684
758
 
685
- @mcp.tool()
759
+ @mcp.tool(
760
+ title="Click Element",
761
+ annotations=ToolAnnotations(
762
+ # These settings are consistent across all click modes. The tool
763
+ # always performs a browser interaction, regardless of which matching
764
+ # element(s) are selected.
765
+ read_only_hint=False, # Clicking can modify browser/page state.
766
+ destructive_hint=False, # The generic click operation is not
767
+ # inherently destructive; the target may be.
768
+ idempotent_hint=False, # Repeating a click can produce a different
769
+ # result or trigger another action.
770
+ open_world_hint=True, # The tool operates on external webpages.
771
+ ),
772
+ )
686
773
  @handle_sb_errors
687
774
  def click_element(
688
775
  selector: str,
@@ -699,12 +786,12 @@ def click_element(
699
786
  clicking all visible matches, conditional clicks, or clicks scoped to a
700
787
  parent element.
701
788
 
702
- Selection behavior:
703
- - `nth` is 1-based and takes precedence over every other click mode.
704
- - Otherwise, `all_matches=True` clicks every currently visible match.
705
- - Otherwise, `only_if_visible=True` clicks only if a match is visible.
706
- - Otherwise, `parent_selector` scopes the click to a nested element.
707
- - With none of the above, performs a normal SeleniumBase click.
789
+ Selection behavior and priority:
790
+ `nth` is 1-based and takes precedence over every other click mode.
791
+ Otherwise, `all_matches=True` clicks every currently visible match.
792
+ Otherwise, `only_if_visible=True` clicks only if a match is visible.
793
+ Otherwise, `parent_selector` scopes the click to a nested element.
794
+ If none of the above are set, then a regular click is performed.
708
795
 
709
796
  Args:
710
797
  selector: CSS selector, XPath selector, or supported SeleniumBase
@@ -779,7 +866,11 @@ def click_element(
779
866
  return f"Clicked {selector}"
780
867
 
781
868
 
782
- @mcp.tool()
869
+ @mcp.tool(title="Hover / Click / Drag")
870
+ # Annotations intentionally omitted: 'hover' alone is a near-harmless
871
+ # observation-adjacent action, while 'hover_and_click' and 'drag_and_drop'
872
+ # can modify or reorder page/data state (like click_element) -- no single
873
+ # destructive_hint value would be accurate for the whole tool.
783
874
  @handle_sb_errors
784
875
  def hover_action(
785
876
  selector: str,
@@ -865,7 +956,19 @@ def hover_action(
865
956
  )
866
957
 
867
958
 
868
- @mcp.tool()
959
+ @mcp.tool(
960
+ title="Type Text",
961
+ annotations=ToolAnnotations(
962
+ # idempotent_hint is deliberately omitted: fill_input/set_value/
963
+ # clear_only converge to the same end state on repeat calls, but
964
+ # mode="append" compounds text on each call, so no single value
965
+ # would be accurate for every mode.
966
+ read_only_hint=False,
967
+ destructive_hint=False,
968
+ open_world_hint=True, # Since "\n" can perform the "Enter" action,
969
+ # which includes form submissions.
970
+ ),
971
+ )
869
972
  @handle_sb_errors
870
973
  def type_text(
871
974
  selector: str,
@@ -935,7 +1038,17 @@ def type_text(
935
1038
  return f"type_text(mode={mode!r}) done for {selector}"
936
1039
 
937
1040
 
938
- @mcp.tool()
1041
+ @mcp.tool(
1042
+ title="Select Option",
1043
+ annotations=ToolAnnotations(
1044
+ read_only_hint=False,
1045
+ destructive_hint=False,
1046
+ idempotent_hint=False, # Selecting an option can trigger arbitrary
1047
+ # page-side behavior/events.
1048
+ open_world_hint=True, # Selecting an option can change browser
1049
+ # state and can trigger arbitrary page-side behavior.
1050
+ ),
1051
+ )
939
1052
  @handle_sb_errors
940
1053
  def select_option(
941
1054
  dropdown_selector: str,
@@ -977,7 +1090,13 @@ def select_option(
977
1090
  return f"Selected ({by}={value!r}) in {dropdown_selector}"
978
1091
 
979
1092
 
980
- @mcp.tool()
1093
+ @mcp.tool(
1094
+ title="Focus Element",
1095
+ annotations=ToolAnnotations(
1096
+ read_only_hint=False,
1097
+ destructive_hint=False,
1098
+ ),
1099
+ )
981
1100
  @handle_sb_errors
982
1101
  def focus_element(
983
1102
  selector: str,
@@ -1030,7 +1149,17 @@ def focus_element(
1030
1149
  # Waiting & assertions
1031
1150
  # ---------------------------------------------------------------------------
1032
1151
 
1033
- @mcp.tool()
1152
+ @mcp.tool(
1153
+ title="Wait For Condition",
1154
+ annotations=ToolAnnotations(
1155
+ # Consistent across every state: This tool only observes/blocks,
1156
+ # and it never modifies the page itself.
1157
+ read_only_hint=True,
1158
+ destructive_hint=False,
1159
+ idempotent_hint=True,
1160
+ open_world_hint=False,
1161
+ ),
1162
+ )
1034
1163
  @handle_sb_errors
1035
1164
  def wait_for_condition(
1036
1165
  state: Literal[
@@ -1138,7 +1267,17 @@ def wait_for_condition(
1138
1267
  return f"Element {selector} reached state '{state}'."
1139
1268
 
1140
1269
 
1141
- @mcp.tool()
1270
+ @mcp.tool(
1271
+ title="Assert Condition",
1272
+ annotations=ToolAnnotations(
1273
+ # Consistent across every check: Purely a verification/read
1274
+ # operation, and never modifies the page.
1275
+ read_only_hint=True,
1276
+ destructive_hint=False,
1277
+ idempotent_hint=True,
1278
+ open_world_hint=False,
1279
+ ),
1280
+ )
1142
1281
  @handle_sb_errors
1143
1282
  def assert_condition(
1144
1283
  check: Literal[
@@ -1256,7 +1395,11 @@ def assert_condition(
1256
1395
  # Cookies & storage
1257
1396
  # ---------------------------------------------------------------------------
1258
1397
 
1259
- @mcp.tool()
1398
+ @mcp.tool(title="Manage Cookies")
1399
+ # Annotations intentionally omitted: 'get_all' is a pure read, 'clear' is
1400
+ # destructive, and 'save'/'load' are file/session I/O -- no single
1401
+ # read_only_hint or destructive_hint value would be accurate for the whole
1402
+ # tool.
1260
1403
  @handle_sb_errors
1261
1404
  def manage_cookies(
1262
1405
  action: Literal["get_all", "clear", "save", "load"] = "get_all",
@@ -1328,7 +1471,10 @@ def manage_cookies(
1328
1471
  )
1329
1472
 
1330
1473
 
1331
- @mcp.tool()
1474
+ @mcp.tool(title="Manage Storage")
1475
+ # Annotations intentionally omitted: 'get' is a pure read while 'set'
1476
+ # modifies storage -- no single read_only_hint value would be accurate
1477
+ # for the whole tool.
1332
1478
  @handle_sb_errors
1333
1479
  def manage_storage(
1334
1480
  key: str,
@@ -1404,7 +1550,20 @@ def manage_storage(
1404
1550
  # Scrolling
1405
1551
  # ---------------------------------------------------------------------------
1406
1552
 
1407
- @mcp.tool()
1553
+ @mcp.tool(
1554
+ title="Scroll Page",
1555
+ annotations=ToolAnnotations(
1556
+ # Consistent across up/down/top/bottom: a harmless, local,
1557
+ # non-destructive scroll-position change.
1558
+ # idempotent_hint is deliberately omitted: 'top'/'bottom' are
1559
+ # idempotent (repeating lands you in the same place), but 'up'/
1560
+ # 'down' compound with each call, so no single value would be
1561
+ # accurate for every direction.
1562
+ read_only_hint=False,
1563
+ destructive_hint=False,
1564
+ open_world_hint=False,
1565
+ ),
1566
+ )
1408
1567
  @handle_sb_errors
1409
1568
  def scroll_page(
1410
1569
  direction: Literal["up", "down", "top", "bottom"] = "down",
@@ -1460,7 +1619,18 @@ def scroll_page(
1460
1619
  # Windows & tabs
1461
1620
  # ---------------------------------------------------------------------------
1462
1621
 
1463
- @mcp.tool()
1622
+ @mcp.tool(
1623
+ title="Manage Window",
1624
+ annotations=ToolAnnotations(
1625
+ destructive_hint=False,
1626
+ idempotent_hint=True,
1627
+ open_world_hint=False,
1628
+ ),
1629
+ )
1630
+ # The 'read_only_hint' annotation has been intentionally omitted:
1631
+ # 'get_rect' is a pure read while
1632
+ # 'set_rect'/'maximize'/'minimize' modify window state.
1633
+ # There's no single 'read_only_hint' value that's accurate for the whole tool.
1464
1634
  @handle_sb_errors
1465
1635
  def manage_window(
1466
1636
  action: Literal[
@@ -1520,7 +1690,11 @@ def manage_window(
1520
1690
  )
1521
1691
 
1522
1692
 
1523
- @mcp.tool()
1693
+ @mcp.tool(title="Manage Tabs")
1694
+ # Annotations intentionally omitted: 'list_tabs' is a pure read while
1695
+ # 'open_new_tab'/'switch_to_tab'/'switch_to_newest_tab' modify state and
1696
+ # 'close_active_tab' is destructive -- no single read_only_hint or
1697
+ # destructive_hint value would be accurate for the whole tool.
1524
1698
  @handle_sb_errors
1525
1699
  def manage_tabs(
1526
1700
  action: Literal[
@@ -1621,16 +1795,23 @@ def manage_tabs(
1621
1795
  # Captcha solving
1622
1796
  # ---------------------------------------------------------------------------
1623
1797
 
1624
- @mcp.tool()
1798
+ @mcp.tool(
1799
+ title="Solve CAPTCHA",
1800
+ annotations=ToolAnnotations(
1801
+ read_only_hint=False,
1802
+ destructive_hint=False,
1803
+ idempotent_hint=False, # A 2nd attempt on an already-handled or
1804
+ # rotated CAPTCHA widget isn't guaranteed to be a no-op.
1805
+ open_world_hint=True, # Interacts with a 3rd-party CAPTCHA widget.
1806
+ ),
1807
+ )
1625
1808
  @handle_sb_errors
1626
1809
  def solve_captcha() -> str:
1627
1810
  """Attempt a SeleniumBase CDP-based CAPTCHA interaction, such as clicking
1628
1811
  a CAPTCHA checkbox, or performing a drag/drop action on a slider CAPTCHA.
1629
1812
 
1630
- This tool attempts to interact with CAPTCHA controls such as Cloudflare
1631
- Turnstile, reCAPTCHA, hCaptcha, DataDome Slider, or FriendlyCaptcha via
1632
- the Chrome DevTools Protocol (CDP), which is usually stealthier than
1633
- JavaScript because CDP actions can avoid triggering `isTrusted: false`.
1813
+ Supported CAPTCHAs include: Cloudflare Turnstile, reCAPTCHA, hCaptcha,
1814
+ DataDome Slider, and FriendlyCaptcha.
1634
1815
 
1635
1816
  This tool automatically detects the coordinates of CAPTCHA checkboxes
1636
1817
  for determining the correct location to perform the click. If no CAPTCHA
@@ -1649,8 +1830,13 @@ def solve_captcha() -> str:
1649
1830
  or 'manage_cookies' to inspect resulting page/session state.
1650
1831
 
1651
1832
  Returns:
1652
- A message confirming that the CAPTCHA interaction was attempted.
1833
+ A confirmation message of the CAPTCHA interaction.
1653
1834
  The message is the same for both successful and failed attempts.
1835
+
1836
+ Notes:
1837
+ Clicking with the Chrome DevTools Protocol (CDP) is generally
1838
+ stealthier than clicking with JavaScript because CDP actions
1839
+ can avoid triggering `isTrusted: false`.
1654
1840
  """
1655
1841
  sb = _get_sb()
1656
1842
  sb.solve_captcha()
@@ -1661,7 +1847,17 @@ def solve_captcha() -> str:
1661
1847
  # Output & misc
1662
1848
  # ---------------------------------------------------------------------------
1663
1849
 
1664
- @mcp.tool()
1850
+ @mcp.tool(
1851
+ title="Save Page",
1852
+ annotations=ToolAnnotations(
1853
+ # Consistent across screenshot/html/pdf: All three read the current
1854
+ # (unmodified) page and write a new local file, which may silently
1855
+ # overwrite an existing file of the same name.
1856
+ read_only_hint=False,
1857
+ idempotent_hint=False,
1858
+ open_world_hint=False,
1859
+ ),
1860
+ )
1665
1861
  @handle_sb_errors
1666
1862
  def save_page(
1667
1863
  format: Literal["screenshot", "html", "pdf"] = "screenshot",
@@ -1741,7 +1937,12 @@ def save_page(
1741
1937
  return f"Saved {format} as {name}"
1742
1938
 
1743
1939
 
1744
- @mcp.tool()
1940
+ @mcp.tool(title="Run JavaScript")
1941
+ # Annotations intentionally omitted: arbitrary JavaScript can read, write,
1942
+ # navigate, or destroy data, or do nothing at all -- no annotation value
1943
+ # would be more informative than the MCP spec's own conservative defaults
1944
+ # for an unannotated tool (not read-only, potentially destructive,
1945
+ # non-idempotent, open-world).
1745
1946
  @handle_sb_errors
1746
1947
  def run_javascript(expression: str) -> Any:
1747
1948
  """Evaluate a JavaScript expression in the current page context.
@@ -7,7 +7,7 @@ certifi>=2026.7.22
7
7
  exceptiongroup>=1.3.1
8
8
  websockets~=16.1.1;python_version=="3.10"
9
9
  websockets>=16.1.1;python_version>="3.11"
10
- filelock>=3.32.6
10
+ filelock>=3.32.7
11
11
  fasteners>=0.20
12
12
  mycdp>=1.4.0
13
13
  pynose>=1.5.5
@@ -28,7 +28,7 @@ tabcompleter>=1.4.1
28
28
  pdbp>=1.8.2
29
29
  idna>=3.19
30
30
  charset-normalizer>=3.5.1,<4
31
- urllib3>=2.7.0,<3
31
+ urllib3>=2.8.0,<3
32
32
  requests~=2.34.2
33
33
  sniffio==1.3.1
34
34
  h11==0.16.0
@@ -1,2 +1,2 @@
1
1
  # seleniumbase package
2
- __version__ = "4.54.5"
2
+ __version__ = "4.54.7"
@@ -222,14 +222,15 @@ class Tab(Connection):
222
222
  except (Exception, TypeError):
223
223
  pass
224
224
  while not item:
225
- item = await self.find_element_by_text(
226
- text, best_match, return_enclosing_element
227
- )
228
225
  if loop.time() - start_time > timeout:
229
226
  raise asyncio.TimeoutError(
230
227
  "Time ran out while waiting for: {%s}" % text
231
228
  )
229
+ await self
232
230
  await self.sleep(0.5)
231
+ item = await self.find_element_by_text(
232
+ text, best_match, return_enclosing_element
233
+ )
233
234
  return item
234
235
 
235
236
  async def select(
@@ -273,13 +274,13 @@ class Tab(Connection):
273
274
  except (Exception, TypeError):
274
275
  pass
275
276
  while not items:
276
- await self
277
- items = await self.find_elements_by_text(text)
278
277
  if loop.time() - now > timeout:
279
278
  raise asyncio.TimeoutError(
280
279
  "Time ran out while waiting for: {%s}" % text
281
280
  )
281
+ await self
282
282
  await self.sleep(0.5)
283
+ items = await self.find_elements_by_text(text)
283
284
  return items
284
285
 
285
286
  async def select_all(
@@ -311,13 +312,13 @@ class Tab(Connection):
311
312
  items.extend(await fr.query_selector_all(selector))
312
313
  items.extend(await self.query_selector_all(selector))
313
314
  while not items:
314
- await self
315
- items = await self.query_selector_all(selector)
316
315
  if loop.time() - now > timeout:
317
316
  raise asyncio.TimeoutError(
318
317
  "Time ran out while waiting for: {%s}" % selector
319
318
  )
319
+ await self
320
320
  await self.sleep(0.5)
321
+ items = await self.query_selector_all(selector)
321
322
  return items
322
323
 
323
324
  async def get(
@@ -1098,25 +1099,32 @@ class Tab(Connection):
1098
1099
  """
1099
1100
  loop = asyncio.get_running_loop()
1100
1101
  now = loop.time()
1102
+ item = None
1101
1103
  if selector:
1102
- item = await self.query_selector(selector)
1103
- while not item:
1104
+ with suppress(Exception):
1104
1105
  item = await self.query_selector(selector)
1106
+ while not item:
1105
1107
  if loop.time() - now > timeout:
1106
1108
  raise asyncio.TimeoutError(
1107
1109
  "Time ran out while waiting for: {%s}" % selector
1108
1110
  )
1111
+ await self
1109
1112
  await self.sleep(0.068)
1113
+ with suppress(Exception):
1114
+ item = await self.query_selector(selector)
1110
1115
  return item
1111
1116
  if text:
1112
- item = await self.find_element_by_text(text)
1113
- while not item:
1117
+ with suppress(Exception):
1114
1118
  item = await self.find_element_by_text(text)
1119
+ while not item:
1115
1120
  if loop.time() - now > timeout:
1116
1121
  raise asyncio.TimeoutError(
1117
1122
  "Time ran out while waiting for: {%s}" % text
1118
1123
  )
1124
+ await self
1119
1125
  await self.sleep(0.068)
1126
+ with suppress(Exception):
1127
+ item = await self.find_element_by_text(text)
1120
1128
  return item
1121
1129
 
1122
1130
  async def set_attributes(self, selector, attribute, value):