pydoll-python 2.9.3__tar.gz → 2.10.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.9.3 → pydoll_python-2.10.0}/PKG-INFO +22 -24
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/README.md +21 -23
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/tab.py +14 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/constants.py +88 -0
- pydoll_python-2.10.0/pydoll/interactions/__init__.py +3 -0
- pydoll_python-2.10.0/pydoll/interactions/scroll.py +121 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pyproject.toml +1 -1
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/LICENSE +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/chromium/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/chromium/base.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/chromium/chrome.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/chromium/edge.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/interfaces.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_options_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_process_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/proxy_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/temp_dir_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/options.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/requests/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/requests/request.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/requests/response.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/browser_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/dom_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/fetch_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/input_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/network_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/page_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/runtime_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/storage_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/commands/target_commands.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/connection/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/connection/connection_handler.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/connection/managers/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/connection/managers/commands_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/connection/managers/events_manager.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/elements/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/elements/mixins/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/elements/mixins/find_elements_mixin.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/elements/web_element.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/exceptions.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/base.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/browser/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/browser/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/browser/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/browser/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/debugger/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/dom/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/dom/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/dom/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/dom/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/emulation/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/fetch/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/fetch/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/fetch/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/fetch/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/input/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/input/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/input/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/input/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/io/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/network/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/network/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/network/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/network/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/page/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/page/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/page/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/page/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/runtime/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/runtime/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/runtime/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/runtime/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/security/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/storage/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/storage/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/storage/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/storage/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/target/__init__.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/target/events.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/target/methods.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/protocol/target/types.py +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/py.typed +0 -0
- {pydoll_python-2.9.3 → pydoll_python-2.10.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.10.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
|
|
@@ -52,37 +52,35 @@ Built from scratch with a different philosophy, Pydoll connects directly to the
|
|
|
52
52
|
|
|
53
53
|
We believe that powerful automation shouldn't require you to become an expert in configuration or constantly fight with bot protection systems. With Pydoll, you can focus on what really matters: your automation logic, not the underlying complexity or protection systems.
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
## 🌟 What makes Pydoll special?
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
- **Zero Webdrivers**: Say goodbye to webdriver compatibility issues
|
|
58
|
+
- **Human-like Interaction Engine**: Capable of passing behavioral CAPTCHAs like reCAPTCHA v3 or Turnstile, depending on IP reputation and interaction patterns
|
|
59
|
+
- **Asynchronous Performance**: For high-speed automation and multiple simultaneous tasks
|
|
60
|
+
- **Humanized Interactions**: Mimic real user behavior
|
|
61
|
+
- **Simplicity**: With Pydoll, you install and you're ready to automate.
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
## 🆕 What's New
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
### Human-Like Page Scrolling: Scroll Like a Real User!
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
* **Mouse Interaction:** Simulation of cursor paths using Bezier curves, variable speeds based on Fitts's Law principles, and randomized click offsets. Event sequences (`mousemove`, `mousedown`, `mouseup`, `click`) will be handled automatically.
|
|
65
|
-
* **Keyboard Input:** Character-by-character typing with randomized `Dwell` (key press duration) and `Flight` (time between keys) times. Optional simulation of typing errors and corrections.
|
|
66
|
-
* **Scroll Simulation:** Physics-based scrolling mimicking momentum and inertia.
|
|
67
|
-
* **Timing Variations:** Introduction of randomized delays ("cognitive time") before and after actions to avoid predictable automation patterns.
|
|
68
|
-
* **Comprehensive Documentation Overhaul:** A new series of in-depth technical guides ("Deep Dives") covering:
|
|
69
|
-
* **Network Fingerprinting:** Analysis of TCP/IP, TLS/JA3, and HTTP/2 characteristics. Includes practical examples like **building custom HTTP and SOCKS5 proxy servers** and discussing proxy detection techniques.
|
|
70
|
-
* **Browser Fingerprinting:** Detailed exploration of `navigator` properties, Client Hints, Canvas/WebGL rendering, font detection, and screen attributes.
|
|
71
|
-
* **Behavioral Fingerprinting:** Analysis of mouse dynamics, keystroke patterns (including bigram timing), scroll physics, and event sequencing.
|
|
72
|
-
* **Advanced Browser Control:** Extensive documentation on using `browser_preferences` to modify hundreds of internal Chromium settings for granular control over performance, privacy, and fingerprinting.
|
|
73
|
-
* **Practical Examples:** Including configurations for **Docker environments** and common evasion scenarios.
|
|
67
|
+
Now you can control page scrolling with smooth animations and automatic completion waiting:
|
|
74
68
|
|
|
75
|
-
|
|
69
|
+
```python
|
|
70
|
+
from pydoll.constants import ScrollPosition
|
|
76
71
|
|
|
77
|
-
|
|
72
|
+
# Scroll down with smooth animation (waits for completion)
|
|
73
|
+
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
# Navigate to specific positions
|
|
76
|
+
await tab.scroll.to_bottom(smooth=True)
|
|
77
|
+
await tab.scroll.to_top(smooth=True)
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
79
|
+
# Instant scroll for speed when realism isn't critical
|
|
80
|
+
await tab.scroll.by(ScrollPosition.UP, 300, smooth=False)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Unlike `execute_script("window.scrollBy(...)")` which returns immediately, the scroll API uses CDP's `awaitPromise` to wait for the browser's `scrollend` event, ensuring your next actions only execute after scrolling completely finishes. Perfect for taking screenshots, loading lazy content, or creating realistic reading patterns.
|
|
86
84
|
|
|
87
85
|
## 📦 Installation
|
|
88
86
|
|
|
@@ -32,37 +32,35 @@ Built from scratch with a different philosophy, Pydoll connects directly to the
|
|
|
32
32
|
|
|
33
33
|
We believe that powerful automation shouldn't require you to become an expert in configuration or constantly fight with bot protection systems. With Pydoll, you can focus on what really matters: your automation logic, not the underlying complexity or protection systems.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
## 🌟 What makes Pydoll special?
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
- **Zero Webdrivers**: Say goodbye to webdriver compatibility issues
|
|
38
|
+
- **Human-like Interaction Engine**: Capable of passing behavioral CAPTCHAs like reCAPTCHA v3 or Turnstile, depending on IP reputation and interaction patterns
|
|
39
|
+
- **Asynchronous Performance**: For high-speed automation and multiple simultaneous tasks
|
|
40
|
+
- **Humanized Interactions**: Mimic real user behavior
|
|
41
|
+
- **Simplicity**: With Pydoll, you install and you're ready to automate.
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
## 🆕 What's New
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
### Human-Like Page Scrolling: Scroll Like a Real User!
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
* **Mouse Interaction:** Simulation of cursor paths using Bezier curves, variable speeds based on Fitts's Law principles, and randomized click offsets. Event sequences (`mousemove`, `mousedown`, `mouseup`, `click`) will be handled automatically.
|
|
45
|
-
* **Keyboard Input:** Character-by-character typing with randomized `Dwell` (key press duration) and `Flight` (time between keys) times. Optional simulation of typing errors and corrections.
|
|
46
|
-
* **Scroll Simulation:** Physics-based scrolling mimicking momentum and inertia.
|
|
47
|
-
* **Timing Variations:** Introduction of randomized delays ("cognitive time") before and after actions to avoid predictable automation patterns.
|
|
48
|
-
* **Comprehensive Documentation Overhaul:** A new series of in-depth technical guides ("Deep Dives") covering:
|
|
49
|
-
* **Network Fingerprinting:** Analysis of TCP/IP, TLS/JA3, and HTTP/2 characteristics. Includes practical examples like **building custom HTTP and SOCKS5 proxy servers** and discussing proxy detection techniques.
|
|
50
|
-
* **Browser Fingerprinting:** Detailed exploration of `navigator` properties, Client Hints, Canvas/WebGL rendering, font detection, and screen attributes.
|
|
51
|
-
* **Behavioral Fingerprinting:** Analysis of mouse dynamics, keystroke patterns (including bigram timing), scroll physics, and event sequencing.
|
|
52
|
-
* **Advanced Browser Control:** Extensive documentation on using `browser_preferences` to modify hundreds of internal Chromium settings for granular control over performance, privacy, and fingerprinting.
|
|
53
|
-
* **Practical Examples:** Including configurations for **Docker environments** and common evasion scenarios.
|
|
47
|
+
Now you can control page scrolling with smooth animations and automatic completion waiting:
|
|
54
48
|
|
|
55
|
-
|
|
49
|
+
```python
|
|
50
|
+
from pydoll.constants import ScrollPosition
|
|
56
51
|
|
|
57
|
-
|
|
52
|
+
# Scroll down with smooth animation (waits for completion)
|
|
53
|
+
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
# Navigate to specific positions
|
|
56
|
+
await tab.scroll.to_bottom(smooth=True)
|
|
57
|
+
await tab.scroll.to_top(smooth=True)
|
|
60
58
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
# Instant scroll for speed when realism isn't critical
|
|
60
|
+
await tab.scroll.by(ScrollPosition.UP, 300, smooth=False)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Unlike `execute_script("window.scrollBy(...)")` which returns immediately, the scroll API uses CDP's `awaitPromise` to wait for the browser's `scrollend` event, ensuring your next actions only execute after scrolling completely finishes. Perfect for taking screenshots, loading lazy content, or creating realistic reading patterns.
|
|
66
64
|
|
|
67
65
|
## 📦 Installation
|
|
68
66
|
|
|
@@ -50,6 +50,7 @@ from pydoll.exceptions import (
|
|
|
50
50
|
TopLevelTargetRequired,
|
|
51
51
|
WaitElementTimeout,
|
|
52
52
|
)
|
|
53
|
+
from pydoll.interactions.scroll import ScrollAPI
|
|
53
54
|
from pydoll.protocol.browser.types import DownloadBehavior, DownloadProgressState
|
|
54
55
|
from pydoll.protocol.page.events import PageEvent
|
|
55
56
|
from pydoll.protocol.page.types import ScreenshotFormat
|
|
@@ -131,6 +132,7 @@ class Tab(FindElementsMixin):
|
|
|
131
132
|
self._intercept_file_chooser_dialog_enabled = False
|
|
132
133
|
self._cloudflare_captcha_callback_id: Optional[int] = None
|
|
133
134
|
self._request: Optional[Request] = None
|
|
135
|
+
self._scroll: Optional[ScrollAPI] = None
|
|
134
136
|
logger.debug(
|
|
135
137
|
(
|
|
136
138
|
f'Tab initialized: target_id={self._target_id}, '
|
|
@@ -176,6 +178,18 @@ class Tab(FindElementsMixin):
|
|
|
176
178
|
self._request = Request(self)
|
|
177
179
|
return self._request
|
|
178
180
|
|
|
181
|
+
@property
|
|
182
|
+
def scroll(self) -> ScrollAPI:
|
|
183
|
+
"""
|
|
184
|
+
Get the scroll API for controlling page scroll behavior.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
ScrollAPI: An instance of the ScrollAPI class for scroll operations.
|
|
188
|
+
"""
|
|
189
|
+
if self._scroll is None:
|
|
190
|
+
self._scroll = ScrollAPI(self)
|
|
191
|
+
return self._scroll
|
|
192
|
+
|
|
179
193
|
@property
|
|
180
194
|
def intercept_file_chooser_dialog_enabled(self) -> bool:
|
|
181
195
|
"""Whether file chooser dialog interception is active."""
|
|
@@ -15,6 +15,13 @@ class PageLoadState(str, Enum):
|
|
|
15
15
|
INTERACTIVE = 'interactive'
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
class ScrollPosition(str, Enum):
|
|
19
|
+
UP = 'up'
|
|
20
|
+
DOWN = 'down'
|
|
21
|
+
LEFT = 'left'
|
|
22
|
+
RIGHT = 'right'
|
|
23
|
+
|
|
24
|
+
|
|
18
25
|
class Scripts:
|
|
19
26
|
ELEMENT_VISIBLE = """
|
|
20
27
|
function() {
|
|
@@ -268,6 +275,87 @@ class Scripts:
|
|
|
268
275
|
}})();
|
|
269
276
|
"""
|
|
270
277
|
|
|
278
|
+
SCROLL_BY = """
|
|
279
|
+
new Promise((resolve) => {{
|
|
280
|
+
const behavior = '{behavior}';
|
|
281
|
+
if (behavior === 'auto') {{
|
|
282
|
+
window.scrollBy({{
|
|
283
|
+
{axis}: {distance},
|
|
284
|
+
behavior: 'auto'
|
|
285
|
+
}});
|
|
286
|
+
resolve();
|
|
287
|
+
}} else {{
|
|
288
|
+
const onScrollEnd = () => {{
|
|
289
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
290
|
+
resolve();
|
|
291
|
+
}};
|
|
292
|
+
window.addEventListener('scrollend', onScrollEnd);
|
|
293
|
+
window.scrollBy({{
|
|
294
|
+
{axis}: {distance},
|
|
295
|
+
behavior: 'smooth'
|
|
296
|
+
}});
|
|
297
|
+
setTimeout(() => {{
|
|
298
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
299
|
+
resolve();
|
|
300
|
+
}}, 2000);
|
|
301
|
+
}}
|
|
302
|
+
}});
|
|
303
|
+
"""
|
|
304
|
+
|
|
305
|
+
SCROLL_TO_TOP = """
|
|
306
|
+
new Promise((resolve) => {{
|
|
307
|
+
const behavior = '{behavior}';
|
|
308
|
+
if (behavior === 'auto') {{
|
|
309
|
+
window.scrollTo({{
|
|
310
|
+
top: 0,
|
|
311
|
+
behavior: 'auto'
|
|
312
|
+
}});
|
|
313
|
+
resolve();
|
|
314
|
+
}} else {{
|
|
315
|
+
const onScrollEnd = () => {{
|
|
316
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
317
|
+
resolve();
|
|
318
|
+
}};
|
|
319
|
+
window.addEventListener('scrollend', onScrollEnd);
|
|
320
|
+
window.scrollTo({{
|
|
321
|
+
top: 0,
|
|
322
|
+
behavior: 'smooth'
|
|
323
|
+
}});
|
|
324
|
+
setTimeout(() => {{
|
|
325
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
326
|
+
resolve();
|
|
327
|
+
}}, 2000);
|
|
328
|
+
}}
|
|
329
|
+
}});
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
SCROLL_TO_BOTTOM = """
|
|
333
|
+
new Promise((resolve) => {{
|
|
334
|
+
const behavior = '{behavior}';
|
|
335
|
+
if (behavior === 'auto') {{
|
|
336
|
+
window.scrollTo({{
|
|
337
|
+
top: document.body.scrollHeight,
|
|
338
|
+
behavior: 'auto'
|
|
339
|
+
}});
|
|
340
|
+
resolve();
|
|
341
|
+
}} else {{
|
|
342
|
+
const onScrollEnd = () => {{
|
|
343
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
344
|
+
resolve();
|
|
345
|
+
}};
|
|
346
|
+
window.addEventListener('scrollend', onScrollEnd);
|
|
347
|
+
window.scrollTo({{
|
|
348
|
+
top: document.body.scrollHeight,
|
|
349
|
+
behavior: 'smooth'
|
|
350
|
+
}});
|
|
351
|
+
setTimeout(() => {{
|
|
352
|
+
window.removeEventListener('scrollend', onScrollEnd);
|
|
353
|
+
resolve();
|
|
354
|
+
}}, 2000);
|
|
355
|
+
}}
|
|
356
|
+
}});
|
|
357
|
+
"""
|
|
358
|
+
|
|
271
359
|
|
|
272
360
|
class Key(tuple[str, int], Enum):
|
|
273
361
|
BACKSPACE = ('Backspace', 8)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from pydoll.commands import RuntimeCommands
|
|
6
|
+
from pydoll.constants import Scripts, ScrollPosition
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from pydoll.browser.tab import Tab
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ScrollAPI:
|
|
13
|
+
"""
|
|
14
|
+
API for controlling page scroll behavior.
|
|
15
|
+
|
|
16
|
+
Provides methods for scrolling the page in different directions,
|
|
17
|
+
to specific positions, or by relative distances.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, tab: Tab):
|
|
21
|
+
"""
|
|
22
|
+
Initialize the ScrollAPI with a tab instance.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
tab: Tab instance to execute scroll commands on.
|
|
26
|
+
"""
|
|
27
|
+
self._tab = tab
|
|
28
|
+
|
|
29
|
+
async def by(
|
|
30
|
+
self,
|
|
31
|
+
position: ScrollPosition,
|
|
32
|
+
distance: int | float,
|
|
33
|
+
smooth: bool = True,
|
|
34
|
+
):
|
|
35
|
+
"""
|
|
36
|
+
Scroll the page by a relative distance in the specified direction.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
position: Direction to scroll (UP, DOWN, LEFT, RIGHT).
|
|
40
|
+
distance: Number of pixels to scroll.
|
|
41
|
+
smooth: Use smooth scrolling animation if True, instant if False.
|
|
42
|
+
"""
|
|
43
|
+
axis, scroll_distance = self._get_axis_and_distance(position, distance)
|
|
44
|
+
behavior = self._get_behavior(smooth)
|
|
45
|
+
|
|
46
|
+
script = Scripts.SCROLL_BY.format(
|
|
47
|
+
axis=axis,
|
|
48
|
+
distance=scroll_distance,
|
|
49
|
+
behavior=behavior,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
await self._execute_script_await_promise(script)
|
|
53
|
+
|
|
54
|
+
async def to_top(self, smooth: bool = True):
|
|
55
|
+
"""
|
|
56
|
+
Scroll to the top of the page (Y=0).
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
smooth: Use smooth scrolling animation if True, instant if False.
|
|
60
|
+
"""
|
|
61
|
+
behavior = self._get_behavior(smooth)
|
|
62
|
+
script = Scripts.SCROLL_TO_TOP.format(behavior=behavior)
|
|
63
|
+
await self._execute_script_await_promise(script)
|
|
64
|
+
|
|
65
|
+
async def to_bottom(self, smooth: bool = True):
|
|
66
|
+
"""
|
|
67
|
+
Scroll to the bottom of the page (Y=document.body.scrollHeight).
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
smooth: Use smooth scrolling animation if True, instant if False.
|
|
71
|
+
"""
|
|
72
|
+
behavior = self._get_behavior(smooth)
|
|
73
|
+
script = Scripts.SCROLL_TO_BOTTOM.format(behavior=behavior)
|
|
74
|
+
await self._execute_script_await_promise(script)
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _get_axis_and_distance(
|
|
78
|
+
position: ScrollPosition, distance: int | float
|
|
79
|
+
) -> tuple[str, int | float]:
|
|
80
|
+
"""
|
|
81
|
+
Convert scroll position to axis and signed distance.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
position: Direction to scroll.
|
|
85
|
+
distance: Absolute distance to scroll.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Tuple of (axis, signed_distance) where axis is 'left' or 'top'
|
|
89
|
+
and signed_distance is positive or negative based on direction.
|
|
90
|
+
"""
|
|
91
|
+
if position in {ScrollPosition.UP, ScrollPosition.DOWN}:
|
|
92
|
+
axis = 'top'
|
|
93
|
+
scroll_distance = -distance if position == ScrollPosition.UP else distance
|
|
94
|
+
return axis, scroll_distance * 10
|
|
95
|
+
|
|
96
|
+
axis = 'left'
|
|
97
|
+
scroll_distance = -distance if position == ScrollPosition.LEFT else distance
|
|
98
|
+
return axis, scroll_distance * 10
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def _get_behavior(smooth: bool) -> str:
|
|
102
|
+
"""
|
|
103
|
+
Convert smooth boolean to CSS scroll behavior value.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
smooth: Whether to use smooth scrolling.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
'smooth' if smooth is True, 'auto' otherwise.
|
|
110
|
+
"""
|
|
111
|
+
return 'smooth' if smooth else 'auto'
|
|
112
|
+
|
|
113
|
+
async def _execute_script_await_promise(self, script: str):
|
|
114
|
+
"""
|
|
115
|
+
Execute JavaScript and await promise resolution.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
script: JavaScript code that returns a Promise.
|
|
119
|
+
"""
|
|
120
|
+
command = RuntimeCommands.evaluate(expression=script, await_promise=True)
|
|
121
|
+
return await self._tab._execute_command(command)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pydoll-python"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.10.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
|
|
File without changes
|
{pydoll_python-2.9.3 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_options_manager.py
RENAMED
|
File without changes
|
{pydoll_python-2.9.3 → pydoll_python-2.10.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
|
|
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
|