pydoll-python 2.21.0__tar.gz → 2.21.1__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.21.1/PKG-INFO +380 -0
- pydoll_python-2.21.1/README.md +359 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/constants.py +115 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/web_element.py +19 -7
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/keyboard.py +25 -2
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/scroll.py +4 -1
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pyproject.toml +1 -1
- pydoll_python-2.21.0/PKG-INFO +0 -446
- pydoll_python-2.21.0/README.md +0 -425
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/LICENSE +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/chromium/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/chromium/base.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/chromium/chrome.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/chromium/edge.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/interfaces.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/managers/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/managers/browser_options_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/managers/browser_process_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/managers/proxy_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/managers/temp_dir_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/options.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/requests/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/requests/har_recorder.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/requests/request.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/requests/response.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/browser/tab.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/browser_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/dom_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/emulation_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/fetch_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/input_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/network_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/page_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/runtime_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/storage_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/commands/target_commands.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/connection/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/connection/connection_handler.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/connection/managers/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/connection/managers/commands_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/connection/managers/events_manager.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/decorators.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/mixins/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/mixins/find_elements_mixin.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/shadow_root.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/utils/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/elements/utils/selector_parser.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/exceptions.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/iframe.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/mouse.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/interactions/utils.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/base.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/browser/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/browser/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/browser/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/browser/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/debugger/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/dom/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/dom/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/dom/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/dom/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/emulation/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/emulation/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/emulation/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/fetch/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/fetch/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/fetch/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/fetch/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/input/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/input/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/input/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/input/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/io/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/network/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/network/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/network/har_types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/network/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/network/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/page/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/page/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/page/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/page/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/runtime/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/runtime/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/runtime/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/runtime/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/security/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/storage/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/storage/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/storage/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/storage/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/target/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/target/events.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/target/methods.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/protocol/target/types.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/py.typed +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/utils/__init__.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/utils/bundle.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/utils/general.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/utils/socks5_proxy_forwarder.py +0 -0
- {pydoll_python-2.21.0 → pydoll_python-2.21.1}/pydoll/utils/user_agent_parser.py +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydoll-python
|
|
3
|
+
Version: 2.21.1
|
|
4
|
+
Summary: Pydoll is a library for automating chromium-based browsers without a WebDriver, offering realistic interactions.
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Author: Thalison Fernandes
|
|
7
|
+
Author-email: thalissfernandes99@gmail.com
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: aiofiles (>=25.1.0,<26.0.0)
|
|
16
|
+
Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
|
|
17
|
+
Requires-Dist: typing_extensions (>=4.14.0,<5.0.0)
|
|
18
|
+
Requires-Dist: websockets (>=14,<15)
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="https://github.com/user-attachments/assets/2c380638-b04a-4b04-b1c8-2958e4237a94" alt="Pydoll Logo" /> <br>
|
|
23
|
+
</p>
|
|
24
|
+
<p align="center">Async-native, fully typed, built for evasion and performance.</p>
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<a href="https://github.com/autoscrape-labs/pydoll/stargazers"><img src="https://img.shields.io/github/stars/autoscrape-labs/pydoll?style=social"></a>
|
|
28
|
+
<a href="https://codecov.io/gh/autoscrape-labs/pydoll" >
|
|
29
|
+
<img src="https://codecov.io/gh/autoscrape-labs/pydoll/graph/badge.svg?token=40I938OGM9"/>
|
|
30
|
+
</a>
|
|
31
|
+
<img src="https://github.com/autoscrape-labs/pydoll/actions/workflows/tests.yml/badge.svg" alt="Tests">
|
|
32
|
+
<img src="https://github.com/autoscrape-labs/pydoll/actions/workflows/ruff-ci.yml/badge.svg" alt="Ruff CI">
|
|
33
|
+
<img src="https://github.com/autoscrape-labs/pydoll/actions/workflows/mypy.yml/badge.svg" alt="MyPy CI">
|
|
34
|
+
<img src="https://img.shields.io/badge/python-%3E%3D3.10-blue" alt="Python >= 3.10">
|
|
35
|
+
<a href="https://deepwiki.com/autoscrape-labs/pydoll"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
<p align="center">
|
|
39
|
+
<a href="https://pydoll.tech/">Documentation</a> ·
|
|
40
|
+
<a href="#getting-started">Getting Started</a> ·
|
|
41
|
+
<a href="#features">Features</a> ·
|
|
42
|
+
<a href="#support">Support</a>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
Pydoll automates Chromium-based browsers (Chrome, Edge) by connecting directly to the Chrome DevTools Protocol over WebSocket. No WebDriver binary, no `navigator.webdriver` flag, no compatibility issues.
|
|
46
|
+
|
|
47
|
+
It combines a high-level API for common tasks with low-level CDP access for fine-grained control over network, fingerprinting, and browser behavior. The entire codebase is async-native and fully type-checked with mypy.
|
|
48
|
+
|
|
49
|
+
### Sponsors
|
|
50
|
+
|
|
51
|
+
<a href="https://www.thordata.com/?ls=github&lk=pydoll">
|
|
52
|
+
<img alt="Thordata" src="public/images/thordata.png" />
|
|
53
|
+
</a>
|
|
54
|
+
|
|
55
|
+
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.
|
|
56
|
+
|
|
57
|
+
**[Sign up through our link](https://www.thordata.com/?ls=github&lk=pydoll)** to support the project and get **1GB free** to get started.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
<a href="https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc">
|
|
62
|
+
<img alt="CapSolver" src="public/images/capsolver.jpeg" />
|
|
63
|
+
</a>
|
|
64
|
+
|
|
65
|
+
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.
|
|
66
|
+
|
|
67
|
+
**[Register with our invite code](https://dashboard.capsolver.com/passport/register?inviteCode=WPhTbOsbXEpc)** and use code **PYDOLL** to get an extra **6% balance bonus**.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### Why Pydoll
|
|
72
|
+
|
|
73
|
+
- **Stealth-first**: Human-like mouse movement, realistic typing, and granular [browser preference](https://pydoll.tech/docs/features/configuration/browser-preferences/) control for fingerprint management.
|
|
74
|
+
- **Async and typed**: Built on `asyncio` from the ground up, 100% type-checked with `mypy`. Full IDE autocompletion and static error checking.
|
|
75
|
+
- **Network control**: [Intercept](https://pydoll.tech/docs/features/network/interception/) requests to block ads/trackers, [monitor](https://pydoll.tech/docs/features/network/monitoring/) traffic for API discovery, and make [authenticated HTTP requests](https://pydoll.tech/docs/features/network/http-requests/) that inherit the browser session.
|
|
76
|
+
- **Shadow DOM and iframes**: Full support for [shadow roots](https://pydoll.tech/docs/deep-dive/architecture/shadow-dom/) (including closed) and cross-origin iframes. Discover, query, and interact with elements inside them using the same API.
|
|
77
|
+
- **Ergonomic API**: `tab.find()` for most cases, `tab.query()` for complex [CSS/XPath selectors](https://pydoll.tech/docs/deep-dive/guides/selectors-guide/).
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install pydoll-python
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
No WebDriver binaries or external dependencies required.
|
|
86
|
+
|
|
87
|
+
## What's New
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary><b>HAR Network Recording</b></summary>
|
|
91
|
+
<br>
|
|
92
|
+
|
|
93
|
+
Record network activity during a browser session and export as HAR 1.2. Replay recorded requests to reproduce exact API sequences.
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from pydoll.browser.chromium import Chrome
|
|
97
|
+
|
|
98
|
+
async with Chrome() as browser:
|
|
99
|
+
tab = await browser.start()
|
|
100
|
+
|
|
101
|
+
async with tab.request.record() as capture:
|
|
102
|
+
await tab.go_to('https://example.com')
|
|
103
|
+
|
|
104
|
+
capture.save('flow.har')
|
|
105
|
+
print(f'Captured {len(capture.entries)} requests')
|
|
106
|
+
|
|
107
|
+
responses = await tab.request.replay('flow.har')
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Filter by resource type:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from pydoll.protocol.network.types import ResourceType
|
|
114
|
+
|
|
115
|
+
async with tab.request.record(
|
|
116
|
+
resource_types=[ResourceType.FETCH, ResourceType.XHR]
|
|
117
|
+
) as capture:
|
|
118
|
+
await tab.go_to('https://example.com')
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
[HAR Recording Docs](https://pydoll.tech/docs/features/network/network-recording/)
|
|
122
|
+
</details>
|
|
123
|
+
|
|
124
|
+
<details>
|
|
125
|
+
<summary><b>Page Bundles</b></summary>
|
|
126
|
+
<br>
|
|
127
|
+
|
|
128
|
+
Save the current page and all its assets (CSS, JS, images, fonts) as a `.zip` bundle for offline viewing. Optionally inline everything into a single HTML file.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
await tab.save_bundle('page.zip')
|
|
132
|
+
await tab.save_bundle('page-inline.zip', inline_assets=True)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
[Screenshots, PDFs & Bundles Docs](https://pydoll.tech/docs/features/automation/screenshots-and-pdfs/)
|
|
136
|
+
</details>
|
|
137
|
+
|
|
138
|
+
<details>
|
|
139
|
+
<summary><b>Shadow DOM Support</b></summary>
|
|
140
|
+
<br>
|
|
141
|
+
|
|
142
|
+
Full Shadow DOM support, including closed shadow roots. Because Pydoll operates at the CDP level (below JavaScript), the `closed` mode restriction doesn't apply.
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
shadow = await element.get_shadow_root()
|
|
146
|
+
button = await shadow.query('.internal-btn')
|
|
147
|
+
await button.click()
|
|
148
|
+
|
|
149
|
+
# Discover all shadow roots on the page
|
|
150
|
+
shadow_roots = await tab.find_shadow_roots()
|
|
151
|
+
for sr in shadow_roots:
|
|
152
|
+
checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
|
|
153
|
+
if checkbox:
|
|
154
|
+
await checkbox.click()
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Highlights:
|
|
158
|
+
- Closed shadow roots work without workarounds
|
|
159
|
+
- `find_shadow_roots()` discovers every shadow root on the page
|
|
160
|
+
- `timeout` parameter for polling until shadow roots appear
|
|
161
|
+
- `deep=True` traverses cross-origin iframes (OOPIFs)
|
|
162
|
+
- Standard `find()`, `query()`, `click()` API inside shadow roots
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# Cloudflare Turnstile inside a cross-origin iframe
|
|
166
|
+
shadow_roots = await tab.find_shadow_roots(deep=True, timeout=10)
|
|
167
|
+
for sr in shadow_roots:
|
|
168
|
+
checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
|
|
169
|
+
if checkbox:
|
|
170
|
+
await checkbox.click()
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
[Shadow DOM Docs](https://pydoll.tech/docs/deep-dive/architecture/shadow-dom/)
|
|
174
|
+
</details>
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary><b>Humanized Mouse Movement</b></summary>
|
|
178
|
+
<br>
|
|
179
|
+
|
|
180
|
+
Mouse operations produce human-like cursor movement by default:
|
|
181
|
+
|
|
182
|
+
- **Bezier curve paths** with asymmetric control points
|
|
183
|
+
- **Fitts's Law timing**: duration scales with distance
|
|
184
|
+
- **Minimum-jerk velocity**: bell-shaped speed profile
|
|
185
|
+
- **Physiological tremor**: Gaussian noise scaled with velocity
|
|
186
|
+
- **Overshoot correction**: ~70% chance on fast movements, then corrects back
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
await tab.mouse.move(500, 300)
|
|
190
|
+
await tab.mouse.click(500, 300)
|
|
191
|
+
await tab.mouse.drag(100, 200, 500, 400)
|
|
192
|
+
|
|
193
|
+
button = await tab.find(id='submit')
|
|
194
|
+
await button.click()
|
|
195
|
+
|
|
196
|
+
# Opt out when speed matters
|
|
197
|
+
await tab.mouse.click(500, 300, humanize=False)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
[Mouse Control Docs](https://pydoll.tech/docs/features/automation/mouse-control/)
|
|
201
|
+
</details>
|
|
202
|
+
|
|
203
|
+
## Getting Started
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
import asyncio
|
|
207
|
+
from pydoll.browser import Chrome
|
|
208
|
+
from pydoll.constants import Key
|
|
209
|
+
|
|
210
|
+
async def google_search(query: str):
|
|
211
|
+
async with Chrome() as browser:
|
|
212
|
+
tab = await browser.start()
|
|
213
|
+
await tab.go_to('https://www.google.com')
|
|
214
|
+
|
|
215
|
+
search_box = await tab.find(tag_name='textarea', name='q')
|
|
216
|
+
await search_box.insert_text(query)
|
|
217
|
+
await tab.keyboard.press(Key.ENTER)
|
|
218
|
+
|
|
219
|
+
first_result = await tab.find(
|
|
220
|
+
tag_name='h3',
|
|
221
|
+
text='autoscrape-labs/pydoll',
|
|
222
|
+
timeout=10,
|
|
223
|
+
)
|
|
224
|
+
await first_result.click()
|
|
225
|
+
|
|
226
|
+
await tab.find(id='repository-container-header', timeout=10)
|
|
227
|
+
print(f"Page loaded: {await tab.title}")
|
|
228
|
+
|
|
229
|
+
asyncio.run(google_search('pydoll site:github.com'))
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Features
|
|
233
|
+
|
|
234
|
+
<details>
|
|
235
|
+
<summary><b>Hybrid Automation (UI + API)</b></summary>
|
|
236
|
+
<br>
|
|
237
|
+
|
|
238
|
+
Use UI automation to pass login flows (CAPTCHAs, JS challenges), then switch to `tab.request` for fast API calls that inherit the full browser session: cookies, headers, and all.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
# Log in via UI
|
|
242
|
+
await tab.go_to('https://my-site.com/login')
|
|
243
|
+
await (await tab.find(id='username')).type_text('user')
|
|
244
|
+
await (await tab.find(id='password')).type_text('pass123')
|
|
245
|
+
await (await tab.find(id='login-btn')).click()
|
|
246
|
+
|
|
247
|
+
# Make authenticated API calls using the browser session
|
|
248
|
+
response = await tab.request.get('https://my-site.com/api/user/profile')
|
|
249
|
+
user_data = response.json()
|
|
250
|
+
```
|
|
251
|
+
[Hybrid Automation Docs](https://pydoll.tech/docs/features/network/http-requests/)
|
|
252
|
+
</details>
|
|
253
|
+
|
|
254
|
+
<details>
|
|
255
|
+
<summary><b>Network Interception and Monitoring</b></summary>
|
|
256
|
+
<br>
|
|
257
|
+
|
|
258
|
+
Monitor traffic for API discovery or intercept requests to block ads, trackers, and unnecessary resources.
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
import asyncio
|
|
262
|
+
from pydoll.browser.chromium import Chrome
|
|
263
|
+
from pydoll.protocol.fetch.events import FetchEvent, RequestPausedEvent
|
|
264
|
+
from pydoll.protocol.network.types import ErrorReason
|
|
265
|
+
|
|
266
|
+
async def block_images():
|
|
267
|
+
async with Chrome() as browser:
|
|
268
|
+
tab = await browser.start()
|
|
269
|
+
|
|
270
|
+
async def block_resource(event: RequestPausedEvent):
|
|
271
|
+
request_id = event['params']['requestId']
|
|
272
|
+
resource_type = event['params']['resourceType']
|
|
273
|
+
|
|
274
|
+
if resource_type in ['Image', 'Stylesheet']:
|
|
275
|
+
await tab.fail_request(request_id, ErrorReason.BLOCKED_BY_CLIENT)
|
|
276
|
+
else:
|
|
277
|
+
await tab.continue_request(request_id)
|
|
278
|
+
|
|
279
|
+
await tab.enable_fetch_events()
|
|
280
|
+
await tab.on(FetchEvent.REQUEST_PAUSED, block_resource)
|
|
281
|
+
|
|
282
|
+
await tab.go_to('https://example.com')
|
|
283
|
+
await asyncio.sleep(3)
|
|
284
|
+
await tab.disable_fetch_events()
|
|
285
|
+
|
|
286
|
+
asyncio.run(block_images())
|
|
287
|
+
```
|
|
288
|
+
[Network Monitoring](https://pydoll.tech/docs/features/network/monitoring/) | [Request Interception](https://pydoll.tech/docs/features/network/interception/)
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
<details>
|
|
292
|
+
<summary><b>Browser Fingerprint Control</b></summary>
|
|
293
|
+
<br>
|
|
294
|
+
|
|
295
|
+
Granular control over [browser preferences](https://pydoll.tech/docs/features/configuration/browser-preferences/): hundreds of internal Chrome settings for building consistent fingerprints.
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
options = ChromiumOptions()
|
|
299
|
+
|
|
300
|
+
options.browser_preferences = {
|
|
301
|
+
'profile': {
|
|
302
|
+
'default_content_setting_values': {
|
|
303
|
+
'notifications': 2,
|
|
304
|
+
'geolocation': 2,
|
|
305
|
+
},
|
|
306
|
+
'password_manager_enabled': False
|
|
307
|
+
},
|
|
308
|
+
'intl': {
|
|
309
|
+
'accept_languages': 'en-US,en',
|
|
310
|
+
},
|
|
311
|
+
'browser': {
|
|
312
|
+
'check_default_browser': False,
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
[Browser Preferences Guide](https://pydoll.tech/docs/features/configuration/browser-preferences/)
|
|
317
|
+
</details>
|
|
318
|
+
|
|
319
|
+
<details>
|
|
320
|
+
<summary><b>Concurrency, Contexts and Remote Connections</b></summary>
|
|
321
|
+
<br>
|
|
322
|
+
|
|
323
|
+
Manage [multiple tabs](https://pydoll.tech/docs/features/browser-management/tabs/) and [browser contexts](https://pydoll.tech/docs/features/browser-management/contexts/) (isolated sessions) concurrently. Connect to browsers running in Docker or remote servers.
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
async def scrape_page(url, tab):
|
|
327
|
+
await tab.go_to(url)
|
|
328
|
+
return await tab.title
|
|
329
|
+
|
|
330
|
+
async def concurrent_scraping():
|
|
331
|
+
async with Chrome() as browser:
|
|
332
|
+
tab_google = await browser.start()
|
|
333
|
+
tab_ddg = await browser.new_tab()
|
|
334
|
+
|
|
335
|
+
results = await asyncio.gather(
|
|
336
|
+
scrape_page('https://google.com/', tab_google),
|
|
337
|
+
scrape_page('https://duckduckgo.com/', tab_ddg)
|
|
338
|
+
)
|
|
339
|
+
print(results)
|
|
340
|
+
```
|
|
341
|
+
[Multi-Tab Management](https://pydoll.tech/docs/features/browser-management/tabs/) | [Remote Connections](https://pydoll.tech/docs/features/advanced/remote-connections/)
|
|
342
|
+
</details>
|
|
343
|
+
|
|
344
|
+
<details>
|
|
345
|
+
<summary><b>Retry Decorator</b></summary>
|
|
346
|
+
<br>
|
|
347
|
+
|
|
348
|
+
The `@retry` decorator supports custom recovery logic between attempts (e.g., refreshing the page, rotating proxies) and exponential backoff.
|
|
349
|
+
|
|
350
|
+
```python
|
|
351
|
+
from pydoll.decorators import retry
|
|
352
|
+
from pydoll.exceptions import ElementNotFound, NetworkError
|
|
353
|
+
|
|
354
|
+
@retry(
|
|
355
|
+
max_retries=3,
|
|
356
|
+
exceptions=[ElementNotFound, NetworkError],
|
|
357
|
+
on_retry=my_recovery_function,
|
|
358
|
+
exponential_backoff=True
|
|
359
|
+
)
|
|
360
|
+
async def scrape_product(self, url: str):
|
|
361
|
+
# scraping logic
|
|
362
|
+
...
|
|
363
|
+
```
|
|
364
|
+
[Retry Decorator Docs](https://pydoll.tech/docs/features/advanced/decorators/)
|
|
365
|
+
</details>
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Contributing
|
|
370
|
+
|
|
371
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
372
|
+
|
|
373
|
+
## Support
|
|
374
|
+
|
|
375
|
+
If you find Pydoll useful, consider [sponsoring the project on GitHub](https://github.com/sponsors/thalissonvs).
|
|
376
|
+
|
|
377
|
+
## License
|
|
378
|
+
|
|
379
|
+
[MIT License](LICENSE)
|
|
380
|
+
|