pydoll-python 2.16.0__tar.gz → 2.17.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.
Files changed (92) hide show
  1. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/PKG-INFO +93 -26
  2. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/README.md +92 -25
  3. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/tab.py +374 -28
  4. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/elements/mixins/find_elements_mixin.py +23 -3
  5. pydoll_python-2.17.0/pydoll/elements/shadow_root.py +89 -0
  6. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/elements/web_element.py +80 -5
  7. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/exceptions.py +6 -0
  8. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pyproject.toml +1 -1
  9. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/LICENSE +0 -0
  10. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/__init__.py +0 -0
  11. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/__init__.py +0 -0
  12. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/chromium/__init__.py +0 -0
  13. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/chromium/base.py +0 -0
  14. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/chromium/chrome.py +0 -0
  15. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/chromium/edge.py +0 -0
  16. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/interfaces.py +0 -0
  17. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/managers/__init__.py +0 -0
  18. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/managers/browser_options_manager.py +0 -0
  19. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/managers/browser_process_manager.py +0 -0
  20. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/managers/proxy_manager.py +0 -0
  21. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/managers/temp_dir_manager.py +0 -0
  22. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/options.py +0 -0
  23. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/requests/__init__.py +0 -0
  24. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/requests/request.py +0 -0
  25. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/browser/requests/response.py +0 -0
  26. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/__init__.py +0 -0
  27. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/browser_commands.py +0 -0
  28. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/dom_commands.py +0 -0
  29. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/fetch_commands.py +0 -0
  30. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/input_commands.py +0 -0
  31. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/network_commands.py +0 -0
  32. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/page_commands.py +0 -0
  33. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/runtime_commands.py +0 -0
  34. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/storage_commands.py +0 -0
  35. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/commands/target_commands.py +0 -0
  36. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/connection/__init__.py +0 -0
  37. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/connection/connection_handler.py +0 -0
  38. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/connection/managers/__init__.py +0 -0
  39. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/connection/managers/commands_manager.py +0 -0
  40. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/connection/managers/events_manager.py +0 -0
  41. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/constants.py +0 -0
  42. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/decorators.py +0 -0
  43. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/elements/__init__.py +0 -0
  44. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/elements/mixins/__init__.py +0 -0
  45. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/interactions/__init__.py +0 -0
  46. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/interactions/iframe.py +0 -0
  47. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/interactions/keyboard.py +0 -0
  48. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/interactions/scroll.py +0 -0
  49. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/__init__.py +0 -0
  50. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/base.py +0 -0
  51. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/browser/__init__.py +0 -0
  52. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/browser/events.py +0 -0
  53. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/browser/methods.py +0 -0
  54. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/browser/types.py +0 -0
  55. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/debugger/types.py +0 -0
  56. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/dom/__init__.py +0 -0
  57. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/dom/events.py +0 -0
  58. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/dom/methods.py +0 -0
  59. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/dom/types.py +0 -0
  60. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/emulation/types.py +0 -0
  61. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/fetch/__init__.py +0 -0
  62. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/fetch/events.py +0 -0
  63. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/fetch/methods.py +0 -0
  64. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/fetch/types.py +0 -0
  65. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/input/__init__.py +0 -0
  66. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/input/events.py +0 -0
  67. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/input/methods.py +0 -0
  68. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/input/types.py +0 -0
  69. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/io/types.py +0 -0
  70. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/network/__init__.py +0 -0
  71. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/network/events.py +0 -0
  72. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/network/methods.py +0 -0
  73. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/network/types.py +0 -0
  74. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/page/__init__.py +0 -0
  75. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/page/events.py +0 -0
  76. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/page/methods.py +0 -0
  77. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/page/types.py +0 -0
  78. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/runtime/__init__.py +0 -0
  79. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/runtime/events.py +0 -0
  80. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/runtime/methods.py +0 -0
  81. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/runtime/types.py +0 -0
  82. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/security/types.py +0 -0
  83. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/storage/__init__.py +0 -0
  84. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/storage/events.py +0 -0
  85. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/storage/methods.py +0 -0
  86. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/storage/types.py +0 -0
  87. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/target/__init__.py +0 -0
  88. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/target/events.py +0 -0
  89. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/target/methods.py +0 -0
  90. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/protocol/target/types.py +0 -0
  91. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/py.typed +0 -0
  92. {pydoll_python-2.16.0 → pydoll_python-2.17.0}/pydoll/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydoll-python
