unrealon 1.1.1__py3-none-any.whl → 1.1.4__py3-none-any.whl
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.
- unrealon/__init__.py +16 -6
- unrealon-1.1.4.dist-info/METADATA +658 -0
- unrealon-1.1.4.dist-info/RECORD +54 -0
- {unrealon-1.1.1.dist-info → unrealon-1.1.4.dist-info}/entry_points.txt +1 -1
- unrealon_browser/__init__.py +3 -6
- unrealon_browser/core/browser_manager.py +86 -84
- unrealon_browser/dto/models/config.py +2 -0
- unrealon_browser/managers/captcha.py +165 -185
- unrealon_browser/managers/cookies.py +57 -28
- unrealon_browser/managers/logger_bridge.py +94 -34
- unrealon_browser/managers/profile.py +186 -158
- unrealon_browser/managers/stealth.py +58 -47
- unrealon_driver/__init__.py +8 -21
- unrealon_driver/exceptions.py +5 -0
- unrealon_driver/html_analyzer/__init__.py +32 -0
- unrealon_driver/{parser/managers/html.py → html_analyzer/cleaner.py} +330 -405
- unrealon_driver/html_analyzer/config.py +64 -0
- unrealon_driver/html_analyzer/manager.py +247 -0
- unrealon_driver/html_analyzer/models.py +115 -0
- unrealon_driver/html_analyzer/websocket_analyzer.py +157 -0
- unrealon_driver/models/__init__.py +31 -0
- unrealon_driver/models/websocket.py +98 -0
- unrealon_driver/parser/__init__.py +4 -23
- unrealon_driver/parser/cli_manager.py +6 -5
- unrealon_driver/parser/daemon_manager.py +242 -66
- unrealon_driver/parser/managers/__init__.py +0 -21
- unrealon_driver/parser/managers/config.py +15 -3
- unrealon_driver/parser/parser_manager.py +225 -395
- unrealon_driver/smart_logging/__init__.py +24 -0
- unrealon_driver/smart_logging/models.py +44 -0
- unrealon_driver/smart_logging/smart_logger.py +406 -0
- unrealon_driver/smart_logging/unified_logger.py +525 -0
- unrealon_driver/websocket/__init__.py +31 -0
- unrealon_driver/websocket/client.py +249 -0
- unrealon_driver/websocket/config.py +188 -0
- unrealon_driver/websocket/manager.py +90 -0
- unrealon-1.1.1.dist-info/METADATA +0 -722
- unrealon-1.1.1.dist-info/RECORD +0 -82
- unrealon_bridge/__init__.py +0 -114
- unrealon_bridge/cli.py +0 -316
- unrealon_bridge/client/__init__.py +0 -93
- unrealon_bridge/client/base.py +0 -78
- unrealon_bridge/client/commands.py +0 -89
- unrealon_bridge/client/connection.py +0 -90
- unrealon_bridge/client/events.py +0 -65
- unrealon_bridge/client/health.py +0 -38
- unrealon_bridge/client/html_parser.py +0 -146
- unrealon_bridge/client/logging.py +0 -139
- unrealon_bridge/client/proxy.py +0 -70
- unrealon_bridge/client/scheduler.py +0 -450
- unrealon_bridge/client/session.py +0 -70
- unrealon_bridge/configs/__init__.py +0 -14
- unrealon_bridge/configs/bridge_config.py +0 -212
- unrealon_bridge/configs/bridge_config.yaml +0 -39
- unrealon_bridge/models/__init__.py +0 -138
- unrealon_bridge/models/base.py +0 -28
- unrealon_bridge/models/command.py +0 -41
- unrealon_bridge/models/events.py +0 -40
- unrealon_bridge/models/html_parser.py +0 -79
- unrealon_bridge/models/logging.py +0 -55
- unrealon_bridge/models/parser.py +0 -63
- unrealon_bridge/models/proxy.py +0 -41
- unrealon_bridge/models/requests.py +0 -95
- unrealon_bridge/models/responses.py +0 -88
- unrealon_bridge/models/scheduler.py +0 -592
- unrealon_bridge/models/session.py +0 -28
- unrealon_bridge/server/__init__.py +0 -91
- unrealon_bridge/server/base.py +0 -171
- unrealon_bridge/server/handlers/__init__.py +0 -23
- unrealon_bridge/server/handlers/command.py +0 -110
- unrealon_bridge/server/handlers/html_parser.py +0 -139
- unrealon_bridge/server/handlers/logging.py +0 -95
- unrealon_bridge/server/handlers/parser.py +0 -95
- unrealon_bridge/server/handlers/proxy.py +0 -75
- unrealon_bridge/server/handlers/scheduler.py +0 -545
- unrealon_bridge/server/handlers/session.py +0 -66
- unrealon_driver/browser/__init__.py +0 -8
- unrealon_driver/browser/config.py +0 -74
- unrealon_driver/browser/manager.py +0 -416
- unrealon_driver/parser/managers/browser.py +0 -51
- unrealon_driver/parser/managers/logging.py +0 -609
- {unrealon-1.1.1.dist-info → unrealon-1.1.4.dist-info}/WHEEL +0 -0
- {unrealon-1.1.1.dist-info → unrealon-1.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,12 +3,15 @@ Stealth Manager - Anti-detection system for browser automation
|
|
|
3
3
|
Layer 1: Advanced stealth capabilities inspired by unrealparser
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
import logging
|
|
6
7
|
import asyncio
|
|
7
8
|
from typing import Dict, Any, Optional, List
|
|
8
9
|
from playwright.async_api import Page, BrowserContext
|
|
9
10
|
|
|
10
11
|
# CRITICAL REQUIREMENTS COMPLIANCE - NO INLINE IMPORTS!
|
|
11
|
-
from playwright_stealth import
|
|
12
|
+
from playwright_stealth import stealth, Stealth
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class StealthManager:
|
|
@@ -22,10 +25,11 @@ class StealthManager:
|
|
|
22
25
|
- Stealth arguments optimization
|
|
23
26
|
"""
|
|
24
27
|
|
|
25
|
-
def __init__(self):
|
|
28
|
+
def __init__(self, logger_bridge=None):
|
|
26
29
|
"""Initialize stealth manager"""
|
|
27
30
|
self.stealth_applied = False
|
|
28
31
|
self.test_results: Optional[Dict[str, Any]] = None
|
|
32
|
+
self.logger_bridge = logger_bridge
|
|
29
33
|
|
|
30
34
|
def get_stealth_args(self) -> List[str]:
|
|
31
35
|
"""
|
|
@@ -43,13 +47,34 @@ class StealthManager:
|
|
|
43
47
|
"--no-default-browser-check",
|
|
44
48
|
]
|
|
45
49
|
|
|
50
|
+
# private warpper for logger with if self.logger_bridge
|
|
51
|
+
def _logger(self, message: str, level: str = "info") -> None:
|
|
52
|
+
if self.logger_bridge:
|
|
53
|
+
if level == "info":
|
|
54
|
+
self.logger_bridge.log_info(message)
|
|
55
|
+
elif level == "error":
|
|
56
|
+
self.logger_bridge.log_error(message)
|
|
57
|
+
elif level == "warning":
|
|
58
|
+
self.logger_bridge.log_warning(message)
|
|
59
|
+
else:
|
|
60
|
+
self.logger_bridge.log_info(message)
|
|
61
|
+
else:
|
|
62
|
+
if level == "info":
|
|
63
|
+
logger.info(message)
|
|
64
|
+
elif level == "error":
|
|
65
|
+
logger.error(message)
|
|
66
|
+
elif level == "warning":
|
|
67
|
+
logger.warning(message)
|
|
68
|
+
else:
|
|
69
|
+
logger.info(message)
|
|
70
|
+
|
|
46
71
|
async def apply_stealth(self, page: Page) -> bool:
|
|
47
72
|
"""
|
|
48
73
|
Apply stealth measures to page
|
|
49
74
|
Combines multiple anti-detection techniques
|
|
50
75
|
"""
|
|
51
76
|
try:
|
|
52
|
-
|
|
77
|
+
self._logger("🥷 Applying stealth measures...", "info")
|
|
53
78
|
|
|
54
79
|
# 1. Apply playwright-stealth if available
|
|
55
80
|
stealth_applied = await self._apply_playwright_stealth(page)
|
|
@@ -64,12 +89,12 @@ class StealthManager:
|
|
|
64
89
|
await self._set_realistic_properties(page)
|
|
65
90
|
|
|
66
91
|
self.stealth_applied = True
|
|
67
|
-
|
|
92
|
+
self._logger("✅ Stealth measures applied successfully", "info")
|
|
68
93
|
|
|
69
94
|
return True
|
|
70
95
|
|
|
71
96
|
except Exception as e:
|
|
72
|
-
|
|
97
|
+
self._logger(f"❌ Failed to apply stealth measures: {e}", "error")
|
|
73
98
|
self.stealth_applied = False
|
|
74
99
|
return False
|
|
75
100
|
|
|
@@ -77,11 +102,11 @@ class StealthManager:
|
|
|
77
102
|
"""Apply playwright-stealth with custom config"""
|
|
78
103
|
try:
|
|
79
104
|
# 🔥 WEBDRIVER ONLY CONFIG: Only remove webdriver, nothing else!
|
|
80
|
-
|
|
81
|
-
|
|
105
|
+
stealth_config = Stealth(
|
|
106
|
+
navigator_webdriver=True, # ONLY webdriver removal
|
|
82
107
|
chrome_runtime=False, # DISABLE - we do it ourselves
|
|
83
108
|
navigator_languages=False, # DISABLE - we do it ourselves
|
|
84
|
-
navigator_permissions=False, # DISABLE - we do it ourselves
|
|
109
|
+
navigator_permissions=False, # DISABLE - we do it ourselves
|
|
85
110
|
navigator_plugins=False, # DISABLE - we do it ourselves
|
|
86
111
|
webgl_vendor=False, # DISABLE - we do it ourselves
|
|
87
112
|
chrome_app=False, # DISABLE
|
|
@@ -92,21 +117,22 @@ class StealthManager:
|
|
|
92
117
|
navigator_user_agent=False, # DISABLE
|
|
93
118
|
navigator_vendor=False, # DISABLE
|
|
94
119
|
navigator_platform=False, # DISABLE
|
|
95
|
-
outerdimensions=False, # DISABLE
|
|
96
120
|
hairline=False, # DISABLE
|
|
121
|
+
sec_ch_ua=False, # DISABLE
|
|
122
|
+
navigator_hardware_concurrency=False, # DISABLE
|
|
97
123
|
)
|
|
98
124
|
|
|
99
|
-
await
|
|
100
|
-
|
|
125
|
+
await stealth(page, config=stealth_config)
|
|
126
|
+
self._logger("✅ Playwright-stealth applied with CUSTOM config", "info")
|
|
101
127
|
return True
|
|
102
128
|
except Exception as e:
|
|
103
|
-
|
|
129
|
+
self._logger(f"❌ playwright-stealth failed: {e}", "error")
|
|
104
130
|
return False
|
|
105
131
|
|
|
106
132
|
async def _remove_webdriver_property(self, page: Page) -> None:
|
|
107
133
|
"""Remove navigator.webdriver property - HANDLED BY PLAYWRIGHT-STEALTH"""
|
|
108
134
|
# 🔥 REDUNDANT: playwright-stealth already does this with webdriver=True
|
|
109
|
-
|
|
135
|
+
self._logger("✅ WebDriver property removal handled by playwright-stealth", "info")
|
|
110
136
|
|
|
111
137
|
async def _apply_custom_stealth_scripts(self, page: Page) -> None:
|
|
112
138
|
"""Apply custom stealth scripts"""
|
|
@@ -167,7 +193,7 @@ class StealthManager:
|
|
|
167
193
|
"""
|
|
168
194
|
await page.add_init_script(permissions_script)
|
|
169
195
|
|
|
170
|
-
|
|
196
|
+
self._logger("✅ Custom stealth scripts applied", "info")
|
|
171
197
|
|
|
172
198
|
async def _set_realistic_properties(self, page: Page) -> None:
|
|
173
199
|
"""Set realistic browser properties"""
|
|
@@ -192,7 +218,7 @@ class StealthManager:
|
|
|
192
218
|
});
|
|
193
219
|
"""
|
|
194
220
|
await page.add_init_script(realistic_script)
|
|
195
|
-
|
|
221
|
+
self._logger("✅ Realistic properties set", "info")
|
|
196
222
|
|
|
197
223
|
async def test_stealth_on_sannysoft(self, browser_manager) -> Dict[str, Any]:
|
|
198
224
|
"""
|
|
@@ -207,7 +233,7 @@ class StealthManager:
|
|
|
207
233
|
}
|
|
208
234
|
|
|
209
235
|
try:
|
|
210
|
-
|
|
236
|
+
self._logger("🧪 Testing stealth on bot.sannysoft.com...", "info")
|
|
211
237
|
|
|
212
238
|
# Navigate to test page
|
|
213
239
|
test_url = "https://bot.sannysoft.com/"
|
|
@@ -238,11 +264,9 @@ class StealthManager:
|
|
|
238
264
|
# Store results
|
|
239
265
|
self.test_results = test_results
|
|
240
266
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
f" Tests passed: {test_results.get('tests_passed', 0)}/{test_results.get('total_tests', 0)}"
|
|
245
|
-
)
|
|
267
|
+
self._logger("✅ Stealth test completed", "info")
|
|
268
|
+
self._logger(f" Detection score: {test_results.get('detection_score', 'Unknown')}", "info")
|
|
269
|
+
self._logger(f"Tests passed: {test_results.get('tests_passed', 0)}/{test_results.get('total_tests', 0)}")
|
|
246
270
|
|
|
247
271
|
return {
|
|
248
272
|
"success": True,
|
|
@@ -252,7 +276,7 @@ class StealthManager:
|
|
|
252
276
|
}
|
|
253
277
|
|
|
254
278
|
except Exception as e:
|
|
255
|
-
|
|
279
|
+
self._logger(f"❌ Stealth test failed: {e}", "error")
|
|
256
280
|
return {
|
|
257
281
|
"success": False,
|
|
258
282
|
"error": str(e),
|
|
@@ -303,37 +327,24 @@ class StealthManager:
|
|
|
303
327
|
return {
|
|
304
328
|
"stealth_applied": self.stealth_applied,
|
|
305
329
|
"test_results": self.test_results,
|
|
306
|
-
"playwright_stealth_available": self._check_playwright_stealth_available(),
|
|
307
330
|
}
|
|
308
331
|
|
|
309
|
-
def _check_playwright_stealth_available(self) -> bool:
|
|
310
|
-
"""Check if playwright-stealth is available"""
|
|
311
|
-
try:
|
|
312
|
-
import playwright_stealth
|
|
313
|
-
|
|
314
|
-
return True
|
|
315
|
-
except ImportError:
|
|
316
|
-
return False
|
|
317
|
-
|
|
318
332
|
def print_stealth_status(self) -> None:
|
|
319
333
|
"""Print current stealth status"""
|
|
320
334
|
status = self.get_stealth_status()
|
|
321
335
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
print(f" Playwright-stealth: {status['playwright_stealth_available']}")
|
|
336
|
+
self._logger("\n🥷 Stealth Status:", "info")
|
|
337
|
+
self._logger(f"Applied: {status['stealth_applied']}", "info")
|
|
325
338
|
|
|
326
339
|
if status["test_results"]:
|
|
327
340
|
results = status["test_results"]
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
f" Tests passed: {results.get('tests_passed', 0)}/{results.get('total_tests', 0)}"
|
|
331
|
-
)
|
|
341
|
+
self._logger(f" Last test score: {results.get('detection_score', 'Unknown')}", "info")
|
|
342
|
+
self._logger(f"Tests passed: {results.get('tests_passed', 0)}/{results.get('total_tests', 0)}")
|
|
332
343
|
|
|
333
344
|
async def apply_stealth_to_context(self, context: BrowserContext) -> bool:
|
|
334
345
|
"""Apply stealth measures to entire browser context"""
|
|
335
346
|
try:
|
|
336
|
-
|
|
347
|
+
self._logger("🥷 Applying stealth to browser context...", "info")
|
|
337
348
|
|
|
338
349
|
# SIMPLE OLD STYLE SCRIPT - exactly like working unrealparser!
|
|
339
350
|
stealth_script = """
|
|
@@ -343,15 +354,15 @@ class StealthManager:
|
|
|
343
354
|
"""
|
|
344
355
|
|
|
345
356
|
await context.add_init_script(stealth_script)
|
|
346
|
-
|
|
357
|
+
self._logger("✅ Context stealth script applied", "info")
|
|
347
358
|
|
|
348
359
|
return True
|
|
349
360
|
|
|
350
361
|
except Exception as e:
|
|
351
|
-
|
|
362
|
+
self._logger(f"❌ Failed to apply context stealth: {e}", "error")
|
|
352
363
|
return False
|
|
353
364
|
|
|
354
|
-
def apply_webdriver_removal(self, context) -> bool:
|
|
365
|
+
async def apply_webdriver_removal(self, context) -> bool:
|
|
355
366
|
"""
|
|
356
367
|
Remove navigator.webdriver property from context - OLD STYLE method like unrealparser
|
|
357
368
|
|
|
@@ -362,16 +373,16 @@ class StealthManager:
|
|
|
362
373
|
True if successful, False otherwise
|
|
363
374
|
"""
|
|
364
375
|
try:
|
|
365
|
-
#
|
|
366
|
-
context.add_init_script(
|
|
376
|
+
# Remove navigator.webdriver property before page creation - EXACTLY like old unrealparser
|
|
377
|
+
await context.add_init_script(
|
|
367
378
|
"""
|
|
368
379
|
if (navigator.webdriver !== undefined) {
|
|
369
380
|
delete Object.getPrototypeOf(navigator).webdriver;
|
|
370
381
|
}
|
|
371
382
|
"""
|
|
372
383
|
)
|
|
373
|
-
|
|
384
|
+
self._logger("✅ Webdriver removal script applied (OLD STYLE)", "info")
|
|
374
385
|
return True
|
|
375
386
|
except Exception as e:
|
|
376
|
-
|
|
387
|
+
self._logger(f"❌ Error applying webdriver removal: {e}", "error")
|
|
377
388
|
return False
|
unrealon_driver/__init__.py
CHANGED
|
@@ -14,12 +14,10 @@ Key Features:
|
|
|
14
14
|
- 🛡️ Type Safety: Full Pydantic v2 compliance
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
from
|
|
17
|
+
from unrealon import VersionInfo
|
|
18
|
+
|
|
19
|
+
__version__ = VersionInfo().version
|
|
18
20
|
|
|
19
|
-
try:
|
|
20
|
-
__version__ = version("unrealon")
|
|
21
|
-
except Exception:
|
|
22
|
-
__version__ = "1.1.1"
|
|
23
21
|
|
|
24
22
|
from .parser import (
|
|
25
23
|
ParserManager,
|
|
@@ -35,17 +33,13 @@ from .parser import (
|
|
|
35
33
|
ErrorManager,
|
|
36
34
|
RetryConfig,
|
|
37
35
|
ErrorInfo,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
LogLevel,
|
|
41
|
-
HTMLManager,
|
|
42
|
-
HTMLCleaningConfig,
|
|
43
|
-
BrowserManager,
|
|
44
|
-
BrowserConfig,
|
|
36
|
+
|
|
37
|
+
|
|
45
38
|
)
|
|
46
39
|
from .exceptions import ParserError, BrowserError
|
|
47
40
|
|
|
48
41
|
__all__ = [
|
|
42
|
+
"__version__",
|
|
49
43
|
# Main Parser Manager
|
|
50
44
|
"ParserManager",
|
|
51
45
|
"ParserManagerConfig",
|
|
@@ -61,13 +55,8 @@ __all__ = [
|
|
|
61
55
|
"ErrorManager",
|
|
62
56
|
"RetryConfig",
|
|
63
57
|
"ErrorInfo",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"LogLevel",
|
|
67
|
-
"HTMLManager",
|
|
68
|
-
"HTMLCleaningConfig",
|
|
69
|
-
"BrowserManager",
|
|
70
|
-
"BrowserConfig",
|
|
58
|
+
|
|
59
|
+
|
|
71
60
|
# Exceptions
|
|
72
61
|
"ParserError",
|
|
73
62
|
"BrowserError",
|
|
@@ -76,5 +65,3 @@ __all__ = [
|
|
|
76
65
|
]
|
|
77
66
|
# Convenience aliases for backward compatibility
|
|
78
67
|
Parser = ParserManager
|
|
79
|
-
DriverLogger = LoggingManager
|
|
80
|
-
get_driver_logger = LoggingManager
|
unrealon_driver/exceptions.py
CHANGED
|
@@ -5,24 +5,29 @@ UnrealOn Driver exceptions
|
|
|
5
5
|
|
|
6
6
|
class ParserError(Exception):
|
|
7
7
|
"""Base exception for parser errors"""
|
|
8
|
+
|
|
8
9
|
pass
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class BrowserError(ParserError):
|
|
12
13
|
"""Browser-related errors"""
|
|
14
|
+
|
|
13
15
|
pass
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
class HTMLCleaningError(ParserError):
|
|
17
19
|
"""HTML cleaning errors"""
|
|
20
|
+
|
|
18
21
|
pass
|
|
19
22
|
|
|
20
23
|
|
|
21
24
|
class ConfigurationError(ParserError):
|
|
22
25
|
"""Configuration errors"""
|
|
26
|
+
|
|
23
27
|
pass
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
class ConnectionError(ParserError):
|
|
27
31
|
"""Connection errors"""
|
|
32
|
+
|
|
28
33
|
pass
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HTML Analyzer module for unrealon_driver.
|
|
3
|
+
|
|
4
|
+
Provides intelligent HTML processing, cleaning, and analysis with WebSocket communication.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .manager import HTMLAnalyzer, create_html_analyzer
|
|
8
|
+
from .config import HTMLAnalyzerConfig, HTMLCleaningConfig
|
|
9
|
+
from .cleaner import HTMLCleaner, HTMLCleaningStats
|
|
10
|
+
from .websocket_analyzer import WebSocketHTMLAnalyzer
|
|
11
|
+
from .models import HTMLAnalysisResult, HTMLParseResult, HTMLAnalyzerStats, HTMLAnalysisRequest, HTMLParseRequest, HTMLAnalyzerError, HTMLCleaningError, HTMLAnalysisError, WebSocketAnalysisError
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HTMLAnalyzer",
|
|
15
|
+
"HTMLAnalyzerConfig",
|
|
16
|
+
"HTMLCleaningConfig",
|
|
17
|
+
"HTMLCleaningStats",
|
|
18
|
+
"HTMLCleaner",
|
|
19
|
+
"WebSocketHTMLAnalyzer",
|
|
20
|
+
"create_html_analyzer",
|
|
21
|
+
# Models
|
|
22
|
+
"HTMLAnalysisResult",
|
|
23
|
+
"HTMLParseResult",
|
|
24
|
+
"HTMLAnalyzerStats",
|
|
25
|
+
"HTMLAnalysisRequest",
|
|
26
|
+
"HTMLParseRequest",
|
|
27
|
+
# Exceptions
|
|
28
|
+
"HTMLAnalyzerError",
|
|
29
|
+
"HTMLCleaningError",
|
|
30
|
+
"HTMLAnalysisError",
|
|
31
|
+
"WebSocketAnalysisError",
|
|
32
|
+
]
|