crawlo 1.2.8__py3-none-any.whl → 1.2.9__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.
Potentially problematic release.
This version of crawlo might be problematic. Click here for more details.
- crawlo/__init__.py +63 -61
- crawlo/__version__.py +1 -1
- crawlo/cli.py +75 -75
- crawlo/commands/__init__.py +14 -14
- crawlo/commands/check.py +594 -594
- crawlo/commands/genspider.py +151 -151
- crawlo/commands/help.py +138 -138
- crawlo/commands/list.py +155 -155
- crawlo/commands/run.py +323 -323
- crawlo/commands/startproject.py +436 -436
- crawlo/commands/stats.py +187 -187
- crawlo/commands/utils.py +186 -186
- crawlo/config.py +312 -312
- crawlo/config_validator.py +277 -251
- crawlo/core/__init__.py +2 -2
- crawlo/core/engine.py +366 -365
- crawlo/core/processor.py +40 -40
- crawlo/core/scheduler.py +256 -251
- crawlo/crawler.py +1103 -1100
- crawlo/data/__init__.py +5 -5
- crawlo/data/user_agents.py +194 -107
- crawlo/downloader/__init__.py +273 -266
- crawlo/downloader/aiohttp_downloader.py +226 -228
- crawlo/downloader/cffi_downloader.py +245 -256
- crawlo/downloader/httpx_downloader.py +259 -259
- crawlo/downloader/hybrid_downloader.py +212 -212
- crawlo/downloader/playwright_downloader.py +402 -402
- crawlo/downloader/selenium_downloader.py +472 -472
- crawlo/event.py +11 -11
- crawlo/exceptions.py +81 -81
- crawlo/extension/__init__.py +39 -39
- crawlo/extension/health_check.py +141 -141
- crawlo/extension/log_interval.py +57 -57
- crawlo/extension/log_stats.py +81 -81
- crawlo/extension/logging_extension.py +43 -43
- crawlo/extension/memory_monitor.py +104 -104
- crawlo/extension/performance_profiler.py +133 -133
- crawlo/extension/request_recorder.py +107 -107
- crawlo/filters/__init__.py +154 -154
- crawlo/filters/aioredis_filter.py +234 -234
- crawlo/filters/memory_filter.py +269 -269
- crawlo/items/__init__.py +23 -23
- crawlo/items/base.py +21 -21
- crawlo/items/fields.py +52 -52
- crawlo/items/items.py +104 -104
- crawlo/middleware/__init__.py +21 -21
- crawlo/middleware/default_header.py +132 -132
- crawlo/middleware/download_delay.py +104 -104
- crawlo/middleware/middleware_manager.py +136 -136
- crawlo/middleware/offsite.py +114 -114
- crawlo/middleware/proxy.py +386 -368
- crawlo/middleware/request_ignore.py +86 -86
- crawlo/middleware/response_code.py +163 -163
- crawlo/middleware/response_filter.py +136 -136
- crawlo/middleware/retry.py +124 -124
- crawlo/middleware/simple_proxy.py +65 -0
- crawlo/mode_manager.py +211 -211
- crawlo/network/__init__.py +21 -21
- crawlo/network/request.py +379 -338
- crawlo/network/response.py +359 -359
- crawlo/pipelines/__init__.py +21 -21
- crawlo/pipelines/bloom_dedup_pipeline.py +157 -157
- crawlo/pipelines/console_pipeline.py +39 -39
- crawlo/pipelines/csv_pipeline.py +316 -316
- crawlo/pipelines/database_dedup_pipeline.py +223 -223
- crawlo/pipelines/json_pipeline.py +218 -218
- crawlo/pipelines/memory_dedup_pipeline.py +115 -115
- crawlo/pipelines/mongo_pipeline.py +131 -131
- crawlo/pipelines/mysql_pipeline.py +317 -317
- crawlo/pipelines/pipeline_manager.py +62 -62
- crawlo/pipelines/redis_dedup_pipeline.py +167 -167
- crawlo/project.py +290 -315
- crawlo/queue/pqueue.py +37 -37
- crawlo/queue/queue_manager.py +379 -378
- crawlo/queue/redis_priority_queue.py +306 -306
- crawlo/settings/__init__.py +7 -7
- crawlo/settings/default_settings.py +216 -220
- crawlo/settings/setting_manager.py +163 -122
- crawlo/spider/__init__.py +639 -639
- crawlo/stats_collector.py +59 -59
- crawlo/subscriber.py +129 -129
- crawlo/task_manager.py +30 -30
- crawlo/templates/crawlo.cfg.tmpl +10 -10
- crawlo/templates/project/__init__.py.tmpl +3 -3
- crawlo/templates/project/items.py.tmpl +17 -17
- crawlo/templates/project/middlewares.py.tmpl +118 -118
- crawlo/templates/project/pipelines.py.tmpl +96 -96
- crawlo/templates/project/settings.py.tmpl +261 -288
- crawlo/templates/project/settings_distributed.py.tmpl +174 -157
- crawlo/templates/project/settings_gentle.py.tmpl +95 -100
- crawlo/templates/project/settings_high_performance.py.tmpl +125 -134
- crawlo/templates/project/settings_minimal.py.tmpl +30 -0
- crawlo/templates/project/settings_simple.py.tmpl +96 -98
- crawlo/templates/project/spiders/__init__.py.tmpl +5 -5
- crawlo/templates/run.py.tmpl +47 -47
- crawlo/templates/spider/spider.py.tmpl +143 -143
- crawlo/tools/__init__.py +200 -182
- crawlo/tools/anti_crawler.py +268 -268
- crawlo/tools/authenticated_proxy.py +240 -240
- crawlo/{cleaners → tools}/data_formatter.py +225 -225
- crawlo/tools/data_validator.py +180 -180
- crawlo/tools/date_tools.py +290 -36
- crawlo/tools/distributed_coordinator.py +388 -387
- crawlo/{cleaners → tools}/encoding_converter.py +127 -126
- crawlo/tools/request_tools.py +83 -0
- crawlo/tools/retry_mechanism.py +224 -221
- crawlo/tools/scenario_adapter.py +262 -262
- crawlo/{cleaners → tools}/text_cleaner.py +232 -232
- crawlo/utils/__init__.py +35 -35
- crawlo/utils/batch_processor.py +259 -259
- crawlo/utils/controlled_spider_mixin.py +439 -439
- crawlo/utils/db_helper.py +343 -343
- crawlo/utils/enhanced_error_handler.py +356 -356
- crawlo/utils/env_config.py +142 -142
- crawlo/utils/error_handler.py +123 -123
- crawlo/utils/func_tools.py +82 -82
- crawlo/utils/large_scale_config.py +286 -286
- crawlo/utils/large_scale_helper.py +344 -344
- crawlo/utils/log.py +187 -128
- crawlo/utils/performance_monitor.py +285 -285
- crawlo/utils/queue_helper.py +175 -175
- crawlo/utils/redis_connection_pool.py +351 -351
- crawlo/utils/redis_key_validator.py +198 -198
- crawlo/utils/request.py +267 -267
- crawlo/utils/request_serializer.py +218 -218
- crawlo/utils/spider_loader.py +61 -61
- crawlo/utils/system.py +11 -11
- crawlo/utils/tools.py +4 -4
- crawlo/utils/url.py +39 -39
- {crawlo-1.2.8.dist-info → crawlo-1.2.9.dist-info}/METADATA +1011 -764
- crawlo-1.2.9.dist-info/RECORD +219 -0
- examples/__init__.py +7 -7
- tests/DOUBLE_CRAWLO_PREFIX_FIX_REPORT.md +81 -81
- tests/__init__.py +7 -7
- tests/advanced_tools_example.py +275 -275
- tests/authenticated_proxy_example.py +107 -237
- tests/cleaners_example.py +160 -160
- tests/config_validation_demo.py +143 -103
- tests/controlled_spider_example.py +205 -205
- tests/date_tools_example.py +180 -180
- tests/debug_pipelines.py +67 -0
- tests/dynamic_loading_example.py +523 -523
- tests/dynamic_loading_test.py +104 -104
- tests/env_config_example.py +133 -133
- tests/error_handling_example.py +171 -171
- tests/redis_key_validation_demo.py +130 -130
- tests/request_params_example.py +151 -0
- tests/response_improvements_example.py +144 -144
- tests/test_advanced_tools.py +148 -148
- tests/test_all_redis_key_configs.py +145 -145
- tests/test_authenticated_proxy.py +141 -141
- tests/test_cleaners.py +54 -54
- tests/test_comprehensive.py +146 -146
- tests/test_config_consistency.py +80 -80
- tests/test_config_merge.py +153 -0
- tests/test_config_validator.py +182 -193
- tests/test_crawlo_proxy_integration.py +109 -173
- tests/test_date_tools.py +123 -123
- tests/test_default_header_middleware.py +158 -158
- tests/test_distributed.py +65 -0
- tests/test_double_crawlo_fix.py +207 -207
- tests/test_double_crawlo_fix_simple.py +124 -124
- tests/test_download_delay_middleware.py +221 -221
- tests/test_downloader_proxy_compatibility.py +268 -268
- tests/test_dynamic_downloaders_proxy.py +124 -124
- tests/test_dynamic_proxy.py +92 -92
- tests/test_dynamic_proxy_config.py +146 -146
- tests/test_dynamic_proxy_real.py +109 -109
- tests/test_edge_cases.py +303 -303
- tests/test_enhanced_error_handler.py +270 -270
- tests/test_env_config.py +121 -121
- tests/test_error_handler_compatibility.py +112 -112
- tests/test_final_validation.py +153 -153
- tests/test_framework_env_usage.py +103 -103
- tests/test_integration.py +169 -357
- tests/test_item_dedup_redis_key.py +122 -122
- tests/test_mode_consistency.py +51 -51
- tests/test_offsite_middleware.py +221 -221
- tests/test_parsel.py +29 -29
- tests/test_performance.py +327 -327
- tests/test_proxy_api.py +264 -264
- tests/test_proxy_health_check.py +32 -32
- tests/test_proxy_middleware.py +121 -121
- tests/test_proxy_middleware_enhanced.py +216 -216
- tests/test_proxy_middleware_integration.py +136 -136
- tests/test_proxy_middleware_refactored.py +185 -0
- tests/test_proxy_providers.py +56 -56
- tests/test_proxy_stats.py +19 -19
- tests/test_proxy_strategies.py +59 -59
- tests/test_queue_manager_double_crawlo.py +173 -173
- tests/test_queue_manager_redis_key.py +176 -176
- tests/test_random_user_agent.py +73 -0
- tests/test_real_scenario_proxy.py +195 -195
- tests/test_redis_config.py +28 -28
- tests/test_redis_connection_pool.py +294 -294
- tests/test_redis_key_naming.py +181 -181
- tests/test_redis_key_validator.py +123 -123
- tests/test_redis_queue.py +224 -224
- tests/test_request_ignore_middleware.py +182 -182
- tests/test_request_params.py +112 -0
- tests/test_request_serialization.py +70 -70
- tests/test_response_code_middleware.py +349 -349
- tests/test_response_filter_middleware.py +427 -427
- tests/test_response_improvements.py +152 -152
- tests/test_retry_middleware.py +241 -241
- tests/test_scheduler.py +252 -252
- tests/test_scheduler_config_update.py +133 -133
- tests/test_simple_response.py +61 -61
- tests/test_telecom_spider_redis_key.py +205 -205
- tests/test_template_content.py +87 -87
- tests/test_template_redis_key.py +134 -134
- tests/test_tools.py +159 -153
- tests/test_user_agents.py +97 -0
- tests/tools_example.py +260 -257
- tests/verify_distributed.py +117 -0
- crawlo/cleaners/__init__.py +0 -61
- crawlo/utils/date_tools.py +0 -290
- crawlo-1.2.8.dist-info/RECORD +0 -209
- {crawlo-1.2.8.dist-info → crawlo-1.2.9.dist-info}/WHEEL +0 -0
- {crawlo-1.2.8.dist-info → crawlo-1.2.9.dist-info}/entry_points.txt +0 -0
- {crawlo-1.2.8.dist-info → crawlo-1.2.9.dist-info}/top_level.txt +0 -0
tests/test_final_validation.py
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
最终验证测试:确认分布式队列的 logger 序列化问题已完全解决
|
|
5
|
-
"""
|
|
6
|
-
import asyncio
|
|
7
|
-
import pickle
|
|
8
|
-
import sys
|
|
9
|
-
sys.path.insert(0, "..")
|
|
10
|
-
|
|
11
|
-
from crawlo.network.request import Request
|
|
12
|
-
from crawlo.spider import Spider
|
|
13
|
-
from crawlo.core.scheduler import Scheduler
|
|
14
|
-
from crawlo.queue.redis_priority_queue import RedisPriorityQueue
|
|
15
|
-
from crawlo.utils.log import get_logger
|
|
16
|
-
from unittest.mock import Mock
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class TestSpider(Spider):
|
|
20
|
-
"""测试爬虫"""
|
|
21
|
-
name = "validation_spider"
|
|
22
|
-
|
|
23
|
-
def __init__(self):
|
|
24
|
-
super().__init__()
|
|
25
|
-
# 故意添加多个 logger 来测试清理
|
|
26
|
-
self.custom_logger = get_logger("custom")
|
|
27
|
-
self.debug_logger = get_logger("debug")
|
|
28
|
-
self.nested_data = {
|
|
29
|
-
'logger': get_logger("nested"),
|
|
30
|
-
'sub': {
|
|
31
|
-
'logger_ref': get_logger("sub_logger")
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
def parse(self, response):
|
|
36
|
-
# 验证主 logger 还在
|
|
37
|
-
self.logger.info(f"
|
|
38
|
-
return {"url": response.url, "status": "success"}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def test_scheduler_cleaning():
|
|
42
|
-
"""测试调度器的 logger 清理"""
|
|
43
|
-
print("
|
|
44
|
-
|
|
45
|
-
spider = TestSpider()
|
|
46
|
-
request = Request(
|
|
47
|
-
url="https://scheduler-test.com",
|
|
48
|
-
callback=spider.parse,
|
|
49
|
-
meta={"logger": get_logger("meta_logger")}
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
# Mock crawler 和 scheduler
|
|
53
|
-
class MockCrawler:
|
|
54
|
-
def __init__(self):
|
|
55
|
-
self.spider = spider
|
|
56
|
-
|
|
57
|
-
class MockScheduler(Scheduler):
|
|
58
|
-
def __init__(self):
|
|
59
|
-
self.crawler = MockCrawler()
|
|
60
|
-
self.logger = get_logger("MockScheduler")
|
|
61
|
-
|
|
62
|
-
scheduler = MockScheduler()
|
|
63
|
-
|
|
64
|
-
# 清理前检查
|
|
65
|
-
print(f"
|
|
66
|
-
print(f"
|
|
67
|
-
print(f"
|
|
68
|
-
|
|
69
|
-
# 执行清理
|
|
70
|
-
cleaned_request = scheduler._deep_clean_loggers(request)
|
|
71
|
-
|
|
72
|
-
# 清理后检查
|
|
73
|
-
print(f"
|
|
74
|
-
print(f"
|
|
75
|
-
print(f"
|
|
76
|
-
|
|
77
|
-
# 序列化测试
|
|
78
|
-
try:
|
|
79
|
-
serialized = pickle.dumps(cleaned_request)
|
|
80
|
-
print(f"
|
|
81
|
-
return True
|
|
82
|
-
except Exception as e:
|
|
83
|
-
print(f"
|
|
84
|
-
return False
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
async def test_redis_queue_cleaning():
|
|
88
|
-
"""测试 Redis 队列的 logger 清理"""
|
|
89
|
-
print("\\n
|
|
90
|
-
|
|
91
|
-
spider = TestSpider()
|
|
92
|
-
request = Request(
|
|
93
|
-
url="https://redis-test.com",
|
|
94
|
-
callback=spider.parse,
|
|
95
|
-
meta={"logger": get_logger("meta_logger")}
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
try:
|
|
99
|
-
queue = RedisPriorityQueue(redis_url="redis://127.0.0.1:6379/0")
|
|
100
|
-
await queue.connect()
|
|
101
|
-
|
|
102
|
-
# 入队测试
|
|
103
|
-
success = await queue.put(request, priority=0)
|
|
104
|
-
print(f"
|
|
105
|
-
|
|
106
|
-
if success:
|
|
107
|
-
# 出队测试
|
|
108
|
-
retrieved = await queue.get(timeout=2.0)
|
|
109
|
-
if retrieved:
|
|
110
|
-
print(f"
|
|
111
|
-
print(f"
|
|
112
|
-
await queue.close()
|
|
113
|
-
return True
|
|
114
|
-
else:
|
|
115
|
-
print("
|
|
116
|
-
await queue.close()
|
|
117
|
-
return False
|
|
118
|
-
else:
|
|
119
|
-
await queue.close()
|
|
120
|
-
return False
|
|
121
|
-
|
|
122
|
-
except Exception as e:
|
|
123
|
-
print(f"
|
|
124
|
-
return False
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
async def main():
|
|
128
|
-
"""主测试函数"""
|
|
129
|
-
print("
|
|
130
|
-
print("=" * 60)
|
|
131
|
-
|
|
132
|
-
# 测试 1: 调度器清理
|
|
133
|
-
scheduler_ok = test_scheduler_cleaning()
|
|
134
|
-
|
|
135
|
-
# 测试 2: Redis 队列清理
|
|
136
|
-
redis_ok = await test_redis_queue_cleaning()
|
|
137
|
-
|
|
138
|
-
print("\\n" + "=" * 60)
|
|
139
|
-
print("
|
|
140
|
-
print(f" 调度器 logger 清理: {'
|
|
141
|
-
print(f" Redis 队列清理: {'
|
|
142
|
-
|
|
143
|
-
if scheduler_ok and redis_ok:
|
|
144
|
-
print("\\n
|
|
145
|
-
print("
|
|
146
|
-
print("
|
|
147
|
-
return True
|
|
148
|
-
else:
|
|
149
|
-
print("\\n
|
|
150
|
-
return False
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if __name__ == "__main__":
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
最终验证测试:确认分布式队列的 logger 序列化问题已完全解决
|
|
5
|
+
"""
|
|
6
|
+
import asyncio
|
|
7
|
+
import pickle
|
|
8
|
+
import sys
|
|
9
|
+
sys.path.insert(0, "..")
|
|
10
|
+
|
|
11
|
+
from crawlo.network.request import Request
|
|
12
|
+
from crawlo.spider import Spider
|
|
13
|
+
from crawlo.core.scheduler import Scheduler
|
|
14
|
+
from crawlo.queue.redis_priority_queue import RedisPriorityQueue
|
|
15
|
+
from crawlo.utils.log import get_logger
|
|
16
|
+
from unittest.mock import Mock
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestSpider(Spider):
|
|
20
|
+
"""测试爬虫"""
|
|
21
|
+
name = "validation_spider"
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
super().__init__()
|
|
25
|
+
# 故意添加多个 logger 来测试清理
|
|
26
|
+
self.custom_logger = get_logger("custom")
|
|
27
|
+
self.debug_logger = get_logger("debug")
|
|
28
|
+
self.nested_data = {
|
|
29
|
+
'logger': get_logger("nested"),
|
|
30
|
+
'sub': {
|
|
31
|
+
'logger_ref': get_logger("sub_logger")
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def parse(self, response):
|
|
36
|
+
# 验证主 logger 还在
|
|
37
|
+
self.logger.info(f"主 logger 工作正常: {response.url}")
|
|
38
|
+
return {"url": response.url, "status": "success"}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_scheduler_cleaning():
|
|
42
|
+
"""测试调度器的 logger 清理"""
|
|
43
|
+
print("测试调度器 logger 清理...")
|
|
44
|
+
|
|
45
|
+
spider = TestSpider()
|
|
46
|
+
request = Request(
|
|
47
|
+
url="https://scheduler-test.com",
|
|
48
|
+
callback=spider.parse,
|
|
49
|
+
meta={"logger": get_logger("meta_logger")}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Mock crawler 和 scheduler
|
|
53
|
+
class MockCrawler:
|
|
54
|
+
def __init__(self):
|
|
55
|
+
self.spider = spider
|
|
56
|
+
|
|
57
|
+
class MockScheduler(Scheduler):
|
|
58
|
+
def __init__(self):
|
|
59
|
+
self.crawler = MockCrawler()
|
|
60
|
+
self.logger = get_logger("MockScheduler")
|
|
61
|
+
|
|
62
|
+
scheduler = MockScheduler()
|
|
63
|
+
|
|
64
|
+
# 清理前检查
|
|
65
|
+
print(f" 清理前 - spider.logger: {spider.logger is not None}")
|
|
66
|
+
print(f" 清理前 - spider.custom_logger: {spider.custom_logger is not None}")
|
|
67
|
+
print(f" 清理前 - request.callback: {request.callback is not None}")
|
|
68
|
+
|
|
69
|
+
# 执行清理
|
|
70
|
+
cleaned_request = scheduler._deep_clean_loggers(request)
|
|
71
|
+
|
|
72
|
+
# 清理后检查
|
|
73
|
+
print(f" 清理后 - spider.logger: {spider.logger is not None}")
|
|
74
|
+
print(f" 清理后 - spider.custom_logger: {spider.custom_logger is None}")
|
|
75
|
+
print(f" 清理后 - request.callback: {cleaned_request.callback is None}")
|
|
76
|
+
|
|
77
|
+
# 序列化测试
|
|
78
|
+
try:
|
|
79
|
+
serialized = pickle.dumps(cleaned_request)
|
|
80
|
+
print(f" 调度器清理后序列化成功,大小: {len(serialized)} bytes")
|
|
81
|
+
return True
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f" 调度器清理后序列化失败: {e}")
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async def test_redis_queue_cleaning():
|
|
88
|
+
"""测试 Redis 队列的 logger 清理"""
|
|
89
|
+
print("\\n测试 Redis 队列 logger 清理...")
|
|
90
|
+
|
|
91
|
+
spider = TestSpider()
|
|
92
|
+
request = Request(
|
|
93
|
+
url="https://redis-test.com",
|
|
94
|
+
callback=spider.parse,
|
|
95
|
+
meta={"logger": get_logger("meta_logger")}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
queue = RedisPriorityQueue(redis_url="redis://127.0.0.1:6379/0")
|
|
100
|
+
await queue.connect()
|
|
101
|
+
|
|
102
|
+
# 入队测试
|
|
103
|
+
success = await queue.put(request, priority=0)
|
|
104
|
+
print(f" Redis 队列入队成功: {success}")
|
|
105
|
+
|
|
106
|
+
if success:
|
|
107
|
+
# 出队测试
|
|
108
|
+
retrieved = await queue.get(timeout=2.0)
|
|
109
|
+
if retrieved:
|
|
110
|
+
print(f" Redis 队列出队成功: {retrieved.url}")
|
|
111
|
+
print(f" callback 信息保存: {'_callback_info' in retrieved.meta}")
|
|
112
|
+
await queue.close()
|
|
113
|
+
return True
|
|
114
|
+
else:
|
|
115
|
+
print(" 出队失败")
|
|
116
|
+
await queue.close()
|
|
117
|
+
return False
|
|
118
|
+
else:
|
|
119
|
+
await queue.close()
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print(f" Redis 队列测试失败: {e}")
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def main():
|
|
128
|
+
"""主测试函数"""
|
|
129
|
+
print("开始最终验证测试...")
|
|
130
|
+
print("=" * 60)
|
|
131
|
+
|
|
132
|
+
# 测试 1: 调度器清理
|
|
133
|
+
scheduler_ok = test_scheduler_cleaning()
|
|
134
|
+
|
|
135
|
+
# 测试 2: Redis 队列清理
|
|
136
|
+
redis_ok = await test_redis_queue_cleaning()
|
|
137
|
+
|
|
138
|
+
print("\\n" + "=" * 60)
|
|
139
|
+
print("测试结果汇总:")
|
|
140
|
+
print(f" 调度器 logger 清理: {'通过' if scheduler_ok else '失败'}")
|
|
141
|
+
print(f" Redis 队列清理: {'通过' if redis_ok else '失败'}")
|
|
142
|
+
|
|
143
|
+
if scheduler_ok and redis_ok:
|
|
144
|
+
print("\\n所有测试通过!")
|
|
145
|
+
print("分布式队列的 logger 序列化问题已完全修复!")
|
|
146
|
+
print("Crawlo 现在可以正常使用 Redis 分布式队列了!")
|
|
147
|
+
return True
|
|
148
|
+
else:
|
|
149
|
+
print("\\n部分测试失败,需要进一步修复")
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if __name__ == "__main__":
|
|
154
154
|
asyncio.run(main())
|
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
框架环境变量使用测试
|
|
5
|
-
验证整个框架中环境变量的正确使用
|
|
6
|
-
"""
|
|
7
|
-
import sys
|
|
8
|
-
import os
|
|
9
|
-
import unittest
|
|
10
|
-
from unittest.mock import patch, MagicMock
|
|
11
|
-
|
|
12
|
-
# 添加项目根目录到Python路径
|
|
13
|
-
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
14
|
-
|
|
15
|
-
from crawlo.utils.env_config import get_env_var, get_redis_config, get_runtime_config
|
|
16
|
-
from crawlo.settings.setting_manager import SettingManager
|
|
17
|
-
from crawlo.settings import default_settings
|
|
18
|
-
from crawlo.mode_manager import from_env
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class TestFrameworkEnvUsage(unittest.TestCase):
|
|
22
|
-
"""框架环境变量使用测试"""
|
|
23
|
-
|
|
24
|
-
def test_default_settings_env_usage(self):
|
|
25
|
-
"""测试 default_settings.py 中的环境变量使用"""
|
|
26
|
-
# 验证 default_settings.py 不直接使用 os.getenv
|
|
27
|
-
import inspect
|
|
28
|
-
import crawlo.settings.default_settings as default_settings_module
|
|
29
|
-
|
|
30
|
-
source_code = inspect.getsource(default_settings_module)
|
|
31
|
-
# 检查是否还有直接使用 os.getenv 的地方
|
|
32
|
-
self.assertNotIn('os.getenv', source_code,
|
|
33
|
-
"default_settings.py 不应该直接使用 os.getenv")
|
|
34
|
-
|
|
35
|
-
# 但应该使用 env_config 工具
|
|
36
|
-
self.assertIn('get_redis_config', source_code,
|
|
37
|
-
"default_settings.py 应该使用 get_redis_config")
|
|
38
|
-
self.assertIn('get_runtime_config', source_code,
|
|
39
|
-
"default_settings.py 应该使用 get_runtime_config")
|
|
40
|
-
|
|
41
|
-
def test_env_config_tool(self):
|
|
42
|
-
"""测试环境变量配置工具"""
|
|
43
|
-
# 测试获取Redis配置
|
|
44
|
-
with patch.dict(os.environ, {
|
|
45
|
-
'REDIS_HOST': 'test.redis.com',
|
|
46
|
-
'REDIS_PORT': '6380',
|
|
47
|
-
'REDIS_PASSWORD': 'test_pass',
|
|
48
|
-
'REDIS_DB': '2'
|
|
49
|
-
}):
|
|
50
|
-
redis_config = get_redis_config()
|
|
51
|
-
self.assertEqual(redis_config['REDIS_HOST'], 'test.redis.com')
|
|
52
|
-
self.assertEqual(redis_config['REDIS_PORT'], 6380)
|
|
53
|
-
self.assertEqual(redis_config['REDIS_PASSWORD'], 'test_pass')
|
|
54
|
-
self.assertEqual(redis_config['REDIS_DB'], 2)
|
|
55
|
-
|
|
56
|
-
# 测试获取运行时配置
|
|
57
|
-
with patch.dict(os.environ, {
|
|
58
|
-
'PROJECT_NAME': 'test_project',
|
|
59
|
-
'CRAWLO_MODE': 'distributed',
|
|
60
|
-
'CONCURRENCY': '16'
|
|
61
|
-
}):
|
|
62
|
-
runtime_config = get_runtime_config()
|
|
63
|
-
self.assertEqual(runtime_config['PROJECT_NAME'], 'test_project')
|
|
64
|
-
self.assertEqual(runtime_config['CRAWLO_MODE'], 'distributed')
|
|
65
|
-
self.assertEqual(runtime_config['CONCURRENCY'], 16)
|
|
66
|
-
|
|
67
|
-
def test_settings_manager_with_env(self):
|
|
68
|
-
"""测试设置管理器与环境变量的集成"""
|
|
69
|
-
# 设置环境变量
|
|
70
|
-
env_vars = {
|
|
71
|
-
'PROJECT_NAME': 'env_test_project',
|
|
72
|
-
'CONCURRENCY': '12',
|
|
73
|
-
'REDIS_HOST': 'env.redis.test',
|
|
74
|
-
'REDIS_PORT': '6381'
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
with patch.dict(os.environ, env_vars):
|
|
78
|
-
# 重新导入 default_settings 模块以获取最新的环境变量
|
|
79
|
-
import importlib
|
|
80
|
-
import crawlo.settings.default_settings
|
|
81
|
-
importlib.reload(crawlo.settings.default_settings)
|
|
82
|
-
|
|
83
|
-
# 创建设置管理器
|
|
84
|
-
settings = SettingManager()
|
|
85
|
-
settings.set_settings(crawlo.settings.default_settings)
|
|
86
|
-
|
|
87
|
-
# 验证环境变量被正确使用
|
|
88
|
-
redis_config = get_redis_config()
|
|
89
|
-
self.assertEqual(settings.get('REDIS_HOST'), redis_config['REDIS_HOST'])
|
|
90
|
-
|
|
91
|
-
runtime_config = get_runtime_config()
|
|
92
|
-
self.assertEqual(settings.get('PROJECT_NAME'), runtime_config['PROJECT_NAME'])
|
|
93
|
-
|
|
94
|
-
def test_mode_manager_env_usage(self):
|
|
95
|
-
"""测试 mode_manager.py 中的环境变量使用"""
|
|
96
|
-
# 验证 from_env 函数现在会抛出异常
|
|
97
|
-
with self.assertRaises(RuntimeError) as context:
|
|
98
|
-
from_env()
|
|
99
|
-
|
|
100
|
-
self.assertIn("环境变量配置已移除", str(context.exception))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if __name__ == '__main__':
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
框架环境变量使用测试
|
|
5
|
+
验证整个框架中环境变量的正确使用
|
|
6
|
+
"""
|
|
7
|
+
import sys
|
|
8
|
+
import os
|
|
9
|
+
import unittest
|
|
10
|
+
from unittest.mock import patch, MagicMock
|
|
11
|
+
|
|
12
|
+
# 添加项目根目录到Python路径
|
|
13
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
14
|
+
|
|
15
|
+
from crawlo.utils.env_config import get_env_var, get_redis_config, get_runtime_config
|
|
16
|
+
from crawlo.settings.setting_manager import SettingManager
|
|
17
|
+
from crawlo.settings import default_settings
|
|
18
|
+
from crawlo.mode_manager import from_env
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TestFrameworkEnvUsage(unittest.TestCase):
|
|
22
|
+
"""框架环境变量使用测试"""
|
|
23
|
+
|
|
24
|
+
def test_default_settings_env_usage(self):
|
|
25
|
+
"""测试 default_settings.py 中的环境变量使用"""
|
|
26
|
+
# 验证 default_settings.py 不直接使用 os.getenv
|
|
27
|
+
import inspect
|
|
28
|
+
import crawlo.settings.default_settings as default_settings_module
|
|
29
|
+
|
|
30
|
+
source_code = inspect.getsource(default_settings_module)
|
|
31
|
+
# 检查是否还有直接使用 os.getenv 的地方
|
|
32
|
+
self.assertNotIn('os.getenv', source_code,
|
|
33
|
+
"default_settings.py 不应该直接使用 os.getenv")
|
|
34
|
+
|
|
35
|
+
# 但应该使用 env_config 工具
|
|
36
|
+
self.assertIn('get_redis_config', source_code,
|
|
37
|
+
"default_settings.py 应该使用 get_redis_config")
|
|
38
|
+
self.assertIn('get_runtime_config', source_code,
|
|
39
|
+
"default_settings.py 应该使用 get_runtime_config")
|
|
40
|
+
|
|
41
|
+
def test_env_config_tool(self):
|
|
42
|
+
"""测试环境变量配置工具"""
|
|
43
|
+
# 测试获取Redis配置
|
|
44
|
+
with patch.dict(os.environ, {
|
|
45
|
+
'REDIS_HOST': 'test.redis.com',
|
|
46
|
+
'REDIS_PORT': '6380',
|
|
47
|
+
'REDIS_PASSWORD': 'test_pass',
|
|
48
|
+
'REDIS_DB': '2'
|
|
49
|
+
}):
|
|
50
|
+
redis_config = get_redis_config()
|
|
51
|
+
self.assertEqual(redis_config['REDIS_HOST'], 'test.redis.com')
|
|
52
|
+
self.assertEqual(redis_config['REDIS_PORT'], 6380)
|
|
53
|
+
self.assertEqual(redis_config['REDIS_PASSWORD'], 'test_pass')
|
|
54
|
+
self.assertEqual(redis_config['REDIS_DB'], 2)
|
|
55
|
+
|
|
56
|
+
# 测试获取运行时配置
|
|
57
|
+
with patch.dict(os.environ, {
|
|
58
|
+
'PROJECT_NAME': 'test_project',
|
|
59
|
+
'CRAWLO_MODE': 'distributed',
|
|
60
|
+
'CONCURRENCY': '16'
|
|
61
|
+
}):
|
|
62
|
+
runtime_config = get_runtime_config()
|
|
63
|
+
self.assertEqual(runtime_config['PROJECT_NAME'], 'test_project')
|
|
64
|
+
self.assertEqual(runtime_config['CRAWLO_MODE'], 'distributed')
|
|
65
|
+
self.assertEqual(runtime_config['CONCURRENCY'], 16)
|
|
66
|
+
|
|
67
|
+
def test_settings_manager_with_env(self):
|
|
68
|
+
"""测试设置管理器与环境变量的集成"""
|
|
69
|
+
# 设置环境变量
|
|
70
|
+
env_vars = {
|
|
71
|
+
'PROJECT_NAME': 'env_test_project',
|
|
72
|
+
'CONCURRENCY': '12',
|
|
73
|
+
'REDIS_HOST': 'env.redis.test',
|
|
74
|
+
'REDIS_PORT': '6381'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
with patch.dict(os.environ, env_vars):
|
|
78
|
+
# 重新导入 default_settings 模块以获取最新的环境变量
|
|
79
|
+
import importlib
|
|
80
|
+
import crawlo.settings.default_settings
|
|
81
|
+
importlib.reload(crawlo.settings.default_settings)
|
|
82
|
+
|
|
83
|
+
# 创建设置管理器
|
|
84
|
+
settings = SettingManager()
|
|
85
|
+
settings.set_settings(crawlo.settings.default_settings)
|
|
86
|
+
|
|
87
|
+
# 验证环境变量被正确使用
|
|
88
|
+
redis_config = get_redis_config()
|
|
89
|
+
self.assertEqual(settings.get('REDIS_HOST'), redis_config['REDIS_HOST'])
|
|
90
|
+
|
|
91
|
+
runtime_config = get_runtime_config()
|
|
92
|
+
self.assertEqual(settings.get('PROJECT_NAME'), runtime_config['PROJECT_NAME'])
|
|
93
|
+
|
|
94
|
+
def test_mode_manager_env_usage(self):
|
|
95
|
+
"""测试 mode_manager.py 中的环境变量使用"""
|
|
96
|
+
# 验证 from_env 函数现在会抛出异常
|
|
97
|
+
with self.assertRaises(RuntimeError) as context:
|
|
98
|
+
from_env()
|
|
99
|
+
|
|
100
|
+
self.assertIn("环境变量配置已移除", str(context.exception))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == '__main__':
|
|
104
104
|
unittest.main()
|