phantomwright 0.1.2__tar.gz → 0.1.4__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 (51) hide show
  1. {phantomwright-0.1.2 → phantomwright-0.1.4}/PKG-INFO +9 -3
  2. {phantomwright-0.1.2 → phantomwright-0.1.4}/README.md +7 -1
  3. phantomwright-0.1.4/phantomwright/_repo_version.py +1 -0
  4. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/solver.py +16 -45
  5. {phantomwright-0.1.2 → phantomwright-0.1.4}/pyproject.toml +2 -2
  6. phantomwright-0.1.2/phantomwright/_repo_version.py +0 -1
  7. {phantomwright-0.1.2 → phantomwright-0.1.4}/.gitignore +0 -0
  8. {phantomwright-0.1.2 → phantomwright-0.1.4}/LICENSE +0 -0
  9. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/__init__.py +0 -0
  10. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/_impl/__init__.py +0 -0
  11. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/_impl/_core_debug_patch.py +0 -0
  12. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/_impl/_evaluate_patch.py +0 -0
  13. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/_impl/_inconsistency_patch.py +0 -0
  14. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/async_api/__init__.py +0 -0
  15. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/__init__.py +0 -0
  16. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/scripts/observer.js +0 -0
  17. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/scripts/shadow_root.js +0 -0
  18. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/utils/build_js.py +0 -0
  19. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/utils/consts.py +0 -0
  20. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/utils/detection.py +0 -0
  21. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/utils/dom_helpers.py +0 -0
  22. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/captcha/cloudfare/utils/shadow_root.py +0 -0
  23. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/py.typed +0 -0
  24. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/__init__.py +0 -0
  25. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/chrome.app.js +0 -0
  26. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/chrome.csi.js +0 -0
  27. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/chrome.hairline.js +0 -0
  28. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/chrome.load.times.js +0 -0
  29. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/chrome.runtime.js +0 -0
  30. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/error.prototype.js +0 -0
  31. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/iframe.contentWindow.js +0 -0
  32. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/media.codecs.js +0 -0
  33. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.hardwareConcurrency.js +0 -0
  34. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.languages.js +0 -0
  35. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.permissions.js +0 -0
  36. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.platform.js +0 -0
  37. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.plugins.js +0 -0
  38. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.userAgent.js +0 -0
  39. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/navigator.vendor.js +0 -0
  40. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/evasions/webgl.vendor.js +0 -0
  41. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/generate.magic.arrays.js +0 -0
  42. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/js/utils.js +0 -0
  43. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/stealth/stealth.py +0 -0
  44. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/sync_api/__init__.py +0 -0
  45. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/README.md +0 -0
  46. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/__init__.py +0 -0
  47. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/async_basic.py +0 -0
  48. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/async_simulator.py +0 -0
  49. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/script.py +0 -0
  50. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/sync_basic.py +0 -0
  51. {phantomwright-0.1.2 → phantomwright-0.1.4}/phantomwright/user_simulator/sync_simulator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: phantomwright
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Bridging playwright-core patch + extending playwright API for stealth injection & user simulation
5
5
  Project-URL: homepage, https://github.com/ai-microsoft/phantom-wright
6
6
  Project-URL: changelog, https://github.com/ai-microsoft/phantom-wright/blob/main/CHANGELOG.md
@@ -10,7 +10,7 @@ License-File: LICENSE
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Requires-Python: >=3.9
13
- Requires-Dist: phantomwright-driver==1.57.6
13
+ Requires-Dist: phantomwright-driver==1.57.7
14
14
  Provides-Extra: black
15
15
  Requires-Dist: black>=25.9.0; extra == 'black'
16
16
  Provides-Extra: dev
@@ -183,6 +183,8 @@ async def main():
183
183
  }
184
184
  ```
185
185
 
186
+ > ⚠️ **Note:** To prevent infinite detection loops caused by automatic page refreshes during captcha resolution, manual refreshes on the same URL will **not** trigger the resolve process again.
187
+
186
188
  ## Development
187
189
 
188
190
  ### Setup & Test
@@ -256,6 +258,10 @@ CDP does not provide endpoints to manipulate WebSocket. Supporting this would re
256
258
  await page.route_web_socket("/ws", handler)
257
259
  ```
258
260
 
