jd-mcp
by NaoYUN77
README.md
# JD-PULL · JD 爬取 · 分析 · MCP 工具
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://modelcontextprotocol.io)
[](tests/)
一个开源的**招聘 JD 爬取 + 规则分析 + 岗位群像 + MCP 服务器**工具。
任何人 clone 到本地,爬取并分析**自己的数据**,通过 [MCP(Model Context Protocol)](https://modelcontextprotocol.io) 把数据暴露给 Claude / DeepSeek agent / Pi agent / Cursor 等任何支持 MCP 的外部 AI。
```
┌──────────────────────────┐ ┌──────────────────────────┐
│ 外部 AI(任何 MCP 客户端) │ ───► │ 本机 jd-mcp 服务器 │
│ Claude / DeepSeek / Pi │ MCP │ ┌────────────────────┐ │
│ / Cursor … │ │ │ 只读查询 · 写操作 │ │
└──────────────────────────┘ │ └────────┬───────────┘ │
└──────────┼───────────────┘
│ 读写
┌──────────▼───────────────┐
│ 你的数据目录(JD_DATA_DIR)│
│ 本地文件夹 或 私有 git 仓库 │
└──────────────────────────┘
```
爬取结果只存在于你的本机 `data/` 目录或你自己指定的数据仓库。
## 特性
- **JD 爬取**:51job(Playwright 真实浏览器驱动,默认系统 Edge)低频礼貌抓取;Boss直聘 / 拉勾 / 猎聘预留接口(需登录/签名,本期未实现);
- **规则分析**:按分类词典把 JD 归入岗位类别、提取技能与职责高频词;
- **LLM 精分(可选,多供应商)**:Claude / OpenAI / Gemini / DeepSeek / Qwen / Ollama 六家供应商,通过「能力梯子」自动适配各家结构化输出;
- **岗位群像**:按分类生成技能 / 薪资 / 经验 / 学历分布与职责高频词报告(JSON + Markdown);
- **MCP 服务器**:stdio 与 streamable-http 双传输,只读查询工具始终可用,写工具默认开启(`--no-write-tools` 关闭),HTTP 可选 Bearer token 鉴权;
- **数据完全本地**:`JD_DATA_DIR` 可指向任意目录或 git 仓库;数据目录不是独立 git 仓库时,`sync` 自动跳过,保护数据不被误提交。
## 技术栈
| 类别 | 技术 |
|------|------|
| 语言 | Python ≥ 3.10 |
| 爬取 | httpx + BeautifulSoup4(静态解析);Playwright 真实浏览器驱动(51job SPA,默认系统 Edge `channel=msedge`,免下载 chromium) |
| 分析 | jieba 分词 + 规则词典分类;LLM 精分走 anthropic SDK / httpx 多供应商适配 |
| 数据 | 本地 JSON 文件存储;指纹去重(`dedup`);目录结构 raw → classified → reports → site |
| 输出 | 静态 HTML 报告站(内联 CSS,无前端框架依赖) |
| MCP | `mcp>=1.26`(FastMCP)· stdio + streamable-http 双传输 · Pydantic v2 数据校验 |
| 配置 | YAML(PyYAML),站点/词典/LLM 全部可配置不改代码 |
| 测试 | pytest(51 用例) |
| 站点 | 51job(当前启用);Boss直聘 / 拉勾 / 猎聘(预留未实现) |
## 安装
要求 Python ≥ 3.10。
```bash
git clone https://github.com/NaoYUN77/JD-PULL.git
cd JD-PULL
python -m venv .venv && .venv\Scripts\activate # Windows;macOS/Linux 用 source .venv/bin/activate
pip install -e .[dev]
# 51job 爬取走真实浏览器(默认系统 Edge,无需额外下载 chromium)
# 若想用捆绑 chromium:删除 config/settings.yaml 中 crawl.browser.channel 一行后
# playwright install chromium
```
## 快速开始(先有数据)
> 招聘站普遍有反爬风控。**请保持低频、真实浏览器、按实际需要抓取**;被拦截即停止,不要试图绕过。
```bash
# 1) 生成样本 JD(验证全链路;51job 被 WAF 拦截时用)
jdcollector seed
# 2) 真实爬取(按 config/sites.yaml 的关键词/城市;51job 需本机有 Edge 且有头窗口)
jdcollector crawl
# 3) 规则分析(可选加 LLM 精分,见下文「LLM 多供应商精分」)
jdcollector analyze
# 4) 岗位群像报告
jdcollector portrait
# 5) 静态 HTML 报告站(输出到数据目录 site/)
jdcollector view
```
数据默认写在仓库根 `data/`(已被 .gitignore 忽略,不会入库)。
## 作为 MCP 服务器使用
启动后,外部 AI 就能通过 MCP 调用你的数据。
```bash
# stdio(默认,给本地桌面客户端用)
jd-mcp
# 只读模式(只暴露查询,不暴露爬取/分析等写工具)
jd-mcp --no-write-tools
# HTTP(streamable-http,给远程客户端 / 其它进程用,可带 Bearer token)
jd-mcp --transport http --host 0.0.0.0 --port 8000 --token 你的token
```
### Claude Desktop
编辑 `claude_desktop_config.json`:
```json
{
"mcpServers": {
"jdcollector": {
"command": "jd-mcp",
"args": ["--transport", "stdio"]
}
}
}
```
### Claude Code
```bash
claude mcp add jdcollector -- jd-mcp --transport stdio
claude mcp list # 验证已连接
```
### Cursor
Settings → MCP → `+ Add global MCP server`,command 填:
```
jd-mcp --transport stdio
```
## MCP 工具一览
| 类型 | 工具 | 说明 |
|------|------|------|
| 只读 | `get_stats` | 数据汇总统计(总数 / 分类计数) |
| 只读 | `list_categories` | 列出岗位分类及其样本数 |
| 只读 | `search_jobs` | 按关键词 / 分类 / 城市 / 公司搜索 JD(返回标题、薪资、技能等) |
| 只读 | `get_job` | 按 job_id 取单条 JD 完整记录 |
| 只读 | `get_portrait` | 某分类群像报告(JSON) |
| 只读 | `get_portrait_markdown` | 某分类群像报告(Markdown) |
| 写 | `crawl_jobs` | 本地爬取 JD(需 Playwright / 浏览器);返回结构化结果 `{added, elapsed_s, per_site, warnings}`,传 `_meta.progressToken` 可接收逐任务进度通知 |
| 写 | `run_analysis` | 规则分析(可选 LLM 精分) |
| 写 | `run_portrait` | 生成各分类群像报告 |
| 写 | `build_site` | 生成静态 HTML 报告站 |
| 写 | `sync_data` | 把数据目录提交 / 推送到其 git 仓库 |
另注册只读 resources:`jd://stats`、`jd://portrait/{category}`。
## HTTP 部署与鉴权
```bash
jd-mcp --transport http --host 0.0.0.0 --port 8000 --token 你的token
# 环境变量亦可:JD_MCP_TRANSPORT / JD_MCP_HOST / JD_MCP_PORT / JD_MCP_TOKEN
```
客户端连 `http://127.0.0.1:8000/mcp`,请求头带 `Authorization: Bearer 你的token`。
生产环境建议放在反向代理(Nginx / Caddy)后面并启用 TLS;不要直接暴露公网明文端口。
## 数据目录与 git 同步
数据根目录由环境变量 `JD_DATA_DIR` 指定,默认 `<仓库根>/data`(gitignored):
| 环境变量 | 作用 |
|----------|------|
| `JD_DATA_DIR` | 数据根目录;可以是普通文件夹,也可以是独立 git 仓库 |
| `JD_DATA_REPO` | 覆盖 sync/push 的目标仓库 URL(不填则用数据仓库的 `origin`) |
| `JD_GIT_TOKEN` | HTTPS 内嵌 token,**仅本次 push 使用**(不写入 git 配置) |
`sync_data` / `jdcollector sync` 的判定逻辑:
- 数据目录**不是 git 仓库** → 仅本地保存,跳过 git;
- 数据目录**嵌在其它仓库内**(比如工具仓库自己的 `./data`)→ 跳过 git,防止数据被提交进公开仓库;
- 数据目录是**独立 git 仓库** → `add` → `commit` → `pull --rebase` → `push`。
例子:数据放私有 GitHub 仓库
```bash
set JD_DATA_DIR=D:\jd-data
cd D:\jd-data && git init && git remote add origin git@github.com:you/jd-data.git
# 推送时可用
set JD_GIT_TOKEN=ghp_xxx
```
## LLM 多供应商精分
`config/settings.yaml` 的 `llm:` 段:
```yaml
llm:
enabled: true # 关闭即纯规则分析
provider: deepseek # 选供应商
```
| 供应商 | `provider` | 环境变量 | 默认模型 | 能力档位 |
|--------|-----------|----------|----------|----------|
| Anthropic Claude | `claude` | `ANTHROPIC_API_KEY` | `claude-sonnet-5` | L3 schema 严格 |
| OpenAI | `openai` | `OPENAI_API_KEY` | `gpt-4o` | L3 schema 严格 |
| Google Gemini | `gemini` | `GEMINI_API_KEY` | `gemini-2.5-flash` | L3 schema 严格 |
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek-chat` | L2 JSON 模式 |
| 通义千问 | `qwen` | `DASHSCOPE_API_KEY` | `qwen-plus` | L2 JSON 模式 |
| Ollama(本机) | `ollama` | 无 | `qwen2.5:7b` | L2 JSON 模式 |
**能力梯子**:统一 `LlmClient` 抽象,按供应商能力自动选择结构化输出形态——L3 用各家原生 schema 严格模式(Claude `output_config` / OpenAI `response_format.json_schema` / Gemini `response_schema`),L2 用 JSON 模式(DeepSeek / Qwen 的 `response_format.json_object`、Ollama 的 `format:"json"`),L1 纯 prompt 兜底;当前档位失败自动降级。输出统一经 Pydantic 校验,缺失 / 非法时带错误反馈重试一次,仍失败则回退规则结果,不中断流程。
`provider: claude` 时,顶层 `model` / `api_key_env` 仍向后兼容覆盖预设;其它供应商请在 `llm.providers.<name>` 下配置(各字段含义见文件内注释)。
## 项目结构
```
config/ # YAML 配置:settings / sites / categories / skills
src/jdcollector/
crawler/ # 各站点爬虫
analysis/ # 规则分类 + llm_client 能力梯子 + llm 精分
portrait/ # 岗位群像报告
view/ # 静态 HTML 报告站
mcp_server.py # MCP 服务器(工具注册 + CLI 入口)
sync_github.py # 数据目录 git 同步(独立仓库保护)
tests/ # pytest 单元测试
```
## 免责声明(Disclaimer)
> ⚠️ 使用本项目前请务必阅读以下条款。
1. **用途限制**:本项目仅用于个人学习、数据分析与技术交流,不构成任何商业用途,也不构成求职 / 雇佣决策的依据。
2. **数据由使用者自备并自负责任**:爬取行为发生在你自己的机器上,所有数据合规责任由使用者承担。请遵守目标网站的服务条款与 robots.txt,以及所在地法律法规(如《个人信息保护法》《数据安全法》《反不正当竞争法》)。
3. **抓取边界**:仅抓取公开页面;不抓取需登录、非公开的个人信息;不破解验证码、不规避 WAF / 封禁、不使用代理池或规模化采集,不以任何方式干扰目标网站正常服务。被拦截即停止,绝不升级对抗手段。
4. **数据准确性**:JD 内容为站点公开信息,可能过期或不准确,作者不保证其真实、完整、可用;内置 `seed` 样本数据仅用于验证全链路,不代表任何真实招聘信息。
5. **AI 输出仅供参考**:LLM 精分 / 群像结论由第三方模型生成,可能存在偏差,请人工复核后使用。
6. **风险自负**:本项目按 MIT License 开源提供,作者不对因使用本项目产生的任何直接或间接损失、数据泄露或法律风险承担责任。
## License
[MIT](LICENSE) © 2026 NaoYun777
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues