pydoll-python 2.15.0__tar.gz → 2.16.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.
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/PKG-INFO +24 -1
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/README.md +23 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/chromium/base.py +3 -3
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/tab.py +25 -4
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/constants.py +25 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/elements/mixins/find_elements_mixin.py +5 -5
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/elements/web_element.py +24 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pyproject.toml +1 -1
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/LICENSE +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/chromium/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/chromium/chrome.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/chromium/edge.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/interfaces.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/browser_options_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/browser_process_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/proxy_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/temp_dir_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/options.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/requests/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/requests/request.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/requests/response.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/browser_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/dom_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/fetch_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/input_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/network_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/page_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/runtime_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/storage_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/commands/target_commands.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/connection_handler.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/managers/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/managers/commands_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/managers/events_manager.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/decorators.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/elements/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/elements/mixins/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/exceptions.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/interactions/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/interactions/iframe.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/interactions/keyboard.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/interactions/scroll.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/base.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/browser/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/browser/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/browser/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/browser/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/debugger/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/dom/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/dom/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/dom/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/dom/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/emulation/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/fetch/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/fetch/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/fetch/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/fetch/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/input/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/input/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/input/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/input/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/io/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/network/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/network/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/network/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/network/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/page/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/page/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/page/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/page/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/runtime/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/runtime/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/runtime/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/runtime/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/security/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/storage/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/storage/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/storage/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/storage/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/target/__init__.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/target/events.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/target/methods.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/protocol/target/types.py +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/py.typed +0 -0
- {pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pydoll-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.16.0
|
|
4
4
|
Summary: Pydoll is a library for automating chromium-based browsers without a WebDriver, offering realistic interactions.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Thalison Fernandes
|
|
@@ -44,6 +44,29 @@ Forget broken `webdrivers`, compatibility issues, or being blocked by `navigator
|
|
|
44
44
|
|
|
45
45
|
It's designed for modern scraping, combining an **intuitive high-level API** (for productivity) with **deep-level control** over the network and browser behavior (for evasion), allowing you to bypass complex anti-bot defenses.
|
|
46
46
|
|
|
47
|
+
### Sponsors
|
|
48
|
+
|
|
49
|
+
<a href="https://www.thordata.com/?ls=github&lk=pydoll">
|
|
50
|
+
<img alt="Thordata" src="public/images/thordata.png" />
|
|
51
|
+
</a>
|
|
52
|
+
|
|
53
|
+
Pydoll is proudly sponsored by **[Thordata](https://www.thordata.com/?ls=github&lk=pydoll)**: a residential proxy network built for serious web scraping and automation. With **190+ real residential and ISP locations**, fully encrypted connections, and infrastructure optimized for high-performance workflows, Thordata is an excellent choice for scaling your Pydoll automations.
|
|
54
|
+
|
|
55
|
+
**[Sign up through our link](https://www.thordata.com/?ls=github&lk=pydoll)** to support the project and get **1GB free** to get started.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
<a href="https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc">
|
|
61
|
+
<img alt="CapSolver" src="public/images/capsolver.jpeg" />
|
|
62
|
+
</a>
|
|
63
|
+
|
|
64
|
+
Pydoll excels at behavioral evasion, but it doesn't solve captchas. That's where **[CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc)** comes in. An AI-powered service that handles reCAPTCHA, Cloudflare challenges, and more, seamlessly integrating with your automation workflows.
|
|
65
|
+
|
|
66
|
+
**[Register with our invite code](https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc)** and use code **PYDOLL** to get an extra **6% balance bonus**.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
47
70
|
### The Pydoll Philosophy
|
|
48
71
|
|
|
49
72
|
* **Stealth-by-Design:** Pydoll is built for evasion. Our [human-like interactions](https://pydoll.tech/docs/features/automation/human-interactions/) simulate real user clicks, typing, and scrolling to pass behavioral analysis, while granular [Browser Preferences](https://pydoll.tech/docs/features/configuration/browser-preferences/) control lets you patch your browser fingerprint.
|
|
@@ -24,6 +24,29 @@ Forget broken `webdrivers`, compatibility issues, or being blocked by `navigator
|
|
|
24
24
|
|
|
25
25
|
It's designed for modern scraping, combining an **intuitive high-level API** (for productivity) with **deep-level control** over the network and browser behavior (for evasion), allowing you to bypass complex anti-bot defenses.
|
|
26
26
|
|
|
27
|
+
### Sponsors
|
|
28
|
+
|
|
29
|
+
<a href="https://www.thordata.com/?ls=github&lk=pydoll">
|
|
30
|
+
<img alt="Thordata" src="public/images/thordata.png" />
|
|
31
|
+
</a>
|
|
32
|
+
|
|
33
|
+
Pydoll is proudly sponsored by **[Thordata](https://www.thordata.com/?ls=github&lk=pydoll)**: a residential proxy network built for serious web scraping and automation. With **190+ real residential and ISP locations**, fully encrypted connections, and infrastructure optimized for high-performance workflows, Thordata is an excellent choice for scaling your Pydoll automations.
|
|
34
|
+
|
|
35
|
+
**[Sign up through our link](https://www.thordata.com/?ls=github&lk=pydoll)** to support the project and get **1GB free** to get started.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<a href="https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc">
|
|
41
|
+
<img alt="CapSolver" src="public/images/capsolver.jpeg" />
|
|
42
|
+
</a>
|
|
43
|
+
|
|
44
|
+
Pydoll excels at behavioral evasion, but it doesn't solve captchas. That's where **[CapSolver](https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc)** comes in. An AI-powered service that handles reCAPTCHA, Cloudflare challenges, and more, seamlessly integrating with your automation workflows.
|
|
45
|
+
|
|
46
|
+
**[Register with our invite code](https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc)** and use code **PYDOLL** to get an extra **6% balance bonus**.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
27
50
|
### The Pydoll Philosophy
|
|
28
51
|
|
|
29
52
|
* **Stealth-by-Design:** Pydoll is built for evasion. Our [human-like interactions](https://pydoll.tech/docs/features/automation/human-interactions/) simulate real user clicks, typing, and scrolling to pass behavioral analysis, while granular [Browser Preferences](https://pydoll.tech/docs/features/configuration/browser-preferences/) control lets you patch your browser fingerprint.
|
|
@@ -906,9 +906,9 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
906
906
|
def _validate_ws_address(ws_address: str):
|
|
907
907
|
"""Validate WebSocket address."""
|
|
908
908
|
min_slashes = 4
|
|
909
|
-
if not ws_address.startswith('ws://'):
|
|
910
|
-
logger.error('Invalid WebSocket address: missing ws:// prefix')
|
|
911
|
-
raise InvalidWebSocketAddress('WebSocket address must start with ws://')
|
|
909
|
+
if not ws_address.startswith(('ws://', 'wss://')):
|
|
910
|
+
logger.error('Invalid WebSocket address: missing ws:// or wss:// prefix')
|
|
911
|
+
raise InvalidWebSocketAddress('WebSocket address must start with ws:// or wss://')
|
|
912
912
|
if len(ws_address.split('/')) < min_slashes:
|
|
913
913
|
logger.error('Invalid WebSocket address: not enough slashes')
|
|
914
914
|
raise InvalidWebSocketAddress(
|
|
@@ -34,7 +34,7 @@ from pydoll.commands import (
|
|
|
34
34
|
StorageCommands,
|
|
35
35
|
)
|
|
36
36
|
from pydoll.connection import ConnectionHandler
|
|
37
|
-
from pydoll.constants import By
|
|
37
|
+
from pydoll.constants import By, PageLoadState
|
|
38
38
|
from pydoll.elements.mixins import FindElementsMixin
|
|
39
39
|
from pydoll.exceptions import (
|
|
40
40
|
DownloadTimeout,
|
|
@@ -104,6 +104,8 @@ class Tab(FindElementsMixin):
|
|
|
104
104
|
like Cloudflare bypass.
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
|
+
_READY_STATE_ORDER = (PageLoadState.LOADING, PageLoadState.INTERACTIVE, PageLoadState.COMPLETE)
|
|
108
|
+
|
|
107
109
|
def __init__(
|
|
108
110
|
self,
|
|
109
111
|
browser: Browser,
|
|
@@ -231,6 +233,14 @@ class Tab(FindElementsMixin):
|
|
|
231
233
|
)
|
|
232
234
|
return response['result']['result']['value']
|
|
233
235
|
|
|
236
|
+
@property
|
|
237
|
+
async def title(self) -> str:
|
|
238
|
+
"""Get current page title."""
|
|
239
|
+
response: EvaluateResponse = await self._execute_command(
|
|
240
|
+
RuntimeCommands.evaluate('document.title')
|
|
241
|
+
)
|
|
242
|
+
return response['result']['result'].get('value', '')
|
|
243
|
+
|
|
234
244
|
async def enable_page_events(self):
|
|
235
245
|
"""Enable CDP Page domain events (load, navigation, dialogs, etc.)."""
|
|
236
246
|
logger.debug('Enabling Page events')
|
|
@@ -1409,17 +1419,28 @@ class Tab(FindElementsMixin):
|
|
|
1409
1419
|
"""
|
|
1410
1420
|
Wait for page to finish loading.
|
|
1411
1421
|
|
|
1422
|
+
Waits until ``document.readyState`` reaches **at least** the level
|
|
1423
|
+
configured in ``browser.options.page_load_state``. For example, when
|
|
1424
|
+
the target state is ``interactive``, both ``"interactive"`` and
|
|
1425
|
+
``"complete"`` satisfy the condition — this prevents an infinite
|
|
1426
|
+
polling loop when the page transitions past ``interactive`` before the
|
|
1427
|
+
first check runs.
|
|
1428
|
+
|
|
1412
1429
|
Raises:
|
|
1413
|
-
|
|
1430
|
+
WaitElementTimeout: If page doesn't load within *timeout* seconds.
|
|
1414
1431
|
"""
|
|
1432
|
+
target_state = self._browser.options.page_load_state.value
|
|
1433
|
+
target_index = self._READY_STATE_ORDER.index(target_state)
|
|
1415
1434
|
start_time = asyncio.get_event_loop().time()
|
|
1416
1435
|
logger.debug(f'Waiting for page load (timeout={timeout}s)')
|
|
1417
1436
|
while True:
|
|
1418
1437
|
response: EvaluateResponse = await self._execute_command(
|
|
1419
1438
|
RuntimeCommands.evaluate(expression='document.readyState')
|
|
1420
1439
|
)
|
|
1421
|
-
|
|
1422
|
-
|
|
1440
|
+
current_state = response['result']['result']['value']
|
|
1441
|
+
current_index = self._READY_STATE_ORDER.index(current_state)
|
|
1442
|
+
if current_index >= target_index:
|
|
1443
|
+
logger.debug(f'Page load state reached: {current_state} (target: {target_state})')
|
|
1423
1444
|
break
|
|
1424
1445
|
if asyncio.get_event_loop().time() - start_time > timeout:
|
|
1425
1446
|
raise WaitElementTimeout('Page load timed out')
|
|
@@ -13,6 +13,7 @@ class By(str, Enum):
|
|
|
13
13
|
class PageLoadState(str, Enum):
|
|
14
14
|
COMPLETE = 'complete'
|
|
15
15
|
INTERACTIVE = 'interactive'
|
|
16
|
+
LOADING = 'loading'
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class ScrollPosition(str, Enum):
|
|
@@ -436,6 +437,30 @@ new Promise((resolve) => {{
|
|
|
436
437
|
}
|
|
437
438
|
"""
|
|
438
439
|
|
|
440
|
+
CLEAR_INPUT = """
|
|
441
|
+
function() {
|
|
442
|
+
const el = this;
|
|
443
|
+
|
|
444
|
+
// Standard input/textarea
|
|
445
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') {
|
|
446
|
+
el.value = '';
|
|
447
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
448
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ContentEditable elements
|
|
453
|
+
if (el.isContentEditable) {
|
|
454
|
+
el.focus();
|
|
455
|
+
el.innerHTML = '';
|
|
456
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
"""
|
|
463
|
+
|
|
439
464
|
IS_EDITABLE = """
|
|
440
465
|
function() {
|
|
441
466
|
const el = this;
|
|
@@ -463,9 +463,9 @@ class FindElementsMixin:
|
|
|
463
463
|
)
|
|
464
464
|
response: list[str] = []
|
|
465
465
|
for query in query_response['result']['result']:
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
466
|
+
if not (query['name'].isdigit() and 'objectId' in query['value']):
|
|
467
|
+
continue
|
|
468
|
+
response.append(query['value']['objectId'])
|
|
469
469
|
|
|
470
470
|
elements = []
|
|
471
471
|
for object_id in response:
|
|
@@ -646,11 +646,11 @@ class FindElementsMixin:
|
|
|
646
646
|
async def _execute_command(
|
|
647
647
|
self, command: Command[T_CommandParams, T_CommandResponse]
|
|
648
648
|
) -> T_CommandResponse:
|
|
649
|
-
"""Execute CDP command via resolved handler (
|
|
649
|
+
"""Execute CDP command via resolved handler (10s timeout)."""
|
|
650
650
|
handler, session_id = self._resolve_routing()
|
|
651
651
|
if session_id:
|
|
652
652
|
command['sessionId'] = session_id
|
|
653
|
-
return await handler.execute_command(command, timeout=
|
|
653
|
+
return await handler.execute_command(command, timeout=10)
|
|
654
654
|
|
|
655
655
|
def _get_find_element_command(
|
|
656
656
|
self,
|
|
@@ -123,6 +123,11 @@ class WebElement(FindElementsMixin): # noqa: PLR0904
|
|
|
123
123
|
self._iframe_resolver = IFrameContextResolver(self)
|
|
124
124
|
return self._iframe_resolver
|
|
125
125
|
|
|
126
|
+
@property
|
|
127
|
+
def attributes(self) -> dict[str, str]:
|
|
128
|
+
"""Read-only copy of the element's cached attributes."""
|
|
129
|
+
return dict(self._attributes)
|
|
130
|
+
|
|
126
131
|
@property
|
|
127
132
|
def value(self) -> Optional[str]:
|
|
128
133
|
"""Element's value attribute (for form elements)."""
|
|
@@ -530,6 +535,25 @@ class WebElement(FindElementsMixin): # noqa: PLR0904
|
|
|
530
535
|
await asyncio.sleep(hold_time)
|
|
531
536
|
await self._connection_handler.execute_command(release_command)
|
|
532
537
|
|
|
538
|
+
async def clear(self):
|
|
539
|
+
"""
|
|
540
|
+
Clear the current value of the element.
|
|
541
|
+
|
|
542
|
+
Supports standard inputs, textareas, and contenteditable elements.
|
|
543
|
+
Dispatches ``input`` and ``change`` events so frameworks detect the update.
|
|
544
|
+
|
|
545
|
+
Raises:
|
|
546
|
+
ElementNotInteractable: If the element does not accept text input.
|
|
547
|
+
"""
|
|
548
|
+
logger.info('Clearing element value')
|
|
549
|
+
result = await self.execute_script(Scripts.CLEAR_INPUT, return_by_value=True)
|
|
550
|
+
success = result['result'].get('result', {}).get('value', False)
|
|
551
|
+
if not success:
|
|
552
|
+
logger.error('Element does not accept text input')
|
|
553
|
+
raise ElementNotInteractable('Element does not accept text input')
|
|
554
|
+
if self._attributes.get('tag_name', '').lower() in {'input', 'textarea'}:
|
|
555
|
+
self._attributes['value'] = ''
|
|
556
|
+
|
|
533
557
|
async def insert_text(self, text: str):
|
|
534
558
|
"""
|
|
535
559
|
Insert text into element using JavaScript.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pydoll-python"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.16.0"
|
|
4
4
|
description = "Pydoll is a library for automating chromium-based browsers without a WebDriver, offering realistic interactions."
|
|
5
5
|
authors = ["Thalison Fernandes <thalissfernandes99@gmail.com>"]
|
|
6
6
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/browser_options_manager.py
RENAMED
|
File without changes
|
{pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/browser/managers/browser_process_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pydoll_python-2.15.0 → pydoll_python-2.16.0}/pydoll/connection/managers/commands_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|