feat: 添加 CrawlService 爬取编排器 + 测试

This commit is contained in:
2026-05-09 13:50:58 +08:00
parent 5e0582d499
commit 022d348052
4 changed files with 122 additions and 0 deletions
View File
+36
View File
@@ -0,0 +1,36 @@
from typing import Dict, List
from app.crawler.base import BaseSpider, CrawlResult
class CrawlService:
def __init__(self):
self.spiders: Dict[str, BaseSpider] = {}
def register(self, spider: BaseSpider):
self.spiders[spider.name] = spider
async def run_all(self) -> List[CrawlResult]:
results = []
for name, spider in self.spiders.items():
result = await spider.crawl()
results.append(result)
return results
async def run_spider(self, name: str, **kwargs) -> List[CrawlResult]:
spider = self.spiders.get(name)
if spider is None:
return [CrawlResult(
source_code=name, source_name=name,
error_message=f"Spider not found: {name}"
)]
result = await spider.crawl(**kwargs)
return [result]
def get_spider_names(self) -> List[str]:
return list(self.spiders.keys())
def get_pipeline_config(self, name: str):
spider = self.spiders.get(name)
if spider:
return spider.get_pipeline_config()
return None
View File
+86
View File
@@ -0,0 +1,86 @@
import pytest
from datetime import datetime
from app.crawler.base import BaseSpider, CrawlResult, PipelineConfig
from app.services.crawl_service import CrawlService
class MockGXGPSpider(BaseSpider):
name = "mock_gxgp"
source_code = "mock_gxgp"
source_name = "Mock GXGP"
async def crawl(self, **kwargs):
return CrawlResult(
source_code=self.source_code,
source_name=self.source_name,
total_count=10,
new_count=5,
announcements=[],
)
def get_pipeline_config(self):
return PipelineConfig(
filter_enabled=True,
keywords=["大化"],
notify_mode="filtered",
)
class MockDahuagovSpider(BaseSpider):
name = "mock_dahuagov"
source_code = "mock_dahuagov"
source_name = "Mock Dahuagov"
async def crawl(self, **kwargs):
return CrawlResult(
source_code=self.source_code,
source_name=self.source_name,
total_count=3,
new_count=3,
announcements=[],
)
def get_pipeline_config(self):
return PipelineConfig(
filter_enabled=False,
notify_mode="all",
mark_sent=True,
)
@pytest.mark.asyncio
async def test_crawl_service_registers_spiders():
service = CrawlService()
service.register(MockGXGPSpider())
service.register(MockDahuagovSpider())
assert len(service.spiders) == 2
@pytest.mark.asyncio
async def test_crawl_service_run_all():
service = CrawlService()
service.register(MockGXGPSpider())
service.register(MockDahuagovSpider())
results = await service.run_all()
assert len(results) == 2
assert results[0].total_count == 10
assert results[1].total_count == 3
assert all(r.success for r in results)
@pytest.mark.asyncio
async def test_crawl_service_run_specific():
service = CrawlService()
service.register(MockGXGPSpider())
service.register(MockDahuagovSpider())
results = await service.run_spider("mock_dahuagov")
assert len(results) == 1
assert results[0].source_code == "mock_dahuagov"
@pytest.mark.asyncio
async def test_crawl_service_run_unknown():
service = CrawlService()
results = await service.run_spider("nonexistent")
assert len(results) == 1
assert results[0].success is False