3
- Version: 2.16.0
3
+ Version: 2.17.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
@@ -84,6 +84,73 @@ That's it. No `webdrivers`. No external dependencies.
84
84
 
85
85
  ## 🆕 What's New
86
86
 
87
+ <details>
88
+ <summary><b>Shadow DOM Support: Access Closed Shadow Roots with Zero Effort</b></summary>
89
+ <br>
90
+
91
+ Pydoll now provides **full Shadow DOM support**, automatically handling both open and closed shadow roots — something traditional automation tools can't do. Because Pydoll operates at the CDP level (below JavaScript), the `closed` mode restriction simply doesn't apply.
92
+
93
+ ```python
94
+ # Get the shadow root of a specific element
95
+ shadow = await element.get_shadow_root()
96
+ button = await shadow.query('.internal-btn')
97
+ await button.click()
98
+
99
+ # Or discover ALL shadow roots on the page at once
100
+ shadow_roots = await tab.find_shadow_roots()
101
+ for sr in shadow_roots:
102
+ checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
103
+ if checkbox:
104
+ await checkbox.click()
105
+ ```
106
+
107
+ **Key highlights:**
108
+
109
+ - **Closed shadow roots just work** — no workarounds, no hacks
110
+ - **`find_shadow_roots()`** discovers every shadow root on the page, even when you don't know the host selector
111
+ - **`timeout` parameter** for polling until shadow roots appear asynchronously — works on both `find_shadow_roots()` and `get_shadow_root()`
112
+ - **`deep=True`** traverses cross-origin iframes (OOPIFs) — essential for widgets like Cloudflare Turnstile captchas
113
+ - **Same familiar API** — use `find()`, `query()`, and `click()` inside shadow roots just like anywhere else
114
+
115
+ ```python
116
+ # Real-world example: Cloudflare Turnstile inside a cross-origin iframe
117
+ shadow_roots = await tab.find_shadow_roots(deep=True, timeout=10)
118
+ for sr in shadow_roots:
119
+ checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
120
+ if checkbox:
121
+ await checkbox.click()
122
+ ```
123
+
124
+ [**📖 Shadow DOM Docs**](https://pydoll.tech/docs/deep-dive/architecture/shadow-dom/)
125
+ </details>
126
+
127
+ <details>
128
+ <summary><b>Cloudflare Turnstile Bypass: Faster, More Robust, Fully Automatic</b></summary>
129
+ <br>
130
+
131
+ The Cloudflare Turnstile bypass has been **completely rewritten** using shadow root traversal, making it significantly more reliable than the old selector-based approach.
132
+
133
+ **What changed:**
134
+
135
+ - **Automatic detection** — Pydoll now polls the page's shadow DOM for the Cloudflare challenge domain, no selectors needed
136
+ - **Full shadow root traversal** — navigates outer shadow root → cross-origin iframe → inner shadow root → actual checkbox element
137
+ - **No more artificial delays** — the old `time_before_click` sleep is gone; the checkbox is clicked as soon as it's found
138
+ - **Zero configuration** — just call the method, Pydoll handles the rest
139
+
140
+ ```python
141
+ async with Chrome() as browser:
142
+ tab = await browser.start()
143
+
144
+ # That's it — fully automatic
145
+ async with tab.expect_and_bypass_cloudflare_captcha():
146
+ await tab.go_to('https://site-with-turnstile.com')
147
+
148
+ print("Captcha handled!")
149
+ ```
150
+
151
+ [**📖 Cloudflare Turnstile Docs**](https://pydoll.tech/docs/features/advanced/behavioral-captcha-bypass/)
152
+ </details>
153
+
87
154
  <details>
88
155
  <summary><b>Humanized Keyboard Input (<code>humanize=True</code>)</b></summary>
89
156
  <br>
@@ -142,31 +209,31 @@ from pydoll.browser import Chrome
142
209
  from pydoll.constants import Key
143
210
 
144
211
  async def google_search(query: str):
145
-     # Context manager handles browser start() and stop()
146
-     async with Chrome() as browser:
147
-         tab = await browser.start()
148
-         await tab.go_to('https://www.google.com')
149
-
150
-         # Intuitive finding API: find by HTML attributes
151
-         search_box = await tab.find(tag_name='textarea', name='q')
152
-         
153
-         # "Human-like" interactions simulate typing
154
-         await search_box.insert_text(query)
155
-         await search_box.press_keyboard_key(Key.ENTER)
156
-
157
-         # Find by text and click (simulates mouse movement)
158
-         first_result = await tab.find(
159
-             tag_name='h3',
160
-             text='autoscrape-labs/pydoll', # Supports partial text matching
161
-             timeout=10,
162
-         )
163
-         await first_result.click()
164
-
165
-         # Wait for an element to confirm navigation
166
-         await tab.find(id='repository-container-header', timeout=10)
167
-         print(f"Page loaded: {await tab.title}")
168
-
169
- asyncio.run(google_search('pydoll python'))
212
+ # Context manager handles browser start() and stop()
213
+ async with Chrome() as browser:
214
+ tab = await browser.start()
215
+ await tab.go_to('https://www.google.com')
216
+
217
+ # Intuitive finding API: find by HTML attributes
218
+ search_box = await tab.find(tag_name='textarea', name='q')
219
+
220
+ # "Human-like" interactions simulate typing
221
+ await search_box.insert_text(query)
222
+ await tab.keyboard.press(Key.ENTER)
223
+
224
+ # Find by text and click (simulates mouse movement)
225
+ first_result = await tab.find(
226
+ tag_name='h3',
227
+ text='autoscrape-labs/pydoll', # Supports partial text matching
228
+ timeout=10,
229
+ )
230
+ await first_result.click()
231
+
232
+ # Wait for an element to confirm navigation
233
+ await tab.find(id='repository-container-header', timeout=10)
234
+ print(f"Page loaded: {await tab.title}")
235
+
236
+ asyncio.run(google_search('pydoll site:github.com'))
170
237
  ```
171
238
 
172
239
  ## ⚡ The Pydoll Feature Ecosystem
@@ -64,6 +64,73 @@ That's it. No `webdrivers`. No external dependencies.
64
64
 
65
65
  ## 🆕 What's New
66
66
 
67
+ <details>
68
+ <summary><b>Shadow DOM Support: Access Closed Shadow Roots with Zero Effort</b></summary>
69
+ <br>
70
+
71
+ Pydoll now provides **full Shadow DOM support**, automatically handling both open and closed shadow roots — something traditional automation tools can't do. Because Pydoll operates at the CDP level (below JavaScript), the `closed` mode restriction simply doesn't apply.
72
+
73
+ ```python
74
+ # Get the shadow root of a specific element
75
+ shadow = await element.get_shadow_root()
76
+ button = await shadow.query('.internal-btn')
77
+ await button.click()
78
+
79
+ # Or discover ALL shadow roots on the page at once
80
+ shadow_roots = await tab.find_shadow_roots()
81
+ for sr in shadow_roots:
82
+ checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
83
+ if checkbox:
84
+ await checkbox.click()
85
+ ```
86
+
87
+ **Key highlights:**
88
+
89
+ - **Closed shadow roots just work** — no workarounds, no hacks
90
+ - **`find_shadow_roots()`** discovers every shadow root on the page, even when you don't know the host selector
91
+ - **`timeout` parameter** for polling until shadow roots appear asynchronously — works on both `find_shadow_roots()` and `get_shadow_root()`
92
+ - **`deep=True`** traverses cross-origin iframes (OOPIFs) — essential for widgets like Cloudflare Turnstile captchas
93
+ - **Same familiar API** — use `find()`, `query()`, and `click()` inside shadow roots just like anywhere else
94
+
95
+ ```python
96
+ # Real-world example: Cloudflare Turnstile inside a cross-origin iframe
97
+ shadow_roots = await tab.find_shadow_roots(deep=True, timeout=10)
98
+ for sr in shadow_roots:
99
+ checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
100
+ if checkbox:
101
+ await checkbox.click()
102
+ ```
103
+
104
+ [**📖 Shadow DOM Docs**](https://pydoll.tech/docs/deep-dive/architecture/shadow-dom/)
105
+ </details>
106
+
107
+ <details>
108
+ <summary><b>Cloudflare Turnstile Bypass: Faster, More Robust, Fully Automatic</b></summary>
109
+ <br>
110
+
111
+ The Cloudflare Turnstile bypass has been **completely rewritten** using shadow root traversal, making it significantly more reliable than the old selector-based approach.
112
+
113
+ **What changed:**
114
+
115
+ - **Automatic detection** — Pydoll now polls the page's shadow DOM for the Cloudflare challenge domain, no selectors needed
116
+ - **Full shadow root traversal** — navigates outer shadow root → cross-origin iframe → inner shadow root → actual checkbox element
117
+ - **No more artificial delays** — the old `time_before_click` sleep is gone; the checkbox is clicked as soon as it's found
118
+ - **Zero configuration** — just call the method, Pydoll handles the rest
119
+
120
+ ```python
121
+ async with Chrome() as browser:
122
+ tab = await browser.start()
123
+
124
+ # That's it — fully automatic
125
+ async with tab.expect_and_bypass_cloudflare_captcha():
126
+ await tab.go_to('https://site-with-turnstile.com')
127
+
128
+ print("Captcha handled!")
129
+ ```
130
+
131
+ [**📖 Cloudflare Turnstile Docs**](https://pydoll.tech/docs/features/advanced/behavioral-captcha-bypass/)
132
+ </details>
133
+
67
134
  <details>
68
135
  <summary><b>Humanized Keyboard Input (<code>humanize=True</code>)</b></summary>
69
136
  <br>
@@ -122,31 +189,31 @@ from pydoll.browser import Chrome
122
189
  from pydoll.constants import Key
123
190
 
124
191
  async def google_search(query: str):
125
-     # Context manager handles browser start() and stop()
126
-     async with Chrome() as browser:
127
-         tab = await browser.start()
128
-         await tab.go_to('https://www.google.com')
129
-
130
-         # Intuitive finding API: find by HTML attributes
131
-         search_box = await tab.find(tag_name='textarea', name='q')
132
-         
133
-         # "Human-like" interactions simulate typing
134
-         await search_box.insert_text(query)
135
-         await search_box.press_keyboard_key(Key.ENTER)
136
-
137
-         # Find by text and click (simulates mouse movement)
138
-         first_result = await tab.find(
139
-             tag_name='h3',
140
-             text='autoscrape-labs/pydoll', # Supports partial text matching
141
-             timeout=10,
142
-         )
143
-         await first_result.click()
144
-
145
-         # Wait for an element to confirm navigation
146
-         await tab.find(id='repository-container-header', timeout=10)
147
-         print(f"Page loaded: {await tab.title}")
148
-
149
- asyncio.run(google_search('pydoll python'))
192
+ # Context manager handles browser start() and stop()
193
+ async with Chrome() as browser:
194
+ tab = await browser.start()
195
+ await tab.go_to('https://www.google.com')
196
+
197
+ # Intuitive finding API: find by HTML attributes
198
+ search_box = await tab.find(tag_name='textarea', name='q')
199
+
200
+ # "Human-like" interactions simulate typing
201
+ await search_box.insert_text(query)
202
+ await tab.keyboard.press(Key.ENTER)
203
+
204
+ # Find by text and click (simulates mouse movement)
205
+ first_result = await tab.find(
206
+ tag_name='h3',
207
+ text='autoscrape-labs/pydoll', # Supports partial text matching
208
+ timeout=10,
209
+ )
210
+ await first_result.click()
211
+
212
+ # Wait for an element to confirm navigation
213
+ await tab.find(id='repository-container-header', timeout=10)
214
+ print(f"Page loaded: {await tab.title}")
215
+
216
+ asyncio.run(google_search('pydoll site:github.com'))
150
217
  ```
151
218
 
152
219
  ## ⚡ The Pydoll Feature Ecosystem