pydoll-python 2.9.2__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.2 → pydoll_python-2.10.0}/PKG-INFO +24 -7
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/README.md +23 -6
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/chromium/base.py +42 -27
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/chromium/chrome.py +6 -2
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/chromium/edge.py +6 -2
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_options_manager.py +7 -2
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/proxy_manager.py +5 -2
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/requests/request.py +19 -17
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/requests/response.py +8 -11
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/tab.py +74 -34
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/browser_commands.py +42 -34
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/dom_commands.py +69 -58
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/fetch_commands.py +30 -24
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/input_commands.py +33 -27
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/network_commands.py +47 -41
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/page_commands.py +65 -57
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/runtime_commands.py +26 -20
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/storage_commands.py +46 -42
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/target_commands.py +23 -17
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/connection/connection_handler.py +11 -12
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/connection/managers/commands_manager.py +5 -1
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/connection/managers/events_manager.py +12 -8
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/constants.py +88 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/elements/mixins/find_elements_mixin.py +37 -29
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/elements/web_element.py +80 -25
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/exceptions.py +12 -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.2 → pydoll_python-2.10.0}/pyproject.toml +1 -1
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/LICENSE +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/chromium/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/interfaces.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_process_manager.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/temp_dir_manager.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/options.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/requests/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/commands/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/connection/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/connection/managers/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/elements/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/elements/mixins/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/base.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/browser/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/browser/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/browser/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/browser/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/debugger/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/dom/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/dom/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/dom/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/dom/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/emulation/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/fetch/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/fetch/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/fetch/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/fetch/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/input/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/input/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/input/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/input/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/io/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/network/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/network/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/network/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/network/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/page/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/page/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/page/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/page/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/runtime/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/runtime/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/runtime/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/runtime/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/security/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/storage/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/storage/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/storage/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/storage/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/target/__init__.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/target/events.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/target/methods.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/protocol/target/types.py +0 -0
- {pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/py.typed +0 -0
- {pydoll_python-2.9.2 → 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
|
|
@@ -19,7 +19,7 @@ Requires-Dist: websockets (>=14,<15)
|
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
22
|
-
<img src="https://github.com/user-attachments/assets/
|
|
22
|
+
<img src="https://github.com/user-attachments/assets/2c380638-b04a-4b04-b1c8-2958e4237a94" alt="Pydoll Logo" /> <br>
|
|
23
23
|
</p>
|
|
24
24
|
<h1 align="center">Pydoll: scraping, the easier way</h1>
|
|
25
25
|
|
|
@@ -52,11 +52,6 @@ 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
|
-
<div>
|
|
56
|
-
<h4>Be a good human. Give it a star ⭐</h4>
|
|
57
|
-
No stars, no bugs fixed. Just kidding (maybe)
|
|
58
|
-
</div>
|
|
59
|
-
|
|
60
55
|
## 🌟 What makes Pydoll special?
|
|
61
56
|
|
|
62
57
|
- **Zero Webdrivers**: Say goodbye to webdriver compatibility issues
|
|
@@ -65,6 +60,28 @@ We believe that powerful automation shouldn't require you to become an expert in
|
|
|
65
60
|
- **Humanized Interactions**: Mimic real user behavior
|
|
66
61
|
- **Simplicity**: With Pydoll, you install and you're ready to automate.
|
|
67
62
|
|
|
63
|
+
## 🆕 What's New
|
|
64
|
+
|
|
65
|
+
### Human-Like Page Scrolling: Scroll Like a Real User!
|
|
66
|
+
|
|
67
|
+
Now you can control page scrolling with smooth animations and automatic completion waiting:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from pydoll.constants import ScrollPosition
|
|
71
|
+
|
|
72
|
+
# Scroll down with smooth animation (waits for completion)
|
|
73
|
+
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
|
|
74
|
+
|
|
75
|
+
# Navigate to specific positions
|
|
76
|
+
await tab.scroll.to_bottom(smooth=True)
|
|
77
|
+
await tab.scroll.to_top(smooth=True)
|
|
78
|
+
|
|
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.
|
|
84
|
+
|
|
68
85
|
## 📦 Installation
|
|
69
86
|
|
|
70
87
|
```bash
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://github.com/user-attachments/assets/
|
|
2
|
+
<img src="https://github.com/user-attachments/assets/2c380638-b04a-4b04-b1c8-2958e4237a94" alt="Pydoll Logo" /> <br>
|
|
3
3
|
</p>
|
|
4
4
|
<h1 align="center">Pydoll: scraping, the easier way</h1>
|
|
5
5
|
|
|
@@ -32,11 +32,6 @@ 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
|
-
<div>
|
|
36
|
-
<h4>Be a good human. Give it a star ⭐</h4>
|
|
37
|
-
No stars, no bugs fixed. Just kidding (maybe)
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
35
|
## 🌟 What makes Pydoll special?
|
|
41
36
|
|
|
42
37
|
- **Zero Webdrivers**: Say goodbye to webdriver compatibility issues
|
|
@@ -45,6 +40,28 @@ We believe that powerful automation shouldn't require you to become an expert in
|
|
|
45
40
|
- **Humanized Interactions**: Mimic real user behavior
|
|
46
41
|
- **Simplicity**: With Pydoll, you install and you're ready to automate.
|
|
47
42
|
|
|
43
|
+
## 🆕 What's New
|
|
44
|
+
|
|
45
|
+
### Human-Like Page Scrolling: Scroll Like a Real User!
|
|
46
|
+
|
|
47
|
+
Now you can control page scrolling with smooth animations and automatic completion waiting:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from pydoll.constants import ScrollPosition
|
|
51
|
+
|
|
52
|
+
# Scroll down with smooth animation (waits for completion)
|
|
53
|
+
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
|
|
54
|
+
|
|
55
|
+
# Navigate to specific positions
|
|
56
|
+
await tab.scroll.to_bottom(smooth=True)
|
|
57
|
+
await tab.scroll.to_top(smooth=True)
|
|
58
|
+
|
|
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.
|
|
64
|
+
|
|
48
65
|
## 📦 Installation
|
|
49
66
|
|
|
50
67
|
```bash
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import json
|
|
3
5
|
import logging
|
|
@@ -8,11 +10,9 @@ from abc import ABC, abstractmethod
|
|
|
8
10
|
from contextlib import suppress
|
|
9
11
|
from functools import partial
|
|
10
12
|
from random import randint
|
|
11
|
-
from
|
|
12
|
-
from typing import Any, Awaitable, Callable, Optional, overload
|
|
13
|
+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Optional, overload
|
|
13
14
|
from urllib.parse import urlsplit, urlunsplit
|
|
14
15
|
|
|
15
|
-
from pydoll.browser.interfaces import BrowserOptionsManager
|
|
16
16
|
from pydoll.browser.managers import (
|
|
17
17
|
BrowserProcessManager,
|
|
18
18
|
ProxyManager,
|
|
@@ -35,30 +35,38 @@ from pydoll.exceptions import (
|
|
|
35
35
|
MissingTargetOrWebSocket,
|
|
36
36
|
NoValidTabFound,
|
|
37
37
|
)
|
|
38
|
-
from pydoll.protocol.
|
|
39
|
-
from pydoll.protocol.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
from pydoll.
|
|
46
|
-
from pydoll.protocol.
|
|
47
|
-
from pydoll.protocol.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
from pydoll.protocol.
|
|
55
|
-
from pydoll.protocol.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
38
|
+
from pydoll.protocol.browser.types import DownloadBehavior
|
|
39
|
+
from pydoll.protocol.fetch.events import FetchEvent
|
|
40
|
+
from pydoll.protocol.fetch.types import AuthChallengeResponseType
|
|
41
|
+
|
|
42
|
+
if TYPE_CHECKING:
|
|
43
|
+
from tempfile import TemporaryDirectory
|
|
44
|
+
|
|
45
|
+
from pydoll.browser.interfaces import BrowserOptionsManager
|
|
46
|
+
from pydoll.protocol.base import Command, Response, T_CommandParams, T_CommandResponse
|
|
47
|
+
from pydoll.protocol.browser.methods import (
|
|
48
|
+
GetVersionResponse,
|
|
49
|
+
GetVersionResult,
|
|
50
|
+
GetWindowForTargetResponse,
|
|
51
|
+
)
|
|
52
|
+
from pydoll.protocol.browser.types import Bounds, PermissionType
|
|
53
|
+
from pydoll.protocol.fetch.events import RequestPausedEvent
|
|
54
|
+
from pydoll.protocol.fetch.types import HeaderEntry
|
|
55
|
+
from pydoll.protocol.network.types import (
|
|
56
|
+
Cookie,
|
|
57
|
+
CookieParam,
|
|
58
|
+
ErrorReason,
|
|
59
|
+
RequestMethod,
|
|
60
|
+
ResourceType,
|
|
61
|
+
)
|
|
62
|
+
from pydoll.protocol.storage.methods import GetCookiesResponse
|
|
63
|
+
from pydoll.protocol.target.methods import (
|
|
64
|
+
CreateBrowserContextResponse,
|
|
65
|
+
CreateTargetResponse,
|
|
66
|
+
GetBrowserContextsResponse,
|
|
67
|
+
GetTargetsResponse,
|
|
68
|
+
)
|
|
69
|
+
from pydoll.protocol.target.types import TargetInfo
|
|
62
70
|
|
|
63
71
|
logger = logging.getLogger(__name__)
|
|
64
72
|
|
|
@@ -209,6 +217,13 @@ class Browser(ABC): # noqa: PLR0904
|
|
|
209
217
|
await self._connection_handler.close()
|
|
210
218
|
logger.info('Browser process stopped and resources cleaned up')
|
|
211
219
|
|
|
220
|
+
async def close(self):
|
|
221
|
+
"""
|
|
222
|
+
Closes the WebSocket connection and releases resources.
|
|
223
|
+
"""
|
|
224
|
+
logger.info('Closing browser WebSocket connection')
|
|
225
|
+
await self._connection_handler.close()
|
|
226
|
+
|
|
212
227
|
async def create_browser_context(
|
|
213
228
|
self, proxy_server: Optional[str] = None, proxy_bypass_list: Optional[str] = None
|
|
214
229
|
) -> str:
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import platform
|
|
3
|
-
from typing import Optional
|
|
5
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
6
|
|
|
5
7
|
from pydoll.browser.chromium.base import Browser
|
|
6
8
|
from pydoll.browser.managers import ChromiumOptionsManager
|
|
7
|
-
from pydoll.browser.options import ChromiumOptions
|
|
8
9
|
from pydoll.exceptions import UnsupportedOS
|
|
9
10
|
from pydoll.utils import validate_browser_paths
|
|
10
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pydoll.browser.options import ChromiumOptions
|
|
14
|
+
|
|
11
15
|
logger = logging.getLogger(__name__)
|
|
12
16
|
|
|
13
17
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
4
|
import platform
|
|
3
|
-
from typing import Optional
|
|
5
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
6
|
|
|
5
7
|
from pydoll.browser.chromium.base import Browser
|
|
6
8
|
from pydoll.browser.managers import ChromiumOptionsManager
|
|
7
|
-
from pydoll.browser.options import Options
|
|
8
9
|
from pydoll.exceptions import UnsupportedOS
|
|
9
10
|
from pydoll.utils import validate_browser_paths
|
|
10
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pydoll.browser.options import Options
|
|
14
|
+
|
|
11
15
|
logger = logging.getLogger(__name__)
|
|
12
16
|
|
|
13
17
|
|
{pydoll_python-2.9.2 → pydoll_python-2.10.0}/pydoll/browser/managers/browser_options_manager.py
RENAMED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
|
-
from typing import Optional
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
5
|
|
|
4
|
-
from pydoll.browser.interfaces import BrowserOptionsManager
|
|
6
|
+
from pydoll.browser.interfaces import BrowserOptionsManager
|
|
5
7
|
from pydoll.browser.options import ChromiumOptions
|
|
6
8
|
from pydoll.exceptions import InvalidOptionsObject
|
|
7
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pydoll.browser.options import Options
|
|
12
|
+
|
|
8
13
|
logger = logging.getLogger(__name__)
|
|
9
14
|
|
|
10
15
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import logging
|
|
2
|
-
from typing import Optional
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pydoll.browser.options import Options
|
|
5
8
|
|
|
6
9
|
logger = logging.getLogger(__name__)
|
|
7
10
|
|
|
@@ -3,16 +3,19 @@ This module provides a Request class that mimics the behavior of requests.
|
|
|
3
3
|
It allows making HTTP requests using the browser's fetch API.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
6
8
|
import json as jsonlib
|
|
7
9
|
import logging
|
|
8
10
|
from typing import TYPE_CHECKING, Any, Callable, Optional, Union, cast
|
|
9
11
|
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
|
|
10
12
|
|
|
11
|
-
from pydoll.browser.requests.response import
|
|
13
|
+
from pydoll.browser.requests.response import Response
|
|
12
14
|
from pydoll.commands.runtime_commands import RuntimeCommands
|
|
13
15
|
from pydoll.constants import Scripts
|
|
16
|
+
from pydoll.exceptions import HTTPError
|
|
14
17
|
from pydoll.protocol.fetch.types import HeaderEntry
|
|
15
|
-
from pydoll.protocol.network.events import NetworkEvent
|
|
18
|
+
from pydoll.protocol.network.events import NetworkEvent, ResponseReceivedExtraInfoEventParams
|
|
16
19
|
from pydoll.protocol.network.types import CookieParam
|
|
17
20
|
|
|
18
21
|
logger = logging.getLogger(__name__)
|
|
@@ -27,7 +30,6 @@ if TYPE_CHECKING:
|
|
|
27
30
|
ResponseReceivedEvent,
|
|
28
31
|
ResponseReceivedEventParams,
|
|
29
32
|
ResponseReceivedExtraInfoEvent,
|
|
30
|
-
ResponseReceivedExtraInfoEventParams,
|
|
31
33
|
)
|
|
32
34
|
from pydoll.protocol.runtime.methods import EvaluateResponse
|
|
33
35
|
|
|
@@ -71,7 +73,7 @@ class Request:
|
|
|
71
73
|
- Cookies are managed automatically by the browser
|
|
72
74
|
"""
|
|
73
75
|
|
|
74
|
-
def __init__(self, tab:
|
|
76
|
+
def __init__(self, tab: Tab):
|
|
75
77
|
"""Initialize a new Request instance bound to a browser tab.
|
|
76
78
|
|
|
77
79
|
Args:
|
|
@@ -81,8 +83,8 @@ class Request:
|
|
|
81
83
|
"""
|
|
82
84
|
self.tab = tab
|
|
83
85
|
self._network_events_enabled = False
|
|
84
|
-
self._requests_sent: list[
|
|
85
|
-
self._requests_received: list[
|
|
86
|
+
self._requests_sent: list[RequestSentEvent] = []
|
|
87
|
+
self._requests_received: list[RequestReceivedEvent] = []
|
|
86
88
|
logger.debug('Request helper initialized for tab')
|
|
87
89
|
|
|
88
90
|
async def request(
|
|
@@ -334,7 +336,7 @@ class Request:
|
|
|
334
336
|
options['body'] = data
|
|
335
337
|
logger.debug('Request data set as raw payload')
|
|
336
338
|
|
|
337
|
-
async def _execute_fetch_request(self, url: str, options: dict[str, Any]) ->
|
|
339
|
+
async def _execute_fetch_request(self, url: str, options: dict[str, Any]) -> EvaluateResponse:
|
|
338
340
|
"""Execute the fetch request using browser's runtime."""
|
|
339
341
|
script = Scripts.MAKE_REQUEST.format(url=jsonlib.dumps(url), options=jsonlib.dumps(options))
|
|
340
342
|
await self._register_callbacks()
|
|
@@ -350,7 +352,7 @@ class Request:
|
|
|
350
352
|
|
|
351
353
|
@staticmethod
|
|
352
354
|
def _build_response(
|
|
353
|
-
result:
|
|
355
|
+
result: EvaluateResponse,
|
|
354
356
|
response_headers: list[HeaderEntry],
|
|
355
357
|
request_headers: list[HeaderEntry],
|
|
356
358
|
cookies: list[CookieParam],
|
|
@@ -385,11 +387,11 @@ class Request:
|
|
|
385
387
|
logger.debug('Network events enabled on tab for request capture')
|
|
386
388
|
|
|
387
389
|
def append_received_request(event: dict) -> None:
|
|
388
|
-
self._requests_received.append(cast(
|
|
390
|
+
self._requests_received.append(cast(RequestReceivedEvent, event))
|
|
389
391
|
logger.debug(f'Appended received request: event={event}')
|
|
390
392
|
|
|
391
393
|
def append_sent_request(event: dict) -> None:
|
|
392
|
-
self._requests_sent.append(cast(
|
|
394
|
+
self._requests_sent.append(cast(RequestSentEvent, event))
|
|
393
395
|
logger.debug(f'Appended sent request: event={event}')
|
|
394
396
|
|
|
395
397
|
await self.tab.on(
|
|
@@ -450,7 +452,7 @@ class Request:
|
|
|
450
452
|
|
|
451
453
|
@staticmethod
|
|
452
454
|
def _extract_headers_from_events(
|
|
453
|
-
events: Union[list[
|
|
455
|
+
events: Union[list[RequestSentEvent], list[RequestReceivedEvent]],
|
|
454
456
|
event_extractors: dict[str, Callable[[Any], list[HeaderEntry]]],
|
|
455
457
|
) -> list[HeaderEntry]:
|
|
456
458
|
"""Extract headers from network events using appropriate extractors.
|
|
@@ -488,7 +490,7 @@ class Request:
|
|
|
488
490
|
return headers
|
|
489
491
|
|
|
490
492
|
def _extract_request_sent_headers(
|
|
491
|
-
self, params:
|
|
493
|
+
self, params: RequestWillBeSentEventParams
|
|
492
494
|
) -> list[HeaderEntry]:
|
|
493
495
|
"""Extract headers from main request event.
|
|
494
496
|
|
|
@@ -503,7 +505,7 @@ class Request:
|
|
|
503
505
|
return self._convert_dict_to_header_entries(request.get('headers', {}))
|
|
504
506
|
|
|
505
507
|
def _extract_request_sent_extra_info_headers(
|
|
506
|
-
self, params:
|
|
508
|
+
self, params: RequestWillBeSentExtraInfoEventParams
|
|
507
509
|
) -> list[HeaderEntry]:
|
|
508
510
|
"""Extract headers from extra request info event.
|
|
509
511
|
|
|
@@ -520,7 +522,7 @@ class Request:
|
|
|
520
522
|
return self._convert_dict_to_header_entries(params.get('headers', {}))
|
|
521
523
|
|
|
522
524
|
def _extract_response_received_headers(
|
|
523
|
-
self, params:
|
|
525
|
+
self, params: ResponseReceivedEventParams
|
|
524
526
|
) -> list[HeaderEntry]:
|
|
525
527
|
"""Extract headers from main response event.
|
|
526
528
|
|
|
@@ -535,7 +537,7 @@ class Request:
|
|
|
535
537
|
return self._convert_dict_to_header_entries(response.get('headers', {}))
|
|
536
538
|
|
|
537
539
|
def _extract_response_received_extra_info_headers(
|
|
538
|
-
self, params:
|
|
540
|
+
self, params: ResponseReceivedExtraInfoEventParams
|
|
539
541
|
) -> list[HeaderEntry]:
|
|
540
542
|
"""Extract headers from extra response info event.
|
|
541
543
|
|
|
@@ -583,7 +585,7 @@ class Request:
|
|
|
583
585
|
f'response_extra_info_events={response_extra_info_events}'
|
|
584
586
|
)
|
|
585
587
|
for event in response_extra_info_events:
|
|
586
|
-
params = cast(
|
|
588
|
+
params = cast(ResponseReceivedExtraInfoEventParams, event['params'])
|
|
587
589
|
headers = self._convert_dict_to_header_entries(params['headers'])
|
|
588
590
|
logger.debug(f'Converting dictionary to header entries: headers={headers}')
|
|
589
591
|
set_cookie_headers = [
|
|
@@ -598,7 +600,7 @@ class Request:
|
|
|
598
600
|
logger.debug(f'Set cookies extracted: cookies={cookies}')
|
|
599
601
|
return cookies
|
|
600
602
|
|
|
601
|
-
def _filter_response_extra_info_events(self) -> list[
|
|
603
|
+
def _filter_response_extra_info_events(self) -> list[RequestReceivedEvent]:
|
|
602
604
|
"""Filter network events to find those containing Set-Cookie information.
|
|
603
605
|
|
|
604
606
|
Returns:
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import json as jsonlib
|
|
2
4
|
import logging
|
|
3
|
-
from typing import Any, Optional, Union
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
6
|
+
|
|
7
|
+
from pydoll.exceptions import HTTPError
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
from pydoll.protocol.
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pydoll.protocol.fetch.types import HeaderEntry
|
|
11
|
+
from pydoll.protocol.network.types import CookieParam
|
|
7
12
|
|
|
8
13
|
logger = logging.getLogger(__name__)
|
|
9
14
|
|
|
@@ -221,11 +226,3 @@ class Response:
|
|
|
221
226
|
f'HTTP error status encountered: status={self.status_code}, url={self._url}'
|
|
222
227
|
)
|
|
223
228
|
raise HTTPError(f'{self.status_code} Client Error: for url {self._url}')
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
class HTTPError(Exception):
|
|
227
|
-
"""
|
|
228
|
-
Exception raised for HTTP error responses (4xx and 5xx status codes).
|
|
229
|
-
"""
|
|
230
|
-
|
|
231
|
-
pass
|