261
+ #### `add_init_script` Not Compatible with Edge New Tab Page Prerender
262
+
263
+ As Edge NTP's prerendered New Tab page won't install Playwright route, `add_init_script` won't work in a prerendered session, plz ensure you disabled Edge's prerender when launch browser.
264
+
259
265
  #### `add_init_script` Timing Issue
260
266
 
261
267
  `add_init_script` cannot directly call bindings exposed by `expose_function`/`expose_binding`. Init scripts are injected into the HTML document and execute before exposed APIs are available.
@@ -280,7 +286,7 @@ CDP does not provide endpoints to manipulate WebSocket. Supporting this would re
280
286
 
281
287
  #### `add_init_script` Doesn't Affect Special URLs
282
288
 
283
- Patchright init scripts use routing, which doesn't trigger for `about:blank`, Data-URIs, or `file://` URLs.
289
+ Patchright init scripts use routing, which doesn't trigger for `about:blank`, Data-URIs, `file://` URLs, as well as privilege pages such as `edge://newtab`.
284
290
 
285
291
  - ❌ **Data-URIs**
286
292
  ```python
@@ -163,6 +163,8 @@ async def main():
163
163
  }
164
164
  ```
165
165
 
166
+ > ⚠️ **Note:** To prevent infinite detection loops caused by automatic page refreshes during captcha resolution, manual refreshes on the same URL will **not** trigger the resolve process again.
167
+
166
168
  ## Development
167
169
 
168
170
  ### Setup & Test
@@ -236,6 +238,10 @@ CDP does not provide endpoints to manipulate WebSocket. Supporting this would re
236
238
  await page.route_web_socket("/ws", handler)
237
239
  ```
238
240
 
241
+ #### `add_init_script` Not Compatible with Edge New Tab Page Prerender
242
+
243
+ As Edge NTP's prerendered New Tab page won't install Playwright route, `add_init_script` won't work in a prerendered session, plz ensure you disabled Edge's prerender when launch browser.
244
+
239
245
  #### `add_init_script` Timing Issue
240
246
 
241
247
  `add_init_script` cannot directly call bindings exposed by `expose_function`/`expose_binding`. Init scripts are injected into the HTML document and execute before exposed APIs are available.
@@ -260,7 +266,7 @@ CDP does not provide endpoints to manipulate WebSocket. Supporting this would re
260
266
 
261
267
  #### `add_init_script` Doesn't Affect Special URLs
262
268
 
263
- Patchright init scripts use routing, which doesn't trigger for `about:blank`, Data-URIs, or `file://` URLs.
269
+ Patchright init scripts use routing, which doesn't trigger for `about:blank`, Data-URIs, `file://` URLs, as well as privilege pages such as `edge://newtab`.
264
270
 
265
271
  - ❌ **Data-URIs**
