unrealon 1.1.6__tar.gz → 2.0.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.
- {unrealon-1.1.6 → unrealon-2.0.4}/LICENSE +1 -1
- unrealon-2.0.4/MANIFEST.in +99 -0
- unrealon-2.0.4/PKG-INFO +491 -0
- unrealon-2.0.4/README.md +391 -0
- unrealon-2.0.4/pyproject.toml +164 -0
- unrealon-2.0.4/setup.cfg +4 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/__init__.py +5 -6
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/cli/browser_cli.py +18 -9
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/cli/interactive_mode.py +13 -4
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/core/browser_manager.py +29 -16
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/__init__.py +21 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +175 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/config.py +9 -3
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/__init__.py +1 -1
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/logger_bridge.py +1 -4
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/__init__.py +27 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.pyc +0 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/manager.pyc +0 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.pyc +0 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.pyc +0 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.pyc +0 -0
- unrealon-2.0.4/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.pyc +0 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/__init__.py +160 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/config/__init__.py +16 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/config/environment.py +98 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/config/urls.py +93 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/enums/__init__.py +24 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/enums/status.py +216 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/enums/types.py +240 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/error_handling/__init__.py +45 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +292 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/error_handling/error_context.py +324 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/error_handling/recovery.py +371 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/error_handling/retry.py +268 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/__init__.py +46 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/base.py +292 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/communication.py +22 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/driver.py +11 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/proxy.py +11 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/task.py +12 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/exceptions/validation.py +17 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/__init__.py +98 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/arq_context.py +252 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/arq_responses.py +125 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/base.py +291 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/bridge_stats.py +58 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/communication.py +39 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/config.py +47 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/connection_stats.py +47 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/driver.py +30 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/driver_details.py +98 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/logging.py +28 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/task.py +21 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/typed_responses.py +210 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/__init__.py +91 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/base.py +49 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/config.py +200 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/driver.py +215 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/errors.py +138 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +100 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/logging.py +261 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/proxy.py +496 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/tasks.py +275 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket/utils.py +153 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/models/websocket_session.py +144 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/monitoring/__init__.py +43 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/monitoring/alerts.py +398 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/monitoring/dashboard.py +307 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/monitoring/health_check.py +354 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/monitoring/metrics.py +352 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/utils/__init__.py +11 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/utils/time.py +61 -0
- unrealon-2.0.4/unrealon-core/src/unrealon_core/version.py +219 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/__init__.py +105 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/__init__.py +34 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/base.py +184 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/config.py +30 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +127 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/protocols.py +98 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/core_module/registry.py +146 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/decorators/__init__.py +15 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/decorators/retry.py +117 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/decorators/schedule.py +137 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/decorators/task.py +61 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/decorators/timing.py +132 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/__init__.py +20 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +10 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/communication/session.py +203 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +197 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +10 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/core/config.py +85 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/core/driver.py +221 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +9 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +130 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +11 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +76 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +97 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +48 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +9 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +63 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +10 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +51 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +61 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/__init__.py +32 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/base.py +174 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/browser.py +98 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/cache.py +116 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/http.py +107 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/logger.py +286 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/proxy.py +99 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/registry.py +87 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/threading.py +54 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/managers/update.py +107 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/utils/__init__.py +9 -0
- unrealon-2.0.4/unrealon-driver/src/unrealon_driver/utils/time.py +10 -0
- unrealon-2.0.4/unrealon.egg-info/PKG-INFO +491 -0
- unrealon-2.0.4/unrealon.egg-info/SOURCES.txt +133 -0
- unrealon-2.0.4/unrealon.egg-info/dependency_links.txt +1 -0
- unrealon-2.0.4/unrealon.egg-info/entry_points.txt +3 -0
- unrealon-2.0.4/unrealon.egg-info/requires.txt +80 -0
- unrealon-2.0.4/unrealon.egg-info/top_level.txt +3 -0
- unrealon-1.1.6/.gitignore +0 -350
- unrealon-1.1.6/MANIFEST.in +0 -50
- unrealon-1.1.6/PKG-INFO +0 -625
- unrealon-1.1.6/README.md +0 -533
- unrealon-1.1.6/pyproject.toml +0 -346
- unrealon-1.1.6/requirements-dev.txt +0 -46
- unrealon-1.1.6/requirements-test.txt +0 -34
- unrealon-1.1.6/requirements.txt +0 -28
- unrealon-1.1.6/src/unrealon_browser/managers/stealth.py +0 -388
- unrealon-1.1.6/src/unrealon_driver/README.md +0 -0
- unrealon-1.1.6/src/unrealon_driver/__init__.py +0 -66
- unrealon-1.1.6/src/unrealon_driver/exceptions.py +0 -33
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/__init__.py +0 -32
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/cleaner.py +0 -657
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/config.py +0 -64
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/manager.py +0 -247
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/models.py +0 -115
- unrealon-1.1.6/src/unrealon_driver/html_analyzer/websocket_analyzer.py +0 -157
- unrealon-1.1.6/src/unrealon_driver/models/__init__.py +0 -31
- unrealon-1.1.6/src/unrealon_driver/models/websocket.py +0 -98
- unrealon-1.1.6/src/unrealon_driver/parser/__init__.py +0 -36
- unrealon-1.1.6/src/unrealon_driver/parser/cli_manager.py +0 -142
- unrealon-1.1.6/src/unrealon_driver/parser/daemon_manager.py +0 -403
- unrealon-1.1.6/src/unrealon_driver/parser/managers/__init__.py +0 -25
- unrealon-1.1.6/src/unrealon_driver/parser/managers/config.py +0 -293
- unrealon-1.1.6/src/unrealon_driver/parser/managers/error.py +0 -412
- unrealon-1.1.6/src/unrealon_driver/parser/managers/result.py +0 -321
- unrealon-1.1.6/src/unrealon_driver/parser/parser_manager.py +0 -458
- unrealon-1.1.6/src/unrealon_driver/smart_logging/__init__.py +0 -24
- unrealon-1.1.6/src/unrealon_driver/smart_logging/models.py +0 -44
- unrealon-1.1.6/src/unrealon_driver/smart_logging/smart_logger.py +0 -406
- unrealon-1.1.6/src/unrealon_driver/smart_logging/unified_logger.py +0 -525
- unrealon-1.1.6/src/unrealon_driver/websocket/__init__.py +0 -31
- unrealon-1.1.6/src/unrealon_driver/websocket/client.py +0 -249
- unrealon-1.1.6/src/unrealon_driver/websocket/config.py +0 -188
- unrealon-1.1.6/src/unrealon_driver/websocket/manager.py +0 -90
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/README.md +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/cli/__init__.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/cli/cookies_cli.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/cli/main.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/core/__init__.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/core.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/dataclasses.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/detection.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/enums.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/dto/models/statistics.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/captcha.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/cookies.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/page_wait_manager.py +0 -0
- {unrealon-1.1.6 → unrealon-2.0.4/unrealon-browser}/src/unrealon_browser/managers/profile.py +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include pyproject.toml
|
|
4
|
+
|
|
5
|
+
# Include all source files from submodules
|
|
6
|
+
recursive-include unrealon-core/src *.py
|
|
7
|
+
recursive-include unrealon-driver/src *.py
|
|
8
|
+
|
|
9
|
+
# Include browser files (except stealth .py files)
|
|
10
|
+
recursive-include unrealon-browser/src *.py
|
|
11
|
+
exclude unrealon-browser/src/unrealon_browser/stealth/*.py
|
|
12
|
+
|
|
13
|
+
# Include only protected stealth files (.pyc) and __init__.py
|
|
14
|
+
include unrealon-browser/src/unrealon_browser/stealth/*.pyc
|
|
15
|
+
include unrealon-browser/src/unrealon_browser/stealth/__init__.py
|
|
16
|
+
|
|
17
|
+
# Exclude development files (but not stealth .pyc files)
|
|
18
|
+
recursive-exclude unrealon-core *.pyc
|
|
19
|
+
recursive-exclude unrealon-driver *.pyc
|
|
20
|
+
recursive-exclude unrealon-browser/src/unrealon_browser/cli *.pyc
|
|
21
|
+
recursive-exclude unrealon-browser/src/unrealon_browser/core *.pyc
|
|
22
|
+
recursive-exclude unrealon-browser/src/unrealon_browser/dto *.pyc
|
|
23
|
+
recursive-exclude unrealon-browser/src/unrealon_browser/managers *.pyc
|
|
24
|
+
recursive-exclude . __pycache__
|
|
25
|
+
recursive-exclude . *.pyo
|
|
26
|
+
recursive-exclude . *.orig
|
|
27
|
+
recursive-exclude . *.rej
|
|
28
|
+
|
|
29
|
+
# Exclude test files
|
|
30
|
+
recursive-exclude . test_*
|
|
31
|
+
recursive-exclude . *_test.py
|
|
32
|
+
recursive-exclude . tests
|
|
33
|
+
recursive-exclude . */tests
|
|
34
|
+
recursive-exclude . */tests/*
|
|
35
|
+
recursive-exclude . tests/*
|
|
36
|
+
|
|
37
|
+
# Exclude all @ folders (including examples)
|
|
38
|
+
global-exclude @*
|
|
39
|
+
recursive-exclude . @*
|
|
40
|
+
recursive-exclude . @examples
|
|
41
|
+
recursive-exclude . @docs
|
|
42
|
+
recursive-exclude . @old
|
|
43
|
+
|
|
44
|
+
# Exclude cache files
|
|
45
|
+
recursive-exclude . __pycache__
|
|
46
|
+
recursive-exclude . *.py[co]
|
|
47
|
+
recursive-exclude . .coverage
|
|
48
|
+
recursive-exclude . htmlcov
|
|
49
|
+
recursive-exclude . .pytest_cache
|
|
50
|
+
|
|
51
|
+
# Exclude virtual environments
|
|
52
|
+
recursive-exclude . .venv
|
|
53
|
+
recursive-exclude . .venv/*
|
|
54
|
+
global-exclude .venv
|
|
55
|
+
global-exclude .venv/*
|
|
56
|
+
exclude unrealon-browser/src/unrealon_browser/.venv
|
|
57
|
+
recursive-exclude unrealon-browser/src/unrealon_browser/.venv *
|
|
58
|
+
|
|
59
|
+
# Exclude system files
|
|
60
|
+
recursive-exclude . .DS_Store
|
|
61
|
+
recursive-exclude . Thumbs.db
|
|
62
|
+
|
|
63
|
+
# Exclude development and build files
|
|
64
|
+
exclude setup.py
|
|
65
|
+
exclude setup.cfg
|
|
66
|
+
exclude pytest.ini
|
|
67
|
+
exclude *.lock
|
|
68
|
+
exclude package*.json
|
|
69
|
+
exclude .env*
|
|
70
|
+
exclude poetry.lock
|
|
71
|
+
exclude test.log
|
|
72
|
+
exclude *.log
|
|
73
|
+
exclude Makefile
|
|
74
|
+
exclude .pre-commit-config.yaml
|
|
75
|
+
exclude .secrets.baseline
|
|
76
|
+
|
|
77
|
+
# Exclude only root CLI (development tools), but keep unrealon-browser CLI (user commands)
|
|
78
|
+
exclude cli
|
|
79
|
+
recursive-exclude cli *
|
|
80
|
+
|
|
81
|
+
# Exclude browser automation artifacts
|
|
82
|
+
recursive-exclude . browser_profiles
|
|
83
|
+
recursive-exclude . cookies
|
|
84
|
+
recursive-exclude . screenshots
|
|
85
|
+
recursive-exclude . downloads
|
|
86
|
+
recursive-exclude . profiles
|
|
87
|
+
|
|
88
|
+
# Exclude logs and temporary files
|
|
89
|
+
recursive-exclude . logs
|
|
90
|
+
recursive-exclude . tmp
|
|
91
|
+
recursive-exclude . temp
|
|
92
|
+
recursive-exclude . *.tmp
|
|
93
|
+
recursive-exclude . *.temp
|
|
94
|
+
|
|
95
|
+
# Exclude IDE files
|
|
96
|
+
recursive-exclude . .idea
|
|
97
|
+
recursive-exclude . .vscode
|
|
98
|
+
recursive-exclude . *.swp
|
|
99
|
+
recursive-exclude . *.swo
|
unrealon-2.0.4/PKG-INFO
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: unrealon
|
|
3
|
+
Version: 2.0.4
|
|
4
|
+
Summary: Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities
|
|
5
|
+
Author-email: UnrealOn Team <team@unrealon.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://unrealon.com
|
|
8
|
+
Project-URL: Repository, https://github.com/markolofsen/unrealon-parser-amazon
|
|
9
|
+
Project-URL: Documentation, https://unrealon.com
|
|
10
|
+
Keywords: web-scraping,automation,ai,browser,driver,parsing,orchestration
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Requires-Python: <4.0,>=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
26
|
+
Requires-Dist: selenium>=4.15.0
|
|
27
|
+
Requires-Dist: playwright>=1.40.0
|
|
28
|
+
Requires-Dist: undetected-chromedriver>=3.5.0
|
|
29
|
+
Requires-Dist: fake-useragent>=1.4.0
|
|
30
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
31
|
+
Requires-Dist: click>=8.1.0
|
|
32
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
33
|
+
Requires-Dist: httpx>=0.23.0
|
|
34
|
+
Requires-Dist: beautifulsoup4>=4.13.5
|
|
35
|
+
Requires-Dist: pydantic-yaml>=1.6.0
|
|
36
|
+
Requires-Dist: rich>=13.0.0
|
|
37
|
+
Requires-Dist: pyyaml>=6.0
|
|
38
|
+
Requires-Dist: python-socketio>=5.0
|
|
39
|
+
Requires-Dist: python-dateutil>=2.8
|
|
40
|
+
Requires-Dist: playwright-stealth>=2.0.0
|
|
41
|
+
Requires-Dist: questionary>=2.0.0
|
|
42
|
+
Requires-Dist: asyncio-extras>=1.3.0
|
|
43
|
+
Requires-Dist: pathlib2>=2.3.0
|
|
44
|
+
Requires-Dist: openai>=1.0.0
|
|
45
|
+
Requires-Dist: tiktoken>=0.9.0
|
|
46
|
+
Requires-Dist: fast-langdetect>=0.3.2
|
|
47
|
+
Requires-Dist: langid>=1.1.6
|
|
48
|
+
Requires-Dist: langdetect>=1.0.9
|
|
49
|
+
Requires-Dist: cachetools>=5.3.0
|
|
50
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
51
|
+
Requires-Dist: tomlkit>=0.13.3
|
|
52
|
+
Provides-Extra: dev
|
|
53
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
54
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
55
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
56
|
+
Requires-Dist: pytest-mock>=3.12.0; extra == "dev"
|
|
57
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
|
|
58
|
+
Requires-Dist: pytest-html>=4.0.0; extra == "dev"
|
|
59
|
+
Requires-Dist: pytest-xdist>=3.3.0; extra == "dev"
|
|
60
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == "dev"
|
|
61
|
+
Requires-Dist: pytest-playwright>=0.4.0; extra == "dev"
|
|
62
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
63
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
64
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
65
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
66
|
+
Requires-Dist: build>=1.0.0; extra == "dev"
|
|
67
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
68
|
+
Requires-Dist: questionary>=2.1.0; extra == "dev"
|
|
69
|
+
Requires-Dist: tomlkit>=0.13.3; extra == "dev"
|
|
70
|
+
Requires-Dist: bandit>=1.7.5; extra == "dev"
|
|
71
|
+
Requires-Dist: safety>=2.3.0; extra == "dev"
|
|
72
|
+
Requires-Dist: pylint>=2.17.0; extra == "dev"
|
|
73
|
+
Requires-Dist: locust>=2.0.0; extra == "dev"
|
|
74
|
+
Requires-Dist: responses>=0.23.0; extra == "dev"
|
|
75
|
+
Requires-Dist: aioresponses>=0.7.4; extra == "dev"
|
|
76
|
+
Requires-Dist: pre-commit>=3.3.0; extra == "dev"
|
|
77
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
78
|
+
Requires-Dist: types-python-dateutil>=2.8; extra == "dev"
|
|
79
|
+
Provides-Extra: browser
|
|
80
|
+
Requires-Dist: selenium>=4.15.0; extra == "browser"
|
|
81
|
+
Requires-Dist: playwright>=1.40.0; extra == "browser"
|
|
82
|
+
Requires-Dist: undetected-chromedriver>=3.5.0; extra == "browser"
|
|
83
|
+
Requires-Dist: playwright-stealth>=2.0.0; extra == "browser"
|
|
84
|
+
Provides-Extra: ai
|
|
85
|
+
Requires-Dist: openai>=1.0.0; extra == "ai"
|
|
86
|
+
Requires-Dist: tiktoken>=0.9.0; extra == "ai"
|
|
87
|
+
Requires-Dist: fast-langdetect>=0.3.2; extra == "ai"
|
|
88
|
+
Requires-Dist: langid>=1.1.6; extra == "ai"
|
|
89
|
+
Requires-Dist: langdetect>=1.0.9; extra == "ai"
|
|
90
|
+
Provides-Extra: full
|
|
91
|
+
Requires-Dist: selenium>=4.15.0; extra == "full"
|
|
92
|
+
Requires-Dist: playwright>=1.40.0; extra == "full"
|
|
93
|
+
Requires-Dist: undetected-chromedriver>=3.5.0; extra == "full"
|
|
94
|
+
Requires-Dist: playwright-stealth>=2.0.0; extra == "full"
|
|
95
|
+
Requires-Dist: openai>=1.0.0; extra == "full"
|
|
96
|
+
Requires-Dist: tiktoken>=0.9.0; extra == "full"
|
|
97
|
+
Requires-Dist: fast-langdetect>=0.3.2; extra == "full"
|
|
98
|
+
Requires-Dist: langid>=1.1.6; extra == "full"
|
|
99
|
+
Requires-Dist: langdetect>=1.0.9; extra == "full"
|
|
100
|
+
|
|
101
|
+
# 🚀 UnrealOn v2.0
|
|
102
|
+
|
|
103
|
+
**The easiest way to build production-ready web scrapers in Python.**
|
|
104
|
+
|
|
105
|
+
[](https://badge.fury.io/py/unrealon)
|
|
106
|
+
[](https://www.python.org/downloads/)
|
|
107
|
+
[](https://opensource.org/licenses/MIT)
|
|
108
|
+
|
|
109
|
+
## 🎯 Why UnrealOn?
|
|
110
|
+
|
|
111
|
+
**Stop fighting infrastructure. Start building parsers.**
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# Just focus on YOUR parsing logic
|
|
115
|
+
class MyParser:
|
|
116
|
+
def __init__(self, driver):
|
|
117
|
+
self.driver = driver
|
|
118
|
+
|
|
119
|
+
async def parse_products(self, url: str):
|
|
120
|
+
html = await self.driver.http.get_html(url) # Auto proxy, retries, etc.
|
|
121
|
+
soup = BeautifulSoup(html, 'html.parser')
|
|
122
|
+
|
|
123
|
+
products = []
|
|
124
|
+
for item in soup.select('.product'):
|
|
125
|
+
products.append({
|
|
126
|
+
'title': item.select_one('.title').text,
|
|
127
|
+
'price': item.select_one('.price').text
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
return products # Auto-saved, logged, monitored
|
|
131
|
+
|
|
132
|
+
# Everything else is handled automatically!
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**What you get for free:**
|
|
136
|
+
- ✅ **HTTP Client** with proxy rotation, retries, rate limiting
|
|
137
|
+
- ✅ **Browser Automation** with stealth mode and anti-detection
|
|
138
|
+
- ✅ **Error Handling** with automatic retries and graceful failures
|
|
139
|
+
- ✅ **Logging & Monitoring** with structured logs and performance metrics
|
|
140
|
+
- ✅ **CLI Interface** auto-generated from your parser methods
|
|
141
|
+
- ✅ **Configuration** with YAML files and validation
|
|
142
|
+
- ✅ **Production Deployment** with RPC server integration
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 📦 Installation
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
pip install unrealon
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
That's it! No complex setup, no configuration files to write.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 🚀 Quick Start
|
|
157
|
+
|
|
158
|
+
### 1. Create Your Parser
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# my_parser.py
|
|
162
|
+
from unrealon_driver import UniversalDriver, DriverConfig
|
|
163
|
+
from bs4 import BeautifulSoup
|
|
164
|
+
|
|
165
|
+
class MyWebsiteParser:
|
|
166
|
+
def __init__(self, driver: UniversalDriver):
|
|
167
|
+
self.driver = driver
|
|
168
|
+
|
|
169
|
+
async def parse_products(self, search_query: str):
|
|
170
|
+
"""Parse products from search results."""
|
|
171
|
+
|
|
172
|
+
# UnrealOn handles all the HTTP complexity
|
|
173
|
+
url = f"https://example.com/search?q={search_query}"
|
|
174
|
+
html = await self.driver.http.get_html(url)
|
|
175
|
+
|
|
176
|
+
# Focus on YOUR parsing logic
|
|
177
|
+
soup = BeautifulSoup(html, 'html.parser')
|
|
178
|
+
products = []
|
|
179
|
+
|
|
180
|
+
for item in soup.select('.product-item'):
|
|
181
|
+
product = {
|
|
182
|
+
'title': item.select_one('.title').text.strip(),
|
|
183
|
+
'price': item.select_one('.price').text.strip(),
|
|
184
|
+
'url': item.select_one('a')['href']
|
|
185
|
+
}
|
|
186
|
+
products.append(product)
|
|
187
|
+
|
|
188
|
+
# Results are automatically saved and logged
|
|
189
|
+
await self.driver.logger.info(f"Found {len(products)} products")
|
|
190
|
+
return products
|
|
191
|
+
|
|
192
|
+
# Setup (one time)
|
|
193
|
+
config = DriverConfig.for_development("my_parser")
|
|
194
|
+
driver = UniversalDriver(config)
|
|
195
|
+
parser = MyWebsiteParser(driver)
|
|
196
|
+
|
|
197
|
+
# Use it
|
|
198
|
+
await driver.initialize()
|
|
199
|
+
results = await parser.parse_products("laptop")
|
|
200
|
+
print(f"Found {len(results)} products!")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 2. Add CLI Interface (Optional)
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
# cli.py
|
|
207
|
+
import click
|
|
208
|
+
from my_parser import MyWebsiteParser, driver
|
|
209
|
+
|
|
210
|
+
@click.command()
|
|
211
|
+
@click.option('--query', required=True, help='Search query')
|
|
212
|
+
@click.option('--limit', default=10, help='Max results')
|
|
213
|
+
def search(query: str, limit: int):
|
|
214
|
+
"""Search for products."""
|
|
215
|
+
|
|
216
|
+
async def run():
|
|
217
|
+
await driver.initialize()
|
|
218
|
+
parser = MyWebsiteParser(driver)
|
|
219
|
+
results = await parser.parse_products(query)
|
|
220
|
+
|
|
221
|
+
for i, product in enumerate(results[:limit], 1):
|
|
222
|
+
print(f"{i}. {product['title']} - {product['price']}")
|
|
223
|
+
|
|
224
|
+
await driver.shutdown()
|
|
225
|
+
|
|
226
|
+
import asyncio
|
|
227
|
+
asyncio.run(run())
|
|
228
|
+
|
|
229
|
+
if __name__ == '__main__':
|
|
230
|
+
search()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# Now you have a CLI!
|
|
235
|
+
python cli.py search --query "laptop" --limit 5
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### 3. Production Deployment (Optional)
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
# For production, just add RPC task decorators
|
|
242
|
+
class ProductionParser(UniversalDriver):
|
|
243
|
+
def __init__(self):
|
|
244
|
+
super().__init__(DriverConfig.for_production("my_parser"))
|
|
245
|
+
self.parser = MyWebsiteParser(self)
|
|
246
|
+
|
|
247
|
+
@self.task("parse_products") # Auto-registered RPC task
|
|
248
|
+
async def parse_products_task(self, task_data):
|
|
249
|
+
query = task_data.parameters['query']
|
|
250
|
+
results = await self.parser.parse_products(query)
|
|
251
|
+
|
|
252
|
+
return TaskResultData(
|
|
253
|
+
task_id=task_data.task_id,
|
|
254
|
+
status="completed",
|
|
255
|
+
result=results
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
# Deploy and scale automatically!
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 🎨 Features
|
|
264
|
+
|
|
265
|
+
### 🔧 HTTP Client (Built-in)
|
|
266
|
+
```python
|
|
267
|
+
# All of this is handled automatically:
|
|
268
|
+
html = await driver.http.get_html(url)
|
|
269
|
+
# ✅ Proxy rotation
|
|
270
|
+
# ✅ User-Agent rotation
|
|
271
|
+
# ✅ Automatic retries
|
|
272
|
+
# ✅ Rate limiting
|
|
273
|
+
# ✅ Cookie management
|
|
274
|
+
# ✅ Session persistence
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 🌐 Browser Automation (Built-in)
|
|
278
|
+
```python
|
|
279
|
+
# When you need a real browser:
|
|
280
|
+
page = await driver.browser.get_page(url)
|
|
281
|
+
await page.click('.load-more')
|
|
282
|
+
html = await page.content()
|
|
283
|
+
# ✅ Stealth mode
|
|
284
|
+
# ✅ Anti-detection
|
|
285
|
+
# ✅ JavaScript execution
|
|
286
|
+
# ✅ Screenshot capture
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 📊 Monitoring & Logging (Built-in)
|
|
290
|
+
```python
|
|
291
|
+
# Structured logging that just works:
|
|
292
|
+
await driver.logger.info("Starting parse", extra={
|
|
293
|
+
'url': url,
|
|
294
|
+
'products_found': len(products)
|
|
295
|
+
})
|
|
296
|
+
# ✅ Centralized logging
|
|
297
|
+
# ✅ Performance metrics
|
|
298
|
+
# ✅ Error tracking
|
|
299
|
+
# ✅ Real-time monitoring
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### ⚙️ Configuration (Built-in)
|
|
303
|
+
```yaml
|
|
304
|
+
# config.yaml - Simple YAML configuration
|
|
305
|
+
parser:
|
|
306
|
+
name: "My Parser"
|
|
307
|
+
max_pages: 10
|
|
308
|
+
|
|
309
|
+
http:
|
|
310
|
+
request_delay: 1.0
|
|
311
|
+
max_retries: 3
|
|
312
|
+
|
|
313
|
+
output:
|
|
314
|
+
format: json
|
|
315
|
+
directory: ./results
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 🚀 Production Scaling (Built-in)
|
|
319
|
+
```python
|
|
320
|
+
# Scale to multiple instances automatically
|
|
321
|
+
@driver.task("parse_category")
|
|
322
|
+
async def parse_category_task(self, task_data):
|
|
323
|
+
# This runs on any available parser instance
|
|
324
|
+
category = task_data.parameters['category']
|
|
325
|
+
return await self.parse_category(category)
|
|
326
|
+
|
|
327
|
+
# Deploy multiple instances, they auto-coordinate!
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## 📚 Examples
|
|
333
|
+
|
|
334
|
+
### E-commerce Parser
|
|
335
|
+
```python
|
|
336
|
+
class EcommerceParser:
|
|
337
|
+
async def parse_product(self, product_url: str):
|
|
338
|
+
html = await self.driver.http.get_html(product_url)
|
|
339
|
+
soup = BeautifulSoup(html, 'html.parser')
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
'title': soup.select_one('h1').text,
|
|
343
|
+
'price': soup.select_one('.price').text,
|
|
344
|
+
'description': soup.select_one('.description').text,
|
|
345
|
+
'images': [img['src'] for img in soup.select('.gallery img')]
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### News Scraper
|
|
350
|
+
```python
|
|
351
|
+
class NewsParser:
|
|
352
|
+
async def parse_articles(self, category: str):
|
|
353
|
+
url = f"https://news-site.com/{category}"
|
|
354
|
+
html = await self.driver.http.get_html(url)
|
|
355
|
+
soup = BeautifulSoup(html, 'html.parser')
|
|
356
|
+
|
|
357
|
+
articles = []
|
|
358
|
+
for article in soup.select('.article'):
|
|
359
|
+
articles.append({
|
|
360
|
+
'headline': article.select_one('.headline').text,
|
|
361
|
+
'summary': article.select_one('.summary').text,
|
|
362
|
+
'published': article.select_one('.date').text,
|
|
363
|
+
'url': article.select_one('a')['href']
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
return articles
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Real Estate Listings
|
|
370
|
+
```python
|
|
371
|
+
class RealEstateParser:
|
|
372
|
+
async def parse_listings(self, city: str, max_price: int):
|
|
373
|
+
url = f"https://realestate.com/search?city={city}&max_price={max_price}"
|
|
374
|
+
|
|
375
|
+
# Use browser for JavaScript-heavy sites
|
|
376
|
+
page = await self.driver.browser.get_page(url)
|
|
377
|
+
await page.wait_for_selector('.listing')
|
|
378
|
+
|
|
379
|
+
listings = await page.evaluate('''
|
|
380
|
+
() => Array.from(document.querySelectorAll('.listing')).map(listing => ({
|
|
381
|
+
address: listing.querySelector('.address').textContent,
|
|
382
|
+
price: listing.querySelector('.price').textContent,
|
|
383
|
+
bedrooms: listing.querySelector('.bedrooms').textContent,
|
|
384
|
+
url: listing.querySelector('a').href
|
|
385
|
+
}))
|
|
386
|
+
''')
|
|
387
|
+
|
|
388
|
+
return listings
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 🆚 Why Not Scrapy/BeautifulSoup/Selenium?
|
|
394
|
+
|
|
395
|
+
| Feature | UnrealOn | Scrapy | BeautifulSoup + Requests | Selenium |
|
|
396
|
+
|---------|----------|--------|-------------------------|----------|
|
|
397
|
+
| **Setup Time** | ✅ 5 minutes | ❌ Hours | ❌ Hours | ❌ Hours |
|
|
398
|
+
| **Proxy Rotation** | ✅ Built-in | ❌ Manual setup | ❌ Manual setup | ❌ Manual setup |
|
|
399
|
+
| **Anti-Detection** | ✅ Built-in | ❌ Manual setup | ❌ Manual setup | ❌ Partial |
|
|
400
|
+
| **Error Handling** | ✅ Built-in | ❌ Manual setup | ❌ Manual setup | ❌ Manual setup |
|
|
401
|
+
| **Monitoring** | ✅ Built-in | ❌ Manual setup | ❌ Manual setup | ❌ Manual setup |
|
|
402
|
+
| **CLI Generation** | ✅ Automatic | ❌ Manual | ❌ Manual | ❌ Manual |
|
|
403
|
+
| **Production Deploy** | ✅ Built-in | ❌ Complex | ❌ Very complex | ❌ Very complex |
|
|
404
|
+
| **Learning Curve** | ✅ Minimal | ❌ Steep | ❌ Medium | ❌ Steep |
|
|
405
|
+
|
|
406
|
+
**UnrealOn = All the power, none of the setup.**
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## 🛠️ Advanced Features
|
|
411
|
+
|
|
412
|
+
### Type-Safe Data Models
|
|
413
|
+
```python
|
|
414
|
+
from pydantic import BaseModel
|
|
415
|
+
from typing import Optional
|
|
416
|
+
|
|
417
|
+
class Product(BaseModel):
|
|
418
|
+
title: str
|
|
419
|
+
price: Optional[float] = None
|
|
420
|
+
url: str
|
|
421
|
+
in_stock: bool = True
|
|
422
|
+
|
|
423
|
+
# Automatic validation and serialization
|
|
424
|
+
product = Product(title="Laptop", price=999.99, url="https://...")
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Scheduled Tasks
|
|
428
|
+
```python
|
|
429
|
+
@driver.schedule("0 */6 * * *") # Every 6 hours
|
|
430
|
+
async def monitor_prices():
|
|
431
|
+
"""Monitor price changes automatically."""
|
|
432
|
+
products = await parser.parse_products("laptop")
|
|
433
|
+
# Check for price drops, send alerts, etc.
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Batch Processing
|
|
437
|
+
```python
|
|
438
|
+
async def parse_multiple_categories():
|
|
439
|
+
categories = ["electronics", "books", "clothing"]
|
|
440
|
+
|
|
441
|
+
# Process all categories concurrently
|
|
442
|
+
tasks = [parser.parse_category(cat) for cat in categories]
|
|
443
|
+
results = await driver.threads.submit_batch(tasks, max_workers=3)
|
|
444
|
+
|
|
445
|
+
return results
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 🚀 Getting Started
|
|
451
|
+
|
|
452
|
+
1. **Install**: `pip install unrealon`
|
|
453
|
+
2. **Create parser**: Write your parsing logic (focus on the scraping, not infrastructure)
|
|
454
|
+
3. **Run**: `python my_parser.py`
|
|
455
|
+
4. **Scale**: Add `@driver.task` decorators for production
|
|
456
|
+
|
|
457
|
+
### Complete Example Repository
|
|
458
|
+
- **[Amazon Parser](https://github.com/markolofsen/unrealon-parser-amazon)** - Production-ready Amazon scraper
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 📚 Documentation
|
|
463
|
+
|
|
464
|
+
- **[GitHub Repository](https://github.com/markolofsen/unrealon-parser-amazon)** - Source code and examples
|
|
465
|
+
- **[API Documentation](https://unrealon.com)** - Full API reference
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## 🎉 Success Stories
|
|
470
|
+
|
|
471
|
+
### 🚗 CarAPIs - Automotive Data Platform
|
|
472
|
+
**[carapis.com](https://carapis.com)** - Vehicle listings from 50+ dealerships
|
|
473
|
+
*"Went from prototype to production in 2 days with UnrealOn"*
|
|
474
|
+
|
|
475
|
+
### 🛒 ShopAPIs - E-commerce Intelligence
|
|
476
|
+
**[shopapis.com](https://shopapis.com)** - Price monitoring across 100+ stores
|
|
477
|
+
*"Handles 1M+ products daily with zero maintenance"*
|
|
478
|
+
|
|
479
|
+
### 📊 StockAPIs - Financial Data Platform
|
|
480
|
+
**[stockapis.com](https://stockapis.com)** - Real-time market data collection
|
|
481
|
+
*"Rock-solid reliability for financial data that can't afford downtime"*
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## 📄 License
|
|
486
|
+
|
|
487
|
+
MIT License - Use it however you want!
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
**Stop building infrastructure. Start building parsers.** 🚀
|