Jhatchi/Cyber-Job-Hunter

GitHub: Jhatchi/Cyber-Job-Hunter

自动化网络安全职位聚合器,通过个人资料评分优化求职流程。

Stars: 0 | Forks: 0

# 网络安全求职猎手 基于个人资料评分的自动化网络安全职位聚合器,配有实时 Streamlit 仪表板。在 BeCode 布鲁塞尔蓝队与红队训练营期间独立构建,目标是获得 2026 年 9 月的实习机会。 [![持续集成](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/7c76fae540224701.svg)](https://github.com/Jhatchi/Cyber-Job-Hunter/actions/workflows/ci.yml) [![测试](https://img.shields.io/badge/tests-357%20passing-brightgreen.svg)](#项目指标) [![覆盖率](https://img.shields.io/badge/coverage-89%25-brightgreen.svg)](#项目指标) [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml) [![类型检查](https://img.shields.io/badge/mypy-strict-blue.svg)](pyproject.toml) [![代码风格检查](https://img.shields.io/badge/ruff-bandit_S-black.svg)](pyproject.toml) [![许可证](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE) [![领英](https://img.shields.io/badge/LinkedIn-Johan--Emmanuel%20Hatchi-0A66C2?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/johan-emmanuel-hatchi/) ## 截图 ![列表视图](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/4d9d3deaac224707.png)
详情与统计视图 ![详情视图](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/873637e719224714.png) ![统计视图](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/3dcaa4a6a5224721.png)
## 功能 - **爬取 18 个网络安全职位来源**,覆盖比利时、卢森堡和欧盟(大型咨询公司、专业网络安全公司、公共部门、ENISA、远程职位聚合器)。 - **为每个职位评分 0 到 100 分**,基于可调的个人资料(目标职位、资历、语言、位置),并提供逐行分解说明分数缘由。 - **在 Streamlit 仪表板中呈现结果**,支持 CSV 导出,具备“自上次运行以来新增”的检测功能以及 10 多种筛选器。 ## 技术栈 **核心:** Python 3.11+, httpx, BeautifulSoup4, lxml, feedparser, pydantic v2, SQLModel (SQLite), loguru, click **HTTP 缓存:** hishel (ETag, Last-Modified) **仪表板:** Streamlit, pandas **质量保障:** pytest + respx, ruff (带 bandit `S` 选择器), mypy strict, GitHub Actions CI ## 快速开始 ``` git clone https://github.com/Jhatchi/Cyber-Job-Hunter.git && cd Cyber-Job-Hunter python3.11 -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt #### python scripts/init_db.py && python scripts/run_scrape.py && streamlit run dashboard/app.py Dashboard at `http://localhost:8501`. ## 项目指标 | Metric | Value | |---|---| | Python LOC (`src` + `tests` + `dashboard` + `scripts`) | 12 257 | | Tests | 357 passing | | Coverage on `src/` | 89% (Streamlit UI excluded) | | Active scrapers | 18 across 6 categories | | Type safety | mypy `strict = true` | | Security lint | ruff with `S` (bandit) selector | | CI | GitHub Actions: ruff + mypy + pytest on every push | Run locally: ```bash pytest --cov=src --cov-report=term #### 运行 ruff check . && mypy src ## 架构 ``` config/ (profile.yaml + sources.yaml) | v BaseScraper (抽象基类) 速率限制,抖动,指数退避, 断路器,robots.txt,机器人检测 | +----------+-----------+ v v REST / RSS / Workday HTML 爬虫 | | +----------+-----------+ v JobBase (Pydantic v2) | v filters.py (拒绝规则,网络安全相关性门控) | v scoring.py (0-100分,含可解释的分解说明) | v storage.py (基于 SQLModel 的 SQLite,SHA-256 去重) | +------+-------+ v v #### CSV 导出 Streamlit 仪表板 `BaseScraper` 中集中了反滥用逻辑:每个爬虫(REST、RSS、Workday、HTML)都无需重复即可继承速率限制、退避、断路器和 `robots.txt` 解析。新增来源仅需实现其特定领域的解析逻辑。 ## 评分引擎 每个职位根据可调的个人资料 (`config/profile.yaml`) 评分 0 到 100 分。分数是**可解释的**:仪表板的详情标签页会显示每条触发的规则,包括匹配的关键词和拒绝原因。 **主要信号:** - `+30` 目标职位匹配(SOC 分析师,IAM,渗透测试员,GRC 初级,...) - `+15` 初级 / 实习生 / 培训生 / 0-2 年经验 - `+10` 布鲁塞尔地区,或“毕业生项目” - `+5` 每个技术关键词(跨 7 个网络安全类别,上限 `+30`) **扣分与拒绝条件:** - `-20` “必须硕士”且无替代方案 - 自动拒绝:`5年以上经验`,高级 / 主管 / 经理级别,要求荷兰语 B2+ 但无英语或法语后备,既无目标职位也无技术关键词(网络安全相关性门控)
#### 完整规则集 +30 目标职位匹配(SOC 分析师,IAM,渗透测试员,GRC 初级,等等) +15 “初级、实习生、培训生、0-2年经验” +10 标题中包含“年轻毕业生” 或 描述中包含“毕业生项目” +5 每个匹配的技术关键词(上限 +30),7个网络安全类别 +10 布鲁塞尔 +5 瓦隆区、卢森堡、比利时-卢森堡后备选项 +10 法语 + 英语 +8 仅英语 +8 仅法语 +5 荷兰语“优先考虑” -5 “要求学士”且无替代方案 -20 “必须硕士”且无替代方案 -10 “3年以上经验” 拒绝(分数 = 0): - “5年以上经验”、高级、主管、经理、首席、团队负责人 - 要求荷兰语 B2/C1/C2 且无英语或法语替代方案 - 佛兰德地区但未提及“仅需英语” #### - 网络安全相关性门控:既无目标职位也无技术关键词
## 来源 18 个活跃的爬虫,分为 6 个类别: | 类别 | 来源 | |---|---| | **大型咨询公司与 ESN** | KPMG, Capgemini, Sopra Steria, Accenture, Devoteam, EPAM | | **专业网络安全公司** | NVISO, Toreon, Orange Cyberdefense, EASI, Nexova, Cream | | **比利时公共部门** | Smals, Actiris, Travaillerpour | | **欧盟机构** | ENISA | | **聚合器** | Remotive | | **其他比利时科技公司** | itsme | 爬取技术涵盖 REST JSON、RSS、Workday CXS、Next.js `_next/data`、XML 站点地图和纯 HTML。每个来源在 [`config/sources.yaml`](config/sources.yaml) 中有自己的配置块。
包含技术与国家/地区的完整来源表 | 来源 | 类型 | 国家/地区 | 备注 | |---|---|---|---| | [Remotive](https://remotive.com) | REST JSON | 远程 | 严格服务条款:4 次请求/天,24 小时延迟,需注明来源。 | | [NVISO](https://nviso.eu/jobs/) | HTML | BE, DE, GR, AT | 专业网络安全公司,2026年4月离开 Recruitee。 | | [itsme](https://itsme-id.com) | Recruitee API | BE | 布鲁塞尔数字身份平台。 | | [EASI](https://easi.net/en/jobs) | HTML | BE | ESN,瓦隆区和佛兰德地区。 | | [Smals](https://www.smals.be/en/jobs/list) | HTML (Drupal) | BE | 比利时社会保障 ICT 服务。 | | [Cream by Audensiel](https://www.creamconsulting.com/jobs) | HTML | LU | 网络安全 ESN,卢森堡。 | | [Travaillerpour.be](https://travaillerpour.be) | HTML (Drupal) | BE | 联邦职位门户(FOD, SPF, NCCN)。 | | [Actiris](https://www.actiris.brussels) | XML sitemap + HTML | BE | 布鲁塞尔就业服务,每次运行获取最近 40 个职位。 | | [Accenture](https://www.accenture.com/be-en/careers) | Workday CXS API | BE | 已应用比利时筛选条件。 | | [KPMG Belgium](https://kpmg-career.talent-soft.com) | RSS (TalentSoft) | BE | 完整源,在下游进行网络安全过滤。 | | [Capgemini](https://www.capgemini.com/be-en/jobs) | REST (Azure) | BE | 已预设 `search=cyber`。 | | [Orange Cyberdefense](https://jobs.orangecyberdefense.com) | HTML (TeamTailor) | BE, EU | 职位列表加上每个职位的详细信息补充。 | | [Devoteam](https://www.devoteam.com/jobs) | REST (GCP Cloud Talent) | BE | 原生国家筛选器。 | | [Sopra Steria](https://careers.soprasteria.be) | HTML (Attrax) | BE | 详情页的 JSON-LD `JobPosting`。 | | [Nexova Group](https://www.nexovagroup.eu) | HTML | BE | 网络安全与国防,ESA-Redu SOC。 | | [EPAM](https://careers.epam.com/en/jobs/belgium) | Next.js `_next/data` | BE | 从 `__NEXT_DATA__` 动态提取构建 ID。 | | [Toreon](https://www.toreon.com/jobs/) | HTML | BE | 专业网络安全咨询,安特卫普总部。 | | [ENISA](https://www.enisa.europa.eu/careers) | HTML | EU | 欧盟网络安全机构,雅典总部。 |
**延迟来源**(记录在 `config/sources.yaml` 中):CCB 和 EGov Select(Akamai 反机器人)、cybersecurity.lu(React SPA,无公开 JSON)、Spotit、Moovijob.lu(Cloudflare)、CERT-EU(需欧盟 SECRET 安全许可)、LinkedIn(计划加入,注意服务条款)。 ## 反滥用与伦理 职位信息是公开数据,但负责任地爬取它们并非易事。集中处理于 `BaseScraper`: - **遵守 `robots.txt`**:每次抓取前通过 `urllib.robotparser` 检查。 - **诚实 `User-Agent`**:标识项目,并附带专用的 Proton Pass 联系人别名(可撤销)。 - **速率限制**:每个域名 2 到 5 秒,加上随机抖动。 - **指数退避**:针对瞬时错误:5 秒、15 秒、45 秒(最多 3 次重试),然后触发断路器。 - **域名断路器**:连续 3 次 4xx 或 5xx 错误会禁用该来源 1 小时。 - **检测 Cloudflare 和验证码**:通过单词边界正则表达式,遇到则干净中止(无重试风暴)。 - **对终止性 4xx 不重试**(404,403 当非机器人相关时)。 - **分页上限**:可配置每个来源(默认 5)。 - **默认禁用 LinkedIn 和 Indeed**。 聚合器不收集申请人或招聘人员的个人数据。SQLite 数据库保存在本地。无第三方分析,无遥测数据。 ## 已知限制 - **无 JavaScript 渲染。** Cloudflare 保护或完全客户端渲染的来源(Moovijob.lu、cybersecurity.lu、Spotit、EGov Select)已延迟。添加 Playwright 可解决,但会增加 CI 复杂性和运行时间:这是有意的权衡,而非疏忽。 - **Streamlit UI 未纳入覆盖率计算。** 89% 的覆盖率适用于 `src/`。仪表板小部件是手动测试的。添加 `streamlit-testing` 在待办事项中,但优先级低于发布新爬虫。 - **评分是基于规则的,非机器学习。** 权重根据用户个人资料手动调整。计划增加点赞/点踩反馈循环和机器学习评分(Sprint 4)。 - **单一个人资料,本地 SQLite。** 无多用户,无远程数据库。设计为个人工具,非 SaaS。迁移到 Postgres + 多个人资料是增量功能,但超出当前范围。 - **地理范围:比利时、卢森堡、欧盟机构、远程。** 未覆盖法国/荷兰/德国。添加容易(新增 YAML 条目),只是当前焦点不在此。 - **暂无警报功能。** 新职位会在仪表板中显示,但无邮件或推送通知。Gmail SMTP 摘要配合 launchd cron 是下一个里程碑(Sprint 3)。 ## 路线图 - ✅ **Sprint 1** (2026 年 4 月):项目初始化,Pydantic 模型,评分引擎,过滤器,SQLite 存储,4 个爬虫。 - ✅ **Sprint 2** (2026 年 4 月):Streamlit 仪表板,“自上次运行以来新增”检测,14 个额外爬虫(Smals, Cream, Travaillerpour, Actiris, Accenture, KPMG, Capgemini, Orange Cyberdefense, Devoteam, Sopra Steria, Nexova, EPAM, Toreon, ENISA),网络安全相关性门控。 - 🚧 **Sprint 3**:通过 launchd cron 的 Gmail SMTP 摘要,Forem, StepStone, Jobat(若服务条款允许),Workday Proximus。 - 🚧 **Sprint 4**:Anthropic 驱动的求职信草稿,带安全措施的 LinkedIn 数据接入,基于点赞/点踩反馈训练的机器学习评分。 ## 项目结构 ``` Cyber-Job-Hunter/ pyproject.toml ruff, mypy strict, pytest config requirements.txt .env.example config/ profile.yaml, sources.yaml src/ models.py Job, ScoreResult, ScrapeRun config.py Pydantic loaders filters.py rejection rules, cyber relevance gate scoring.py 0-100 with explainable breakdown deduplication.py SHA-256 content hash storage.py JobRepository (SQLite) scrapers/ base.py + 18 concrete scrapers dashboard/ Streamlit app, 3 views scripts/ init_db.py, run_scrape.py, export_csv.py #### tests/ 357 测试, respx mocks ## 贡献指南 Personal portfolio project, but issues and PRs are welcome. Code conventions in [`CONTRIBUTING.md`](CONTRIBUTING.md). ## 许可证 [MIT](LICENSE), 2026 Jhatchi. ## 关于 Built solo by **Johan-Emmanuel Hatchi** ([GitHub](https://github.com/Jhatchi) · [LinkedIn](https://www.linkedin.com/in/johan-emmanuel-hatchi/)) during the [BeCode Brussels](https://becode.org) Blue & Red Team bootcamp (November 2025 to September 2026). Open to cybersecurity internship opportunities starting September 2026 in Belgium. ```
标签:DNS解析, HTTP缓存, Kubernetes, Python开发, Python编程, SQLite, Streamlit仪表板, Web scraping, 前端仪表板, 安全职位, 安全规则引擎, 实习项目, 实时更新, 开发实践, 开源情报, 开源项目, 数据导出, 数据库管理, 数据缓存, 数据聚合, 欧盟职位, 求职工具, 测试覆盖, 用户配置文件, 网络安全, 网络抓取, 网页解析, 职位猎手, 职位聚合, 自动化抓取, 蓝队红队, 评分系统, 过滤器, 运行时操纵, 逆向工具, 隐私保护