# Phase 4: 后端 & 外部脚本接入 — 技术研究 **研究日期:** 2026-03-21 **阶段目标:** 后端 facade 使用 spiderJobs.platforms.*(已基于 crawler_core),私有复制文件删除;外部脚本 jobs_spider/ 标记废弃 --- ## 1. 现状分析 ### 1.1 app/services/crawler/ 文件结构 ``` app/services/crawler/ ├── _base.py ❌ 复制自 spiderJobs/core/base.py(ApiResult/BaseFetcher/BaseSearcher 旧版) ├── _http_client.py ❌ 复制自 spiderJobs/core/http_client.py ├── _boss_api.py ❌ 复制自 spiderJobs/platforms/boss/api.py ├── _boss_client.py ❌ 复制自 spiderJobs/platforms/boss/client.py(含 batch() 方法) ├── _boss_sign.py ❌ 复制自 spiderJobs/platforms/boss/sign.py ├── _job51_api.py ❌ 复制自 spiderJobs/platforms/job51/api.py ├── _job51_client.py ❌ 复制自 spiderJobs/platforms/job51/client.py ├── _job51_sign.py ❌ 复制自 spiderJobs/platforms/job51/sign.py(应该如此,推测) ├── _zhilian_api.py ❌ 复制自 spiderJobs/platforms/zhilian/api.py ├── _zhilian_client.py ❌ 复制自 spiderJobs/platforms/zhilian/client.py ├── _zhilian_sign.py ❌ 复制自 spiderJobs/platforms/zhilian/sign.py ├── boss.py ✅ BossService — 结构良好,使用 _boss_*(需改导入) ├── qcwy.py ✅ QcwyService — 结构良好,使用 _job51_*(需改导入) ├── zhilian.py ✅ ZhilianService — 结构良好,使用 _zhilian_*(需改导入) └── __init__.py ✅ 不变 ``` ### 1.2 facade 层的对外接口(调用方) | 调用方 | 使用的 Service | |--------|----------------| | `app/services/cleaning.py` | BossService, QcwyService, ZhilianService | | `app/services/company_cleaner.py` | BossService, QcwyService, ZhilianService | | `app/services/company_jobs_sync.py` | BossService, QcwyService, ZhilianService | | `app/api/v1/...` | 通过 Service 层调用 | **重要:** 这些调用方使用的接口(`set_proxy()`, `get_job_detail()`, `get_company_detail()`, `search_jobs()` 等)保持不变,只修改 facade 内部实现。 ### 1.3 迁移前后对应关系 | 当前私有文件 | 替换为 | |-------------|--------| | `_boss_api.py` → `GetBrandDetail, GetJobDetail, SearchBrandJobs, SearchRecJobs` | `spiderJobs.platforms.boss.api` | | `_boss_client.py` → `BossClient, create_client` | `spiderJobs.platforms.boss.client` | | `_boss_sign.py` → `BossSign` | `spiderJobs.platforms.boss.sign`(→ crawler_core 桩) | | `_job51_api.py` → `GetCompanyInfo, GetJobDetail, SearchCompanyJobs, SearchRecommendJobs` | `spiderJobs.platforms.job51.api` | | `_job51_client.py` → `Job51Client, create_client` | `spiderJobs.platforms.job51.client` | | `_zhilian_api.py` → `GetCompanyDetail, GetPositionDetail, SearchCompanyPositions, SearchPositions` | `spiderJobs.platforms.zhilian.api` | | `_zhilian_client.py` → `ZhilianClient, create_capi_client, create_cgate_client` | `spiderJobs.platforms.zhilian.client` | | `_zhilian_sign.py` → `ZhilianSign` | `spiderJobs.platforms.zhilian.sign`(→ crawler_core 桩) | ### 1.4 关键兼容性检查 **BossService 依赖 `_boss_client.BossClient.batch()` 方法:** - `_boss_client.py` 第 79-85 行有 `batch()` 方法 - `spiderJobs/platforms/boss/client.py` 也有 `batch()` 方法(Phase 2 迁移时未删除) - ✅ 完全兼容 **BossService.set_login_data() 设置 `self._signer.mpt/wt2`:** - `BossSign` 在 spiderJobs 版是 crawler_core 的桩(完全透传),`mpt/wt2` 属性在 `crawler_core.boss.sign.BossSign` 中存在 - ✅ 完全兼容 **ZhilianService 使用 `create_cgate_client/create_capi_client`:** - `spiderJobs/platforms/zhilian/client.py` 导出这两个函数 - ✅ 完全兼容 ### 1.5 asyncio.to_thread() 桥接(ARCH-06) 后端是 FastAPI 异步框架,而 crawler_core 使用 requests-go(同步)。 目前 cleaning.py 等是在同步上下文中调用 Service,推测已有 asyncio.to_thread 或者是同步服务。 **决策:** 在 facade 层的 Service 类中添加 async 方法(`async_get_job_detail()` 等), 内部用 `asyncio.to_thread(self.get_job_detail, ...)` 桥接。不修改已有同步方法(让旧调用方继续工作)。 ### 1.6 jobs_spider/ 废弃 `jobs_spider/boss/boos_api.py`(94KB)是最旧的单文件实现,现在三个平台的新实现都在 `spiderJobs/platforms/` 和 `crawler_core/` 中。 只需在 `jobs_spider/CLAUDE.md` 和文件头添加 `## ⚠️ DEPRECATED` 标记,不删除文件(保留历史)。 --- ## 2. 工作量对比 | 维度 | 描述 | |------|------| | facade 层修改 | 3 个文件(boss.py/qcwy.py/zhilian.py)各 3-5 行 import 修改 | | 私有文件 | 9 个文件可以**保留但标记废弃**(或直接删除,风险更低是保留) | | asyncio 桥接 | 3 个 Service 类各加 4-5 个 async 方法 | | jobs_spider 废弃 | 1 个 DEPRECATED 文件头注释 | --- ## 3. 成功标准 | 标准 | 验证方式 | |------|---------| | ARCH-06:facade 有 asyncio.to_thread 桥接 | `grep asyncio.to_thread app/services/crawler/*.py` | | ARCH-07:facade import spiderJobs.platforms.* | `grep "spiderJobs.platforms" app/services/crawler/boss.py` | | ARCH-08:jobs_spider 标记废弃 | `grep DEPRECATED jobs_spider/boss/boos_api.py` | | import 验证 | `python -c "from app.services.crawler.boss import BossService"` 无 ImportError | | 回归测试 | `pytest tests/ -v` 全部通过(98+α 个) | --- ## 4. Phase 4 计划分解 - **Plan 01**:迁移三个 facade 文件(boss.py/qcwy.py/zhilian.py)改导入 spiderJobs.platforms.*,添加 asyncio.to_thread 异步包装方法 - **Plan 02**:废弃 9 个私有复制文件和 jobs_spider/ 旧框架(添加 DEPRECATED 文件头)