266
272
  ```python
@@ -0,0 +1 @@
1
+ version = 'v0.1.4'
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
  import json
3
3
  import time
4
- from typing import Callable, Optional, Union
4
+ from typing import Callable, Optional
5
5
 
6
- from phantomwright.async_api import Page, Browser, BrowserContext
6
+ from phantomwright.async_api import Page, BrowserContext
7
7
 
8
8
  from .utils.consts import ChallengeType
9
9
  from .utils.detection import (
@@ -46,7 +46,7 @@ class CloudflareSolverAsync:
46
46
 
47
47
  def __init__(
48
48
  self,
49
- context_or_browser: Union[BrowserContext, Browser],
49
+ context: BrowserContext,
50
50
  *,
51
51
  max_attempts: int = 3,
52
52
  attempt_delay: int = 5,
@@ -56,8 +56,7 @@ class CloudflareSolverAsync:
56
56
  Initialize the Cloudflare solver.
57
57
 
58
58
  Args:
59
- context_or_browser: Playwright BrowserContext or Browser to monitor for challenges.
60
- If a Browser is provided, all its contexts will be monitored.
59
+ context: Playwright BrowserContext to monitor for challenges.
61
60
  max_attempts: Maximum number of solve attempts per challenge.
62
61
  attempt_delay: Delay in seconds between retry attempts.
63
62
  log_callback: Optional callback function that receives a JSON string
@@ -71,9 +70,7 @@ class CloudflareSolverAsync:
71
70
  - error: Error message if failed, None otherwise
72
71
  - timestamp: Unix timestamp of the event
73
72
  """
74
- self._is_browser = hasattr(context_or_browser, 'new_context')
75
- self._browser: Optional[Browser] = context_or_browser if self._is_browser else None
76
- self._context: Optional[BrowserContext] = None if self._is_browser else context_or_browser
73
+ self.context = context
77
74
  self.max_attempts = max_attempts
78
75
  self.attempt_delay = attempt_delay
79
76
  self.log = log_callback
@@ -143,7 +140,7 @@ class CloudflareSolverAsync:
143
140
  report["challenge_type"] = challenge_type.name
144
141
 
145
142
  if challenge_type is ChallengeType.TURNSTILE:
146
- await page.locator("#cf-turnstile").wait_for()
143
+ await page.locator("#cf-turnstile").wait_for(10000)
147
144
 
148
145
  cf_iframes = await search_shadow_root_iframes(
149
146
  captcha_container=page,
@@ -203,6 +200,8 @@ class CloudflareSolverAsync:
203
200
 
204
201
  finally:
205
202
  report["duration"] = time.time() - report["start_time"]
203
+ if report["success"]:
204
+ report["url"] = None # Clear URL on success for privacy
206
205
  self._log_final_report(report)
207
206
 
208
207
  # ---------------- callback ----------------
@@ -237,48 +236,20 @@ class CloudflareSolverAsync:
237
236
  await page.expose_function("__cf_callback", self._make_on_cf_detected(page))
238
237
  page.on("load", lambda: asyncio.create_task(self._rebind(page)))
239
238
 
240
- def _setup_context(self, context: BrowserContext) -> None:
241
- """Set up page monitoring for a single context."""
242
- context.on(
243
- "page",
244
- lambda p: asyncio.create_task(self._setup_page(p)),
245
- )
246
-
247
239
  # ---------------- public api ----------------
248
240
  def start(self) -> None:
249
241
  """
250
- Start monitoring the browser or context for Cloudflare challenges.
242
+ Start monitoring the browser context for Cloudflare challenges.
251
243
 
252
- This method registers event listeners to automatically detect and solve
253
- Cloudflare challenges on any new page. Call this once after creating
254
- the solver instance.
255
-
256
- If initialized with a Browser, monitors all existing and new contexts.
257
- If initialized with a BrowserContext, monitors only that context.
244
+ This method registers event listeners on the context to automatically
245
+ detect and solve Cloudflare challenges on any new page. Call this once
246
+ after creating the solver instance.
258
247
 
259
248
  Note:
260
249
  This method is synchronous but sets up async handlers internally.
261
250
  Challenges will be solved automatically in the background.
262
251
  """
263
- if self._is_browser:
264
- # Track which contexts we've already set up
265
- self._monitored_contexts: set = set()
266
-
267
- def _check_and_setup_contexts():
268
- for context in self._browser.contexts:
269
- if context not in self._monitored_contexts:
270
- self._monitored_contexts.add(context)
271
- self._setup_context(context)
272
-
273
- # Monitor all existing contexts
274
- _check_and_setup_contexts()
275
-
276
- # Start a background task to periodically check for new contexts
277
- async def _monitor_contexts():
278
- while self._browser.is_connected():
279
- _check_and_setup_contexts()
280
- await asyncio.sleep(0.1) # Check every 100ms for new contexts
281
-
282
- self._monitor_task = asyncio.create_task(_monitor_contexts())
283
- else:
284
- self._setup_context(self._context)
252
+ self.context.on(
253
+ "page",
254
+ lambda p: asyncio.create_task(self._setup_page(p)),
255
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "phantomwright"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  description = "Bridging playwright-core patch + extending playwright API for stealth injection & user simulation"
5
5
  authors = [
6
6
  {name="Hang Yin", email="hangyin@microsoft.com"},
@@ -11,7 +11,7 @@ readme = "README.md"
11
11
  requires-python = ">=3.9"
12
12
 
13
13
  dependencies = [
14
- "phantomwright-driver==1.57.6",
14
+ "phantomwright-driver==1.57.7",
15
15
  ]
16
16
 
17
17
  classifiers = [
@@ -1 +0,0 @@
1
- version = 'v0.1.2'
File without changes
File without changes