seleniumbase 4.47.9__tar.gz → 4.48.0__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.47.9/seleniumbase.egg-info → seleniumbase-4.48.0}/PKG-INFO +7 -10
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/README.md +0 -2
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/requirements.txt +4 -5
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/__version__.py +1 -1
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_mkfile.py +1 -1
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_mkrec.py +1 -1
- seleniumbase-4.48.0/seleniumbase/core/nest_asyncio.py +282 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/sb_cdp.py +71 -12
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/sb_manager.py +1 -3
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/tab.py +48 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0/seleniumbase.egg-info}/PKG-INFO +7 -10
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase.egg-info/SOURCES.txt +1 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase.egg-info/requires.txt +6 -7
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/setup.py +6 -7
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/.gitignore +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/LICENSE +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/MANIFEST.in +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/install.sh +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/pyproject.toml +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/pytest.ini +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/sbase/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/sbase/__main__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/sbase/steps.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/__main__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/behave/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/behave/behave_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/behave/behave_sb.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/behave/steps.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/decorators.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/encryption.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/exceptions.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/obfuscate.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/common/unobfuscate.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/config/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/config/ad_block_list.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/config/proxy_list.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/config/settings.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/logo_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/rich_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/run.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_behave_gui.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_caseplans.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_commander.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_install.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_mkchart.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_mkdir.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_mkpres.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_objectify.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_print.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/console_scripts/sb_recorder.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/application_manager.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/browser_launcher.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/capabilities_parser.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/colored_traceback.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/create_db_tables.sql +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/detect_b_ver.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/download_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/encoded_images.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/jqc_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/log_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/mysql.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/proxy_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/recorder_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/report_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/s3_manager.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/sb_driver.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/session_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/settings_parser.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/style_sheet.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/testcase_manager.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/tour_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/core/visual_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/cft_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/chs_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/extensions/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/extensions/ad_block.zip +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/extensions/disable_csp.zip +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/extensions/recorder.zip +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/extensions/sbase_ext.zip +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/base_case.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/constants.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/css_to_xpath.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/errors.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/js_utils.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/page_actions.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/page_utils.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/shared_utils.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/unittest_helper.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/words.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/fixtures/xpath_to_css.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/js_code/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/js_code/active_css_js.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/js_code/live_js.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/js_code/recorder_js.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/masterqa/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/masterqa/master_qa.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/base_plugin.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/basic_test_info.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/db_reporting_plugin.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/driver_manager.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/page_source.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/pytest_plugin.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/s3_logging_plugin.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/screen_shots.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/plugins/selenium_plugin.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/resources/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/chinese.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/dutch.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/french.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/italian.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/japanese.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/korean.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/master_dict.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/portuguese.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/russian.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/spanish.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/translate/translator.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/_contradict.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/browser.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/cdp_util.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/config.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/connection.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/cdp_driver/element.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/dprocess.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/options.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/patcher.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/reactor.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/undetected/webelement.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/download_selenium_server.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/font_color +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/grid-hub +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/grid-node +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/grid_hub.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/grid_node.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/register-grid-node.bat +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/register-grid-node.sh +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/start-grid-hub.bat +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_grid/start-grid-hub.sh +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_ide/__init__.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase/utilities/selenium_ide/convert_ide.py +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase.egg-info/dependency_links.txt +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase.egg-info/entry_points.txt +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/seleniumbase.egg-info/top_level.txt +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/setup.cfg +0 -0
- {seleniumbase-4.47.9 → seleniumbase-4.48.0}/virtualenv_install.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: seleniumbase
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.48.0
|
|
4
4
|
Summary: A complete web automation framework for end-to-end testing.
|
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
|
6
6
|
Author: Michael Mintz
|
|
@@ -74,7 +74,7 @@ Requires-Dist: fasteners>=0.20
|
|
|
74
74
|
Requires-Dist: mycdp>=1.3.7
|
|
75
75
|
Requires-Dist: pynose>=1.5.5
|
|
76
76
|
Requires-Dist: platformdirs~=4.4.0; python_version < "3.10"
|
|
77
|
-
Requires-Dist: platformdirs>=4.9.
|
|
77
|
+
Requires-Dist: platformdirs>=4.9.6; python_version >= "3.10"
|
|
78
78
|
Requires-Dist: typing-extensions>=4.15.0
|
|
79
79
|
Requires-Dist: sbvirtualdisplay>=1.4.0
|
|
80
80
|
Requires-Dist: MarkupSafe>=3.0.3
|
|
@@ -89,7 +89,7 @@ Requires-Dist: pyreadline3>=3.5.4; platform_system == "Windows"
|
|
|
89
89
|
Requires-Dist: tabcompleter>=1.4.0
|
|
90
90
|
Requires-Dist: pdbp>=1.8.2
|
|
91
91
|
Requires-Dist: idna>=3.11
|
|
92
|
-
Requires-Dist: charset-normalizer<4,>=3.4.
|
|
92
|
+
Requires-Dist: charset-normalizer<4,>=3.4.7
|
|
93
93
|
Requires-Dist: urllib3<2,>=1.26.20; python_version < "3.10"
|
|
94
94
|
Requires-Dist: urllib3<3,>=1.26.20; python_version >= "3.10"
|
|
95
95
|
Requires-Dist: requests~=2.32.5; python_version < "3.10"
|
|
@@ -104,10 +104,9 @@ Requires-Dist: wsproto==1.2.0; python_version < "3.10"
|
|
|
104
104
|
Requires-Dist: wsproto~=1.3.2; python_version >= "3.10"
|
|
105
105
|
Requires-Dist: websocket-client~=1.9.0
|
|
106
106
|
Requires-Dist: selenium==4.32.0; python_version < "3.10"
|
|
107
|
-
Requires-Dist: selenium==4.
|
|
107
|
+
Requires-Dist: selenium==4.43.0; python_version >= "3.10"
|
|
108
108
|
Requires-Dist: cssselect==1.3.0; python_version < "3.10"
|
|
109
109
|
Requires-Dist: cssselect<2,>=1.4.0; python_version >= "3.10"
|
|
110
|
-
Requires-Dist: nest-asyncio==1.6.0
|
|
111
110
|
Requires-Dist: sortedcontainers==2.4.0
|
|
112
111
|
Requires-Dist: execnet==2.1.1; python_version < "3.10"
|
|
113
112
|
Requires-Dist: execnet==2.1.2; python_version >= "3.10"
|
|
@@ -115,7 +114,7 @@ Requires-Dist: iniconfig==2.1.0; python_version < "3.10"
|
|
|
115
114
|
Requires-Dist: iniconfig==2.3.0; python_version >= "3.10"
|
|
116
115
|
Requires-Dist: pluggy==1.6.0
|
|
117
116
|
Requires-Dist: pytest==8.4.2; python_version < "3.11"
|
|
118
|
-
Requires-Dist: pytest==9.0.
|
|
117
|
+
Requires-Dist: pytest==9.0.3; python_version >= "3.11"
|
|
119
118
|
Requires-Dist: pytest-html==4.0.2
|
|
120
119
|
Requires-Dist: pytest-metadata==3.1.1
|
|
121
120
|
Requires-Dist: pytest-ordering==0.6
|
|
@@ -154,13 +153,13 @@ Requires-Dist: mss==10.1.0; extra == "mss"
|
|
|
154
153
|
Provides-Extra: pdfminer
|
|
155
154
|
Requires-Dist: pdfminer.six==20251107; python_version < "3.10" and extra == "pdfminer"
|
|
156
155
|
Requires-Dist: pdfminer.six==20260107; python_version >= "3.10" and extra == "pdfminer"
|
|
157
|
-
Requires-Dist: cryptography==46.0.
|
|
156
|
+
Requires-Dist: cryptography==46.0.7; extra == "pdfminer"
|
|
158
157
|
Requires-Dist: cffi==2.0.0; extra == "pdfminer"
|
|
159
158
|
Requires-Dist: pycparser==2.23; python_version < "3.10" and extra == "pdfminer"
|
|
160
159
|
Requires-Dist: pycparser==3.0; python_version >= "3.10" and extra == "pdfminer"
|
|
161
160
|
Provides-Extra: pillow
|
|
162
161
|
Requires-Dist: Pillow>=11.3.0; python_version < "3.10" and extra == "pillow"
|
|
163
|
-
Requires-Dist: Pillow>=12.
|
|
162
|
+
Requires-Dist: Pillow>=12.2.0; python_version >= "3.10" and extra == "pillow"
|
|
164
163
|
Provides-Extra: pip-system-certs
|
|
165
164
|
Requires-Dist: pip-system-certs==4.0; platform_system == "Windows" and extra == "pip-system-certs"
|
|
166
165
|
Provides-Extra: proxy
|
|
@@ -818,8 +817,6 @@ import time; time.sleep(3) # Do nothing for 3 seconds.
|
|
|
818
817
|
🔵 **Debug Mode** with Python's built-in **[pdb](https://docs.python.org/3/library/pdb.html)** library helps you debug tests:
|
|
819
818
|
|
|
820
819
|
```python
|
|
821
|
-
import pdb; pdb.set_trace()
|
|
822
|
-
import pytest; pytest.set_trace()
|
|
823
820
|
breakpoint() # Shortcut for "import pdb; pdb.set_trace()"
|
|
824
821
|
```
|
|
825
822
|
|
|
@@ -617,8 +617,6 @@ import time; time.sleep(3) # Do nothing for 3 seconds.
|
|
|
617
617
|
🔵 **Debug Mode** with Python's built-in **[pdb](https://docs.python.org/3/library/pdb.html)** library helps you debug tests:
|
|
618
618
|
|
|
619
619
|
```python
|
|
620
|
-
import pdb; pdb.set_trace()
|
|
621
|
-
import pytest; pytest.set_trace()
|
|
622
620
|
breakpoint() # Shortcut for "import pdb; pdb.set_trace()"
|
|
623
621
|
```
|
|
624
622
|
|
|
@@ -14,7 +14,7 @@ fasteners>=0.20
|
|
|
14
14
|
mycdp>=1.3.7
|
|
15
15
|
pynose>=1.5.5
|
|
16
16
|
platformdirs~=4.4.0;python_version<"3.10"
|
|
17
|
-
platformdirs>=4.9.
|
|
17
|
+
platformdirs>=4.9.6;python_version>="3.10"
|
|
18
18
|
typing-extensions>=4.15.0
|
|
19
19
|
sbvirtualdisplay>=1.4.0
|
|
20
20
|
MarkupSafe>=3.0.3
|
|
@@ -29,7 +29,7 @@ pyreadline3>=3.5.4;platform_system=="Windows"
|
|
|
29
29
|
tabcompleter>=1.4.0
|
|
30
30
|
pdbp>=1.8.2
|
|
31
31
|
idna>=3.11
|
|
32
|
-
charset-normalizer>=3.4.
|
|
32
|
+
charset-normalizer>=3.4.7,<4
|
|
33
33
|
urllib3>=1.26.20,<2;python_version<"3.10"
|
|
34
34
|
urllib3>=1.26.20,<3;python_version>="3.10"
|
|
35
35
|
requests~=2.32.5;python_version<"3.10"
|
|
@@ -44,10 +44,9 @@ wsproto==1.2.0;python_version<"3.10"
|
|
|
44
44
|
wsproto~=1.3.2;python_version>="3.10"
|
|
45
45
|
websocket-client~=1.9.0
|
|
46
46
|
selenium==4.32.0;python_version<"3.10"
|
|
47
|
-
selenium==4.
|
|
47
|
+
selenium==4.43.0;python_version>="3.10"
|
|
48
48
|
cssselect==1.3.0;python_version<"3.10"
|
|
49
49
|
cssselect>=1.4.0,<2;python_version>="3.10"
|
|
50
|
-
nest-asyncio==1.6.0
|
|
51
50
|
sortedcontainers==2.4.0
|
|
52
51
|
execnet==2.1.1;python_version<"3.10"
|
|
53
52
|
execnet==2.1.2;python_version>="3.10"
|
|
@@ -55,7 +54,7 @@ iniconfig==2.1.0;python_version<"3.10"
|
|
|
55
54
|
iniconfig==2.3.0;python_version>="3.10"
|
|
56
55
|
pluggy==1.6.0
|
|
57
56
|
pytest==8.4.2;python_version<"3.11"
|
|
58
|
-
pytest==9.0.
|
|
57
|
+
pytest==9.0.3;python_version>="3.11"
|
|
59
58
|
pytest-html==4.0.2
|
|
60
59
|
pytest-metadata==3.1.1
|
|
61
60
|
pytest-ordering==0.6
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# seleniumbase package
|
|
2
|
-
__version__ = "4.
|
|
2
|
+
__version__ = "4.48.0"
|
|
@@ -277,7 +277,7 @@ def main():
|
|
|
277
277
|
data.append(' self.open("%s")' % url)
|
|
278
278
|
else:
|
|
279
279
|
data.append(" if self.recorder_ext and not self.xvfb:")
|
|
280
|
-
data.append("
|
|
280
|
+
data.append(" breakpoint()")
|
|
281
281
|
if not basic and not recorder:
|
|
282
282
|
data.append(
|
|
283
283
|
' self.type("input", "%s")' " # selector, text" % goodbye
|
|
@@ -216,7 +216,7 @@ def main():
|
|
|
216
216
|
data.append(" if self.recorder_ext:")
|
|
217
217
|
data.append(" # When done recording actions,")
|
|
218
218
|
data.append(' # type "c", and press [Enter].')
|
|
219
|
-
data.append("
|
|
219
|
+
data.append(" breakpoint()")
|
|
220
220
|
data.append("")
|
|
221
221
|
|
|
222
222
|
if esc_end:
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""Patch asyncio to allow nested event loops."""
|
|
2
|
+
import asyncio
|
|
3
|
+
import asyncio.events as events
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
import threading
|
|
7
|
+
from contextlib import contextmanager, suppress
|
|
8
|
+
from heapq import heappop
|
|
9
|
+
|
|
10
|
+
_run_close_loop = True
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PatchedNestAsyncio:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def apply(loop=None, *, run_close_loop=False, error_on_mispatched=False):
|
|
18
|
+
global _run_close_loop
|
|
19
|
+
_patch_asyncio(error_on_mispatched=error_on_mispatched)
|
|
20
|
+
_patch_policy()
|
|
21
|
+
_patch_tornado()
|
|
22
|
+
loop = loop or _get_event_loop()
|
|
23
|
+
if loop is not None:
|
|
24
|
+
_patch_loop(loop)
|
|
25
|
+
_run_close_loop &= run_close_loop
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if sys.version_info < (3, 14, 0):
|
|
29
|
+
def _get_event_loop():
|
|
30
|
+
return asyncio.get_event_loop()
|
|
31
|
+
else:
|
|
32
|
+
def _get_event_loop():
|
|
33
|
+
try:
|
|
34
|
+
return asyncio.get_event_loop()
|
|
35
|
+
except RuntimeError:
|
|
36
|
+
return None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if sys.version_info < (3, 12, 0):
|
|
40
|
+
def run(main, *, debug=False):
|
|
41
|
+
loop = asyncio.get_event_loop()
|
|
42
|
+
loop.set_debug(debug)
|
|
43
|
+
task = asyncio.ensure_future(main)
|
|
44
|
+
try:
|
|
45
|
+
return loop.run_until_complete(task)
|
|
46
|
+
finally:
|
|
47
|
+
if not task.done():
|
|
48
|
+
task.cancel()
|
|
49
|
+
with suppress(asyncio.CancelledError):
|
|
50
|
+
loop.run_until_complete(task)
|
|
51
|
+
else:
|
|
52
|
+
def run(main, *, debug=False, loop_factory=None):
|
|
53
|
+
new_event_loop = False
|
|
54
|
+
set_event_loop = None
|
|
55
|
+
try:
|
|
56
|
+
loop = asyncio.get_running_loop()
|
|
57
|
+
except RuntimeError:
|
|
58
|
+
if not _run_close_loop:
|
|
59
|
+
loop = _get_event_loop()
|
|
60
|
+
if loop is None:
|
|
61
|
+
if loop_factory is None:
|
|
62
|
+
loop_factory = asyncio.new_event_loop
|
|
63
|
+
loop = loop_factory()
|
|
64
|
+
asyncio.set_event_loop(loop)
|
|
65
|
+
else:
|
|
66
|
+
if loop_factory is None:
|
|
67
|
+
loop = asyncio.new_event_loop()
|
|
68
|
+
set_event_loop = _get_event_loop()
|
|
69
|
+
asyncio.set_event_loop(loop)
|
|
70
|
+
else:
|
|
71
|
+
loop = loop_factory()
|
|
72
|
+
new_event_loop = True
|
|
73
|
+
_patch_loop(loop)
|
|
74
|
+
|
|
75
|
+
loop.set_debug(debug)
|
|
76
|
+
task = asyncio.ensure_future(main, loop=loop)
|
|
77
|
+
try:
|
|
78
|
+
return loop.run_until_complete(task)
|
|
79
|
+
finally:
|
|
80
|
+
if not task.done():
|
|
81
|
+
task.cancel()
|
|
82
|
+
with suppress(asyncio.CancelledError):
|
|
83
|
+
loop.run_until_complete(task)
|
|
84
|
+
if set_event_loop:
|
|
85
|
+
asyncio.set_event_loop(set_event_loop)
|
|
86
|
+
if new_event_loop:
|
|
87
|
+
# Avoid ResourceWarning: unclosed event loop
|
|
88
|
+
loop.close()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _patch_asyncio(*, error_on_mispatched=False):
|
|
92
|
+
"""Patch asyncio module to use pure Python tasks and futures."""
|
|
93
|
+
|
|
94
|
+
def _get_event_loop(stacklevel=3):
|
|
95
|
+
loop = events._get_running_loop()
|
|
96
|
+
if loop is None:
|
|
97
|
+
if sys.version_info < (3, 14, 0):
|
|
98
|
+
policy = events.get_event_loop_policy()
|
|
99
|
+
else:
|
|
100
|
+
policy = events._get_event_loop_policy()
|
|
101
|
+
loop = policy.get_event_loop()
|
|
102
|
+
return loop
|
|
103
|
+
|
|
104
|
+
if hasattr(asyncio, "_nest_patched"):
|
|
105
|
+
if not hasattr(asyncio, "_nest_asyncio"):
|
|
106
|
+
if error_on_mispatched:
|
|
107
|
+
raise RuntimeError("asyncio was already patched!")
|
|
108
|
+
elif sys.version_info >= (3, 12, 0):
|
|
109
|
+
import warnings
|
|
110
|
+
warnings.warn("asyncio was already patched!")
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
asyncio.tasks.Task = asyncio.tasks._PyTask
|
|
114
|
+
asyncio.Task = asyncio.tasks._CTask = asyncio.tasks.Task
|
|
115
|
+
asyncio.Future = asyncio.futures._CFuture = asyncio.futures.Future = (
|
|
116
|
+
asyncio.futures._PyFuture
|
|
117
|
+
)
|
|
118
|
+
asyncio.get_event_loop = _get_event_loop
|
|
119
|
+
events._get_event_loop = events.get_event_loop = asyncio.get_event_loop
|
|
120
|
+
asyncio.run = run
|
|
121
|
+
asyncio._nest_patched = True
|
|
122
|
+
asyncio._nest_asyncio = PatchedNestAsyncio()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _patch_policy():
|
|
126
|
+
"""Patch the policy to always return a patched loop."""
|
|
127
|
+
|
|
128
|
+
def get_event_loop(self):
|
|
129
|
+
if self._local._loop is None:
|
|
130
|
+
loop = self.new_event_loop()
|
|
131
|
+
_patch_loop(loop)
|
|
132
|
+
self.set_event_loop(loop)
|
|
133
|
+
return self._local._loop
|
|
134
|
+
|
|
135
|
+
if sys.version_info < (3, 14, 0):
|
|
136
|
+
policy = events.get_event_loop_policy()
|
|
137
|
+
else:
|
|
138
|
+
policy = events._get_event_loop_policy()
|
|
139
|
+
policy.__class__.get_event_loop = get_event_loop
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _patch_loop(loop):
|
|
143
|
+
"""Patch loop to make it reentrant."""
|
|
144
|
+
|
|
145
|
+
def run_forever(self):
|
|
146
|
+
with manage_run(self), manage_asyncgens(self):
|
|
147
|
+
while True:
|
|
148
|
+
self._run_once()
|
|
149
|
+
if self._stopping:
|
|
150
|
+
break
|
|
151
|
+
self._stopping = False
|
|
152
|
+
|
|
153
|
+
def run_until_complete(self, future):
|
|
154
|
+
with manage_run(self):
|
|
155
|
+
f = asyncio.ensure_future(future, loop=self)
|
|
156
|
+
if f is not future:
|
|
157
|
+
f._log_destroy_pending = False
|
|
158
|
+
while not f.done():
|
|
159
|
+
self._run_once()
|
|
160
|
+
if self._stopping:
|
|
161
|
+
break
|
|
162
|
+
if not f.done():
|
|
163
|
+
raise RuntimeError("Loop stopped before Future completed!")
|
|
164
|
+
return f.result()
|
|
165
|
+
|
|
166
|
+
def _run_once(self):
|
|
167
|
+
"""Simplified re-implementation of asyncio's _run_once."""
|
|
168
|
+
ready = self._ready
|
|
169
|
+
scheduled = self._scheduled
|
|
170
|
+
while scheduled and scheduled[0]._cancelled:
|
|
171
|
+
heappop(scheduled)
|
|
172
|
+
timeout = (
|
|
173
|
+
0
|
|
174
|
+
if ready or self._stopping
|
|
175
|
+
else min(max(scheduled[0]._when - self.time(), 0), 86400)
|
|
176
|
+
if scheduled
|
|
177
|
+
else None
|
|
178
|
+
)
|
|
179
|
+
event_list = self._selector.select(timeout)
|
|
180
|
+
self._process_events(event_list)
|
|
181
|
+
end_time = self.time() + self._clock_resolution
|
|
182
|
+
while scheduled and scheduled[0]._when < end_time:
|
|
183
|
+
handle = heappop(scheduled)
|
|
184
|
+
ready.append(handle)
|
|
185
|
+
for _ in range(len(ready)):
|
|
186
|
+
if not ready:
|
|
187
|
+
break
|
|
188
|
+
handle = ready.popleft()
|
|
189
|
+
if not handle._cancelled:
|
|
190
|
+
if sys.version_info < (3, 14, 0):
|
|
191
|
+
curr_task = curr_tasks.pop(self, None)
|
|
192
|
+
else:
|
|
193
|
+
try:
|
|
194
|
+
curr_task = asyncio.tasks._swap_current_task(
|
|
195
|
+
self, None
|
|
196
|
+
)
|
|
197
|
+
except KeyError:
|
|
198
|
+
curr_task = None
|
|
199
|
+
try:
|
|
200
|
+
handle._run()
|
|
201
|
+
finally:
|
|
202
|
+
if curr_task is not None:
|
|
203
|
+
if sys.version_info < (3, 14, 0):
|
|
204
|
+
curr_tasks[self] = curr_task
|
|
205
|
+
else:
|
|
206
|
+
asyncio.tasks._swap_current_task(self, curr_task)
|
|
207
|
+
handle = None
|
|
208
|
+
|
|
209
|
+
@contextmanager
|
|
210
|
+
def manage_run(self):
|
|
211
|
+
self._check_closed()
|
|
212
|
+
old_thread_id = self._thread_id
|
|
213
|
+
old_running_loop = events._get_running_loop()
|
|
214
|
+
try:
|
|
215
|
+
self._thread_id = threading.get_ident()
|
|
216
|
+
events._set_running_loop(self)
|
|
217
|
+
self._num_runs_pending += 1
|
|
218
|
+
if self._is_proactorloop:
|
|
219
|
+
if self._self_reading_future is None:
|
|
220
|
+
self.call_soon(self._loop_self_reading)
|
|
221
|
+
yield
|
|
222
|
+
finally:
|
|
223
|
+
self._thread_id = old_thread_id
|
|
224
|
+
events._set_running_loop(old_running_loop)
|
|
225
|
+
self._num_runs_pending -= 1
|
|
226
|
+
if self._is_proactorloop:
|
|
227
|
+
if (
|
|
228
|
+
self._num_runs_pending == 0
|
|
229
|
+
and self._self_reading_future is not None
|
|
230
|
+
):
|
|
231
|
+
ov = self._self_reading_future._ov
|
|
232
|
+
self._self_reading_future.cancel()
|
|
233
|
+
if ov is not None:
|
|
234
|
+
self._proactor._unregister(ov)
|
|
235
|
+
self._self_reading_future = None
|
|
236
|
+
|
|
237
|
+
@contextmanager
|
|
238
|
+
def manage_asyncgens(self):
|
|
239
|
+
old_agen_hooks = sys.get_asyncgen_hooks()
|
|
240
|
+
try:
|
|
241
|
+
self._set_coroutine_origin_tracking(self._debug)
|
|
242
|
+
if self._asyncgens is not None:
|
|
243
|
+
sys.set_asyncgen_hooks(
|
|
244
|
+
firstiter=self._asyncgen_firstiter_hook,
|
|
245
|
+
finalizer=self._asyncgen_finalizer_hook,
|
|
246
|
+
)
|
|
247
|
+
yield
|
|
248
|
+
finally:
|
|
249
|
+
self._set_coroutine_origin_tracking(False)
|
|
250
|
+
if self._asyncgens is not None:
|
|
251
|
+
sys.set_asyncgen_hooks(*old_agen_hooks)
|
|
252
|
+
|
|
253
|
+
def _check_running(self):
|
|
254
|
+
"""Do not throw exception if loop is already running."""
|
|
255
|
+
pass
|
|
256
|
+
|
|
257
|
+
if hasattr(loop, "_nest_patched"):
|
|
258
|
+
return
|
|
259
|
+
if not isinstance(loop, asyncio.BaseEventLoop):
|
|
260
|
+
raise ValueError("Can't patch loop of type %s" % type(loop))
|
|
261
|
+
cls = loop.__class__
|
|
262
|
+
cls.run_forever = run_forever
|
|
263
|
+
cls.run_until_complete = run_until_complete
|
|
264
|
+
cls._run_once = _run_once
|
|
265
|
+
cls._check_running = _check_running
|
|
266
|
+
cls._num_runs_pending = 1 if loop.is_running() else 0
|
|
267
|
+
cls._is_proactorloop = os.name == "nt" and issubclass(
|
|
268
|
+
cls, asyncio.ProactorEventLoop
|
|
269
|
+
)
|
|
270
|
+
curr_tasks = asyncio.tasks._current_tasks
|
|
271
|
+
cls._nest_patched = True
|
|
272
|
+
cls._nest_asyncio = PatchedNestAsyncio()
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _patch_tornado():
|
|
276
|
+
"""If tornado is imported before nest_asyncio,
|
|
277
|
+
make tornado aware of the pure-Python asyncio Future."""
|
|
278
|
+
if "tornado" in sys.modules:
|
|
279
|
+
import tornado.concurrent as tc # type: ignore
|
|
280
|
+
tc.Future = asyncio.Future
|
|
281
|
+
if asyncio.Future not in tc.FUTURES:
|
|
282
|
+
tc.FUTURES += (asyncio.Future,)
|
|
@@ -193,7 +193,7 @@ class CDPMethods():
|
|
|
193
193
|
Also sets an environment variable to hide this warning:
|
|
194
194
|
Deprecation: "url.parse() behavior is not standardized".
|
|
195
195
|
(github.com/microsoft/playwright-python/issues/3016)"""
|
|
196
|
-
import nest_asyncio
|
|
196
|
+
from seleniumbase.core import nest_asyncio
|
|
197
197
|
nest_asyncio.apply()
|
|
198
198
|
os.environ["NODE_NO_WARNINGS"] = "1"
|
|
199
199
|
driver = self.driver
|
|
@@ -400,7 +400,7 @@ class CDPMethods():
|
|
|
400
400
|
self.__add_light_pause()
|
|
401
401
|
selector = self.__convert_to_css_if_xpath(selector)
|
|
402
402
|
if not self.is_element_present(selector):
|
|
403
|
-
|
|
403
|
+
time.sleep(1)
|
|
404
404
|
timeout = timeout - 1
|
|
405
405
|
if timeout < 1:
|
|
406
406
|
timeout = 1
|
|
@@ -2061,7 +2061,7 @@ class CDPMethods():
|
|
|
2061
2061
|
return False
|
|
2062
2062
|
|
|
2063
2063
|
def _on_a_datadome_slider_page(self, *args, **kwargs):
|
|
2064
|
-
self.loop.run_until_complete(self.page.wait(0.
|
|
2064
|
+
self.loop.run_until_complete(self.page.wait(0.05))
|
|
2065
2065
|
if (
|
|
2066
2066
|
self.is_element_visible(
|
|
2067
2067
|
'body > iframe[src*="/geo.captcha-delivery.com/captcha/"]'
|
|
@@ -2070,6 +2070,12 @@ class CDPMethods():
|
|
|
2070
2070
|
return True
|
|
2071
2071
|
return False
|
|
2072
2072
|
|
|
2073
|
+
def _on_a_friendly_captcha_page(self, *args, **kwargs):
|
|
2074
|
+
self.loop.run_until_complete(self.page.wait(0.05))
|
|
2075
|
+
if self.is_element_visible('iframe[data--frc-frame-id]'):
|
|
2076
|
+
return True
|
|
2077
|
+
return False
|
|
2078
|
+
|
|
2073
2079
|
def _on_a_g_recaptcha_page(self, *args, **kwargs):
|
|
2074
2080
|
time.sleep(0.4) # reCAPTCHA may need a moment to appear
|
|
2075
2081
|
self.loop.run_until_complete(self.page.wait(0.1))
|
|
@@ -2131,7 +2137,7 @@ class CDPMethods():
|
|
|
2131
2137
|
sb_config._saved_cf_x_y = (x, y)
|
|
2132
2138
|
time.sleep(0.08)
|
|
2133
2139
|
if use_cdp:
|
|
2134
|
-
|
|
2140
|
+
time.sleep(0.03)
|
|
2135
2141
|
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2136
2142
|
with gui_lock: # Prevent issues with multiple processes
|
|
2137
2143
|
self.bring_active_window_to_front()
|
|
@@ -2163,7 +2169,7 @@ class CDPMethods():
|
|
|
2163
2169
|
time.sleep(0.15)
|
|
2164
2170
|
return True
|
|
2165
2171
|
|
|
2166
|
-
def __cdp_click_incapsula_hcaptcha(self):
|
|
2172
|
+
def __cdp_click_incapsula_hcaptcha(self, use_cdp=True):
|
|
2167
2173
|
selector = "iframe[data-hcaptcha-widget-id]"
|
|
2168
2174
|
if self.is_element_visible('iframe[src*="_Incapsula_Resource?"]'):
|
|
2169
2175
|
outer_selector = 'iframe[src*="_Incapsula_Resource?"]'
|
|
@@ -2212,6 +2218,56 @@ class CDPMethods():
|
|
|
2212
2218
|
print(" <DEBUG> hCaptcha was NOT clicked!")
|
|
2213
2219
|
return False
|
|
2214
2220
|
|
|
2221
|
+
def __gui_click_friendly_captcha(self, use_cdp=False):
|
|
2222
|
+
selector = 'iframe[data--frc-frame-id]'
|
|
2223
|
+
if self.is_element_visible('iframe[data--frc-frame-id]'):
|
|
2224
|
+
element = self.select('iframe[data--frc-frame-id]')
|
|
2225
|
+
else:
|
|
2226
|
+
return False
|
|
2227
|
+
time.sleep(0.05)
|
|
2228
|
+
self.loop.run_until_complete(self.page.wait(0.1))
|
|
2229
|
+
time.sleep(0.05)
|
|
2230
|
+
with suppress(Exception):
|
|
2231
|
+
element_rect = self.get_element_rect(selector, timeout=0.1)
|
|
2232
|
+
e_x = element_rect["x"]
|
|
2233
|
+
e_y = element_rect["y"]
|
|
2234
|
+
window_rect = self.get_window_rect()
|
|
2235
|
+
win_width = window_rect["innerWidth"]
|
|
2236
|
+
win_height = window_rect["innerHeight"]
|
|
2237
|
+
if (
|
|
2238
|
+
e_x > 1040
|
|
2239
|
+
and e_y > 640
|
|
2240
|
+
and abs(win_width - e_x) < 110
|
|
2241
|
+
and abs(win_height - e_y) < 110
|
|
2242
|
+
):
|
|
2243
|
+
return False
|
|
2244
|
+
gui_element_rect = self.get_gui_element_rect(selector, timeout=1)
|
|
2245
|
+
gui_e_x = gui_element_rect["x"]
|
|
2246
|
+
gui_e_y = gui_element_rect["y"]
|
|
2247
|
+
x_offset = 27
|
|
2248
|
+
y_offset = 34
|
|
2249
|
+
x = gui_e_x + x_offset
|
|
2250
|
+
y = gui_e_y + y_offset
|
|
2251
|
+
sb_config._saved_cf_x_y = (x, y)
|
|
2252
|
+
time.sleep(0.08)
|
|
2253
|
+
if use_cdp:
|
|
2254
|
+
time.sleep(0.03)
|
|
2255
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2256
|
+
with gui_lock: # Prevent issues with multiple processes
|
|
2257
|
+
self.bring_active_window_to_front()
|
|
2258
|
+
time.sleep(0.06)
|
|
2259
|
+
element.mouse_move()
|
|
2260
|
+
time.sleep(0.08)
|
|
2261
|
+
self.click_with_offset(selector, x_offset, y_offset)
|
|
2262
|
+
time.sleep(0.08)
|
|
2263
|
+
element.mouse_move()
|
|
2264
|
+
time.sleep(0.25)
|
|
2265
|
+
return True
|
|
2266
|
+
else:
|
|
2267
|
+
self.gui_click_x_y(x, y)
|
|
2268
|
+
return True
|
|
2269
|
+
return False
|
|
2270
|
+
|
|
2215
2271
|
def solve_captcha(self):
|
|
2216
2272
|
self.__click_captcha(use_cdp=True)
|
|
2217
2273
|
|
|
@@ -2225,9 +2281,9 @@ class CDPMethods():
|
|
|
2225
2281
|
|
|
2226
2282
|
def __click_captcha(self, use_cdp=False):
|
|
2227
2283
|
"""Uses PyAutoGUI unless use_cdp == True"""
|
|
2228
|
-
|
|
2284
|
+
time.sleep(0.075)
|
|
2229
2285
|
self.loop.run_until_complete(self.page.wait(0.1))
|
|
2230
|
-
|
|
2286
|
+
time.sleep(0.025)
|
|
2231
2287
|
source = self.get_page_source()
|
|
2232
2288
|
if self._on_a_cf_turnstile_page(source):
|
|
2233
2289
|
pass
|
|
@@ -2240,6 +2296,9 @@ class CDPMethods():
|
|
|
2240
2296
|
elif self._on_a_datadome_slider_page():
|
|
2241
2297
|
result = self.__gui_slide_datadome_captcha()
|
|
2242
2298
|
return result
|
|
2299
|
+
elif self._on_a_friendly_captcha_page():
|
|
2300
|
+
result = self.__gui_click_friendly_captcha(use_cdp)
|
|
2301
|
+
return result
|
|
2243
2302
|
else:
|
|
2244
2303
|
return False
|
|
2245
2304
|
selector = None
|
|
@@ -2395,7 +2454,7 @@ class CDPMethods():
|
|
|
2395
2454
|
if hasattr(sb_config, "_cdp_proxy") and sb_config._cdp_proxy:
|
|
2396
2455
|
time.sleep(0.22) # CAPTCHA may load slower with proxy
|
|
2397
2456
|
if use_cdp:
|
|
2398
|
-
|
|
2457
|
+
time.sleep(0.03)
|
|
2399
2458
|
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2400
2459
|
with gui_lock: # Prevent issues with multiple processes
|
|
2401
2460
|
self.bring_active_window_to_front()
|
|
@@ -2595,9 +2654,9 @@ class CDPMethods():
|
|
|
2595
2654
|
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2596
2655
|
with gui_lock:
|
|
2597
2656
|
self.bring_active_window_to_front()
|
|
2598
|
-
|
|
2657
|
+
time.sleep(0.02)
|
|
2599
2658
|
element.mouse_move()
|
|
2600
|
-
|
|
2659
|
+
time.sleep(timeframe)
|
|
2601
2660
|
|
|
2602
2661
|
def hover_and_click(self, hover_selector, click_selector):
|
|
2603
2662
|
if getattr(sb_config, "_cdp_mobile_mode", None):
|
|
@@ -2607,9 +2666,9 @@ class CDPMethods():
|
|
|
2607
2666
|
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
2608
2667
|
with gui_lock:
|
|
2609
2668
|
self.bring_active_window_to_front()
|
|
2610
|
-
|
|
2669
|
+
time.sleep(0.02)
|
|
2611
2670
|
hover_element.mouse_move()
|
|
2612
|
-
|
|
2671
|
+
time.sleep(0.25)
|
|
2613
2672
|
try:
|
|
2614
2673
|
self.click(click_selector, timeout=0.5)
|
|
2615
2674
|
except Exception:
|
|
@@ -1408,9 +1408,7 @@ def SB(
|
|
|
1408
1408
|
test_passed = True # This can change later
|
|
1409
1409
|
teardown_exception = None
|
|
1410
1410
|
if "--trace" in sys_argv:
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
pdb.set_trace() # Debug Mode
|
|
1411
|
+
breakpoint() # Debug Mode
|
|
1414
1412
|
# Type "s" and press [Enter] to step into "yield sb".
|
|
1415
1413
|
try:
|
|
1416
1414
|
yield sb
|
|
@@ -1406,6 +1406,11 @@ class Tab(Connection):
|
|
|
1406
1406
|
return True
|
|
1407
1407
|
return False
|
|
1408
1408
|
|
|
1409
|
+
async def __on_a_friendly_captcha_page(self, *args, **kwargs):
|
|
1410
|
+
if await self.is_element_visible('iframe[data--frc-frame-id]'):
|
|
1411
|
+
return True
|
|
1412
|
+
return False
|
|
1413
|
+
|
|
1409
1414
|
async def __on_a_g_recaptcha_page(self, *args, **kwargs):
|
|
1410
1415
|
await self.sleep(0.4) # reCAPTCHA may need a moment to appear
|
|
1411
1416
|
source = await self.get_html()
|
|
@@ -1514,6 +1519,46 @@ class Tab(Connection):
|
|
|
1514
1519
|
print(" <DEBUG> hCaptcha was NOT clicked!")
|
|
1515
1520
|
return False
|
|
1516
1521
|
|
|
1522
|
+
async def __gui_click_friendly_captcha(self):
|
|
1523
|
+
selector = 'iframe[data--frc-frame-id]'
|
|
1524
|
+
if await self.is_element_visible('iframe[data--frc-frame-id]'):
|
|
1525
|
+
element = await self.find_element_by_text(selector)
|
|
1526
|
+
else:
|
|
1527
|
+
return False
|
|
1528
|
+
await self.sleep(0.55)
|
|
1529
|
+
x_offset = 27
|
|
1530
|
+
y_offset = 34
|
|
1531
|
+
was_clicked = False
|
|
1532
|
+
gui_lock = AsyncFileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1533
|
+
async with gui_lock:
|
|
1534
|
+
await self.bring_to_front()
|
|
1535
|
+
await self.sleep(0.056)
|
|
1536
|
+
if "--debug" in sys.argv:
|
|
1537
|
+
displayed_selector = "`%s`" % selector
|
|
1538
|
+
if '"' not in selector:
|
|
1539
|
+
displayed_selector = '"%s"' % selector
|
|
1540
|
+
elif "'" not in selector:
|
|
1541
|
+
displayed_selector = "'%s'" % selector
|
|
1542
|
+
print(
|
|
1543
|
+
" <DEBUG> click_with_offset(%s, %s, %s)"
|
|
1544
|
+
% (displayed_selector, x_offset, y_offset)
|
|
1545
|
+
)
|
|
1546
|
+
with suppress(Exception):
|
|
1547
|
+
await element.mouse_click_with_offset_async(
|
|
1548
|
+
x=x_offset, y=y_offset, center=False
|
|
1549
|
+
)
|
|
1550
|
+
was_clicked = True
|
|
1551
|
+
await self.sleep(0.075)
|
|
1552
|
+
if was_clicked:
|
|
1553
|
+
# Wait a moment for the click to succeed
|
|
1554
|
+
await self.sleep(0.75)
|
|
1555
|
+
if "--debug" in sys.argv:
|
|
1556
|
+
print(" <DEBUG> Friendly Captcha was clicked!")
|
|
1557
|
+
return True
|
|
1558
|
+
if "--debug" in sys.argv:
|
|
1559
|
+
print(" <DEBUG> Friendly Captcha was NOT clicked!")
|
|
1560
|
+
return False
|
|
1561
|
+
|
|
1517
1562
|
async def get_element_rect(self, selector, timeout=5):
|
|
1518
1563
|
element = await self.select(selector, timeout=timeout)
|
|
1519
1564
|
coordinates = None
|
|
@@ -1649,6 +1694,9 @@ class Tab(Connection):
|
|
|
1649
1694
|
elif await self.__on_an_incapsula_hcaptcha_page():
|
|
1650
1695
|
result = await self.__cdp_click_incapsula_hcaptcha()
|
|
1651
1696
|
return result
|
|
1697
|
+
elif await self.__on_a_friendly_captcha_page():
|
|
1698
|
+
result = await self.__gui_click_friendly_captcha()
|
|
1699
|
+
return result
|
|
1652
1700
|
else:
|
|
1653
1701
|
return False
|
|
1654
1702
|
selector = None
|