工作360
支持任何专业领域的自动化英国求职系统。聚合来自50个来源的作业,根据您的个人资料(简历、领英、GitHub或手动偏好)对其进行0-100的评分,跨来源进行重复数据消除,并通过CLI、电子邮件、Slack、Discord、CSV、富终端表和Next.js前端(由FastAPI支持)交付结果。如果没有个人资料,默认为AI/ML求职。
API文档(自动生成)
后端运行后(cd backend && python main.py),API交互式文档在 http://localhost:8000/docs (Swagger用户界面)和 http://localhost:8000/redoc (ReDoc)。两者都是由FastAPI路由装饰器+Pydantic模型生成的,无需单独维护。
建筑
flowchart TD
CLI["CLI (Click)\njob360 run / view / api / status / sources / setup-profile"]
Cron["Cron 4AM/4PM\nEurope/London"]
subgraph Sources["50 Job Sources"]
direction LR
subgraph Keyed["Keyed APIs (7)"]
A1[Reed.co.uk]
A2[Adzuna]
A3[JSearch]
A4[Jooble]
A5[Google Jobs\nSerpApi]
A6[Careerjet]
A7[Findwork]
end
subgraph Free["Free APIs (10)"]
B1[Arbeitnow]
B2[RemoteOK]
B3[Jobicy]
B4[Himalayas]
B5[Remotive]
B6[DevITjobs]
B7[Landing.jobs]
B8[AIJobs.net]
B9[HN Jobs]
B10[YC Companies]
end
subgraph ATS["ATS Boards (10) — ~104 companies"]
C1[Greenhouse\n25 companies]
C2[Lever\n12 companies]
C3[Workable\n8 companies]
C4[Ashby\n9 companies]
C5[SmartRecruiters\n6 companies]
C6[Pinpoint\n8 companies]
C7[Recruitee\n8 companies]
C8[Workday\n15 companies]
C9[Personio\n10 companies]
C10[SuccessFactors\n3 companies]
end
subgraph RSS["RSS/XML Feeds (8)"]
D1[jobs.ac.uk]
D2[NHS Jobs]
D3[WorkAnywhere]
D4[WeWorkRemotely]
D5[RealWorkFromAnywhere]
D6[BioSpace]
D7[University Jobs\n6 UK unis]
D8[UK GOV FindAJob]
end
subgraph Scrapers["HTML Scrapers (7)"]
E1[LinkedIn\nguest API]
E2[JobTensor]
E3[Climatebase]
E4[80000Hours]
E5[BCS Jobs]
E6[AIJobs Global]
E7[AIJobs AI]
end
subgraph Other["Other (5 + 1 stats)"]
F1[Indeed / Glassdoor\npython-jobspy]
F2[HackerNews\nAlgolia API]
F3[TheMuse]
F4[NoFluffJobs]
F5[Nomis\nUK GOV stats]
end
end
CLI -->|"--source / --dry-run / --no-email"| Orchestrator["Orchestrator\nsrc/main.py"]
Cron -->|triggers| Orchestrator
Sources -->|async fetch\nrate-limited + retries| Orchestrator
Orchestrator --> Scorer["Scorer\nTitle 40 + Skills 40\nLocation 10 + Recency 10\n− Negative penalty 30\n− Foreign location 15"]
Scorer --> Dedup[Deduplicator\nnormalized company+title]
Dedup --> DB[(SQLite\nSeen Jobs + Run Log)]
DB --> Channels{NotificationChannel ABC}
Channels --> Email[Email\nHTML + CSV]
Channels --> Slack[Slack\nBlock Kit]
Channels --> Discord[Discord\nEmbeds]
DB --> CSV[CSV Export]
DB --> Report[Markdown Report]
DB --> RichTable[Rich Terminal Table\ncli view]
DB --> NextJS[Next.js Frontend\nvia FastAPI]特性
工作来源(48)
- 7个关键API:Reed,Adzuna,JSearch,Jooble,Google Jobs(SerpApi),Careerjet,Findwork-如果没有API密钥集,请优雅地跳过
- 10个免费API:Arbeitnow、RemoteOK、Jobice、喜马拉雅山、远程、DevITjobs、Landing.jobs、AIJobs.net、HN jobs、YC公司——无需任何配置即可工作
- 10个ATS板:Greenhouse(25)、Lever(12)、Workable(8)、Ashby(9)、SmartRecruiters(6)、Pinpoint(8)
- 8个RSS/XML源:jobs.ac.uk、NHS工作、WorkAnywhere、WeWork Remotely、RealWorkFromAnywhere、BioSpace、大学工作(6个英国大学)、英国政府FindAJob
- 7个HTML抓取器:LinkedIn(API嘉宾),JobTensor,Climatebase,80000Hours,BCS Jobs,AIJobs Global,AIJobs-AI
- 5其他:确实/Glassdoor(通过python jobspy,可选)、HackerNews(Algolia)、TheMuse、NoFluffJobs
- 1市场情报:Nomis(英国政府职位空缺统计)
配置文件系统(任何域)
- CV解析:上传PDF或DOCX,提取技能、职位、教育、证书
- LinkedIn丰富:导入LinkedIn个人资料PDF(个人资料→ More → 保存为PDF)--职位、技能、教育
- GitHub丰富:获取公共仓库,从语言和主题中推断技能
- 交互首选项:目标头衔、技能、地点、工资范围、工作安排
- 动态关键字:个人资料生成个性化搜索查询、相关性关键字和评分标准
- 向后兼容:没有配置文件=与以前相同的AI/ML搜索
评分(0-100)
- 锦标赛 (0-40分)——完全匹配=40,部分匹配=20,关键字重叠=5
- 技能匹配 (0-40分)——初级技能3分,中级2分,高等1分(上限为40分)
- 位置 (0-10分)——目标英国位置=10,远程=8
- 近期性 (0-10分)-0-1天=10,1-3天=8,3-5天=6,5-7天=4,7+天=0
- 负关键字惩罚 (-30分)-与无关职位(销售、护理等)匹配的职位将受到处罚
- 国外地点罚款 (-15分)-非英国地区(美国各州、欧盟国家等)的工作将受到惩罚
- 经验水平检测 --从头衔中解析高级、领导、初级、校长等
数据质量
- HTML实体解码 --清洁
&,<等 - 公司名称清洁 -去掉后缀(如“Ltd”、“Inc”、“Limited”)和区域标签(如“UK”、“EMEA”),以实现一致的重复数据消除
- 薪资异常值过滤 --忽略不切实际的工资值(\500k)
通知(可扩展)
- 电子邮件 --通过Gmail SMTP提供包含热门职位、分数、应用链接和CSV附件的HTML摘要
- Slack --通过webhook发送包含前10个作业的丰富Block Kit消息
- Discord 的中文翻译是“不和谐”或“纷争”。 --通过webhook嵌入前10个作业的消息
- 通知频道ABC --通过实现一个类来添加新频道(例如Telegram)
CLI(单击)
run--完整的管道--source,--dry-run,--log-level,--db-path,--no-email选项view--丰富的终端表--hours,--min-score,--source,--visa-only,--db-path过滤器setup-profile--交互式配置文件向导--cv,--linkedin,--github选项api--启动FastAPI后端服务器(由Next.js前端使用)status--显示数据库中的上次运行统计信息sources--列出所有48个可用来源
前端(Next.js+FastAPI)
- Next.js 16+React 19+顺风4+shadcn
frontend/ - 与FastAPI对话(
backend/src/api/)通过HTTP——25条路由(健康、作业、操作、配置文件、搜索、管道) - 带有过滤器、分数雷达、时间段的工作列表
- 个人资料设置:简历上传、LinkedIn个人资料PDF导入、GitHub用户名、偏好表
- 应用管道看板
基础设施
- 去重 --来自不同来源的同一份工作被标准化的公司+头衔合并
- 持续跟踪 --SQLite数据库可防止跨运行的重复通知
- 签证标记 --自动标记提及签证/赞助关键字的工作
- 异步速率限制 --每源并发+延迟(可在settings.py中配置)
- 重试逻辑 --3次指数回退尝试(1s、2s、4s)+每个请求30秒超时,每个源120秒超时
- Cron调度 —
cron_setup.sh设置英国时间凌晨4点/下午4点(欧洲/伦敦) - 日志记录 --旋转文件处理程序(最大5MB,3个备份)+控制台输出
- 干运行模式 --无需写入数据库或发送通知即可获取和评分
- 自动清洗 --每次运行时,超过30天的作业都会自动删除
- 拆分要求 --产品开发
backend/pyproject.toml,dev/test inrequirements-dev.txt - 强化设置 --Python 3.9+版本检查、幂等安装、.env验证
测试(600次通过(飞行前步骤0后))
| 测试文件 | 计数 | 它涵盖了什么 |
|---|---|---|
test_sources.py | 71 | 所有50个带有模拟HTTP的来源 |
test_profile.py | 55 | CV解析器、首选项、关键字生成器、JobScorer |
test_linkedin_github.py | 58 | LinkedIn PDF解析(section-split+LLM),GitHub API丰富 |
test_scorer.py | 53 | 评分算法、惩罚、最近度等级、边缘情况 |
test_time_buckets.py | 33 | 时间段分组逻辑 |
test_models.py | 21 | 工作数据分类、标准化、公司清理 |
test_notifications.py | 19 | 电子邮件、Slack、Discord发送 |
test_deduplicator.py | 13 | 跨源数据消除逻辑 |
test_main.py | 12 | 编排器集成 |
test_cli.py | 11 | CLI命令+选项+SOURCE_REGISTRY断言 |
test_database.py | 9 | SQLite操作、迁移、源历史 |
test_api.py | 9 | FastAPI端点(健康、作业、操作、配置文件、搜索、管道) |
test_llm_provider.py | 8 | CV解析的多提供商LLM客户端 |
test_notification_base.py | 7 | ABC、格式报警、频道发现 |
test_setup.py | 6 | setup.sh验证 |
test_reports.py | 6 | Markdown+HTML报表生成 |
test_rate_limiter.py | 5 | 异步速率限制器(获取/释放、并发、延迟) |
test_cron.py | 5 | cron_setup.sh验证 |
test_cli_view.py | 5 | 丰富的终端表查看器 |
test_csv_export.py | 4 | CSV导出格式 |
快速开始
# 1. Clone and setup
git clone https://github.com/Ranjith36963/job360.git
cd job360
bash setup.sh
# 2. Configure API keys (optional — free sources work without any keys)
nano .env
# 3. Run job search
source venv/bin/activate
python -m src.cli run
# 4. Single source / dry run
python -m src.cli run --source arbeitnow
python -m src.cli run --dry-run --log-level DEBUG
# 5. Set up a personalised profile
python -m src.cli setup-profile --cv path/to/cv.pdf
python -m src.cli setup-profile --cv cv.pdf --linkedin linkedin-profile.pdf --github yourusername
# 6. View results in terminal
python -m src.cli view --hours 24 --min-score 50
# 7. Start the API + frontend
python -m src.cli api # FastAPI on :8000
# (in another terminal) cd frontend && npm run dev # Next.js on :3000
# 8. Schedule (optional)
bash cron_setup.shCLI使用情况
# Full pipeline — fetch from all 50 sources, score, deduplicate, notify
python -m src.cli run
# Single source only
python -m src.cli run --source arbeitnow
python -m src.cli run --source reed
# Dry run — fetch and score, skip DB writes and notifications
python -m src.cli run --dry-run
# Skip email notifications
python -m src.cli run --no-email
# Debug logging
python -m src.cli run --log-level DEBUG
# Custom database path
python -m src.cli run --db-path /tmp/test.db
# Combine options
python -m src.cli run --source greenhouse --dry-run --log-level DEBUG
# Set up user profile (personalise for any domain)
python -m src.cli setup-profile --cv path/to/cv.pdf
python -m src.cli setup-profile --cv cv.pdf --linkedin linkedin-profile.pdf
python -m src.cli setup-profile --cv cv.pdf --github yourusername
python -m src.cli setup-profile --linkedin linkedin-profile.pdf --github user
# View jobs in Rich terminal table
python -m src.cli view
python -m src.cli view --hours 24 --min-score 50
python -m src.cli view --source reed --visa-only
python -m src.cli view --db-path /tmp/test.db
# Start the FastAPI backend (consumed by the Next.js frontend)
python -m src.cli api
# Show last run stats
python -m src.cli status
# List all available sources
python -m src.cli sourcesAPI密钥设置
| 来源 | 注册 | ENV变量 |
|---|---|---|
| Reed.co.uk | reed.co.uk/开发者 | REED_API_KEY |
| Adzuna | developer.adzuna.com | ADZUNA_APP_ID, ADZUNA_APP_KEY |
| JSearch | rapidapi.com/jsearch | JSEARCH_API_KEY |
| Jooble | jooble.org/api | JOOBLE_API_KEY |
| 谷歌工作 | 蛇网 | SERPAPI_KEY |
| Careerjet | careerjet.com/partners | CAREERJET_AFFID |
| 查找工作 | findwork.dev | FINDWORK_API_KEY |
| GitHub | GITHUB_TOKEN (可选,用于丰富配置文件) | |
| Gmail | 谷歌应用密码 | SMTP_EMAIL, SMTP_PASSWORD, NOTIFY_EMAIL |
| 松弛 | Slack Webhooks | SLACK_WEBHOOK_URL |
| 不和谐 | Discord Webhooks | DISCORD_WEBHOOK_URL |
免费来源(无需密钥):Arbeitnow,RemoteOK,Jobicy,喜马拉雅山,Remotive,DevITjobs,Landing.jobs,AIJobs.net,HN jobs,YC Companies,LinkedIn,Greenhouse,Lever,Workable,Ashby,SmartRecruiters,Pinpoint,Recruiteee,Workday,Personio,SuccessFactors,jobs.ac.uk,NHS jobs,WorkAnywhere,WeWorkRemotely,RealWorkFromAnywhere,BioSpace,University jobs,FindAJob,JobTensor,Climatebase,80000Hours,BCS jobs Nomis-41源代码在没有任何API密钥的情况下工作。
评分算法
| 组件 | 要点 | 工作原理 |
|---|---|---|
| 锦标赛 | 0-40 | 与目标标题完全匹配=40分。部分比赛=20分。关键字重叠=每个5分 |
| 技能匹配 | 0-40 | 主要技能=每项3分。中学=每人2分。三级=各1吨。上限为40 |
| 位置 | 0-10 | 目标英国位置=10pts。远程=8分 |
| 近期性 | 0-10 | 0-1天前发布=10分,1-3天=8分,3-5天=6分,5-7天=4分,7+天=0分 |
| 否定关键字 | -30 | 与无关职位(销售工程师、招聘人员、护士等)匹配的职位将被罚30分 |
| 国外地点 | -15 | 非英国地区(美国各州、欧盟国家等)将被罚15分 |
总计:0-100 --最低分数阈值为30(可在中配置 settings.py)
加载用户配置文件时,评分者使用配置文件中的动态关键字,而不是默认的AI/ML关键字。
通知渠道
通知系统使用抽象基类(NotificationChannel 在 backend/src/notifications/base.py)自动发现:
NotificationChannel (ABC)
├── EmailChannel — configured if SMTP_EMAIL + SMTP_PASSWORD + NOTIFY_EMAIL set
├── SlackChannel — configured if SLACK_WEBHOOK_URL set
└── DiscordChannel — configured if DISCORD_WEBHOOK_URL setget_configured_channels() 仅返回其环境变量已设置的通道。编排器在它们之间循环:
for channel in get_configured_channels():
await channel.send(new_jobs, stats)添加新频道 (例如Telegram):创建 backend/src/notifications/telegram_notify.py,实施 NotificationChannel,并在中注册 get_all_channels().
添加新作业源
- 创建
backend/src/sources/yoursource.py,延伸BaseJobSource - 实施
async fetch_jobs() -> list[Job] - 使用
self.relevance_keywords和self.job_titles用于过滤(非直接导入) - 如果自定义
__init__,接受search_config=None并传递给super().__init__(session, search_config=search_config) - 注册于
SOURCE_REGISTRYdict inbackend/src/main.py - 添加
_build_sources()列入backend/src/main.py(通过search_config=sc) - 在中添加费率限制条目
RATE_LIMITSdict inbackend/src/config/settings.py - 在中添加模拟测试
backend/tests/test_sources.py - 更新
len(SOURCE_REGISTRY) == N断言和预期源集backend/tests/test_cli.py - 如果键入:将env var添加到
backend/src/config/settings.py和.env.example
配置
默认关键字(backend/src/config/keywords.py)
- 25个职位:AI工程师、ML工程师、机器学习工程师、GenAI工程师、生成AI工程师、LLM工程师、NLP工程师、数据科学家、MLOps工程师、AI/ML工程师、深度学习工程师、计算机视觉工程师、RAG工程师、AI解决方案工程师、AI研究工程师、应用ML工程师、Python AI开发人员、AI研究员、ML科学家、机器学习科学家、AI平台工程师、AI基础设施工程师、会话AI工程师、应用科学家、研究科学家
- 15项基本技能 (每个3分):Python、PyTorch、TensorFlow、LangChain、RAG、LLM、生成式AI、拥抱脸、变形金刚、OpenAI、NLP、深度学习、神经网络、计算机视觉、即时工程
- 17项次要技能 (每个2分):Scikit-learn、Keras、AWS、SageMaker、Bedrock、Docker、Kubernetes、FastAPI、ChromaDB、FAISS、OpenSearch、Redis、pgvector、Gemini、Agent AI、LLM微调、微调
- 11高等技能 (各1份):CI/CD、MLF、Git、Linux、n8n、数据管道、ETL、功能工程、S3、CloudWatch、机器学习
- 英国24个地点 +远程/混合动力
- 60个负面标题关键字 涵盖12个类别(销售、IT运营、医疗保健、法律、金融等)
- 仅LLM CV解析 通过
backend/src/profile/llm_provider.py(多供应商:Gemini、Groq、Cerebras,提供免费套餐)。之前的391条记录KNOWN_SKILLS正则表达式集在提交3ba1342中被删除。
ATS公司(backend/src/config/companies.py)
- 温室 (25):DeepMind、Monzo、Deliveroo、Darktrace、Stability AI、Anthropic、Graphcore、Wayve、PolyAI、Synthesia、Wise、Snyk、Stripe、Cloudflare、Databricks、Dataiku、Ocado Technology、Tractable、Paddle、Harness、同构实验室、Speechmatics、Onfido、牛津纳米孔、彭博社
- 杠杆 (12) :Mistral、Healx、Palantir、Spotify、ZOE、Tractable、Helsing、SecondMind、MosaicML、Faculty、Dyson、Five AI
- 可行的 (8) :BenevolentAI、Exscientia、Oxa、Cervest、抱抱脸、Labelbox、Runway、Adept
- 阿什比 (9) :人类学、Cohere、OpenAI、Improbable、Synthesia、多元宇宙、ElevenLabs、困惑、任意尺度
- 智能招聘 (6) :Wise、Revolut、Checkout.com、阿斯利康、三星英国研发、预订
- 精确定位 (8) :MoneySuperMarket、Bulb、Starling Bank、Octopus Energy、Faculty、Arm、Sky、Tesco Technology
- 招聘人员 (8) :Peak AI、Satalia、语音图形、信号AI、特征技术、Causally、Kheiron Medical、PolyAI
- 工作日 (15) :阿斯利康、英伟达、壳牌、罗氏、诺华、思科、戴尔、英特尔、联合利华、汇丰、巴克莱、劳埃德银行集团、劳斯莱斯、葛兰素史克、捷豹路虎
- 个人 (10) :Celonis,贸易共和国,Sennder,知足,Personio,Forto,Taxfix,Wonderkind,Airfocus,Heydata
- 成功因素 (3) :英国宇航系统公司、QinetiQ、泰雷兹英国公司
项目结构
job360/
├── backend/src/
│ ├── main.py # Central orchestrator (run_search, SOURCE_REGISTRY)
│ ├── cli.py # Click CLI (run, view, api, status, sources, setup-profile)
│ ├── cli_view.py # Rich terminal table viewer (time-bucketed)
│ ├── models.py # Job dataclass with company normalisation
│ ├── api/ # FastAPI backend consumed by the Next.js frontend
│ ├── config/
│ │ ├── settings.py # Env vars, rate limits, timeouts, thresholds
│ │ ├── keywords.py # Default AI/ML keywords (KNOWN_SKILLS and KNOWN_TITLE_PATTERNS removed in commit 3ba1342)
│ │ └── companies.py # ATS company slugs (~104 companies across 10 platforms)
│ ├── profile/
│ │ ├── models.py # CVData, UserPreferences, UserProfile, SearchConfig
│ │ ├── cv_parser.py # PDF/DOCX text extraction; LLM-only skill/title extraction
│ │ ├── llm_provider.py # Multi-provider LLM client (Gemini/Groq/Cerebras) for CV parsing
│ │ ├── preferences.py # Form validation, CV+preferences merge
│ │ ├── storage.py # JSON persistence (backend/data/user_profile.json)
│ │ ├── keyword_generator.py # UserProfile -> SearchConfig conversion
│ │ ├── linkedin_parser.py # LinkedIn profile PDF parser (pdfplumber + LLM)
│ │ └── github_enricher.py # GitHub public API enricher
│ ├── sources/
│ │ ├── base.py # Abstract base with retry logic + rate limiting
│ │ └── *.py # 47 source files (48 registry entries)
│ ├── filters/
│ │ ├── skill_matcher.py # Scoring engine (0-100, 4 components + 2 penalties)
│ │ └── deduplicator.py # Cross-source dedup by normalised key
│ ├── notifications/
│ │ ├── base.py # NotificationChannel ABC + auto-discovery
│ │ ├── email_notify.py # Gmail SMTP (HTML + CSV attachment)
│ │ ├── slack_notify.py # Slack Block Kit via webhook
│ │ ├── discord_notify.py # Discord embeds via webhook
│ │ └── report_generator.py # Markdown + HTML report generation
│ ├── storage/
│ │ ├── database.py # Async SQLite (jobs + run_log tables, auto-purge)
│ │ └── csv_export.py # CSV export per run
│ └── utils/
│ ├── logger.py # Rotating file + console logging
│ ├── rate_limiter.py # Async semaphore + delay rate limiter
│ └── time_buckets.py # Time bucket grouping for CLI view
├── backend/tests/ # 600 passing (post-Step-0 pre-flight) across 20 files
│ ├── conftest.py # Shared fixtures (sample jobs)
│ └── test_*.py # 20 test modules
├── backend/data/ # Exports, reports, logs (gitignored)
├── backend/pyproject.toml # Production dependencies (17 packages)
├── requirements-dev.txt # Dev/test dependencies (pytest, aioresponses, fpdf2)
├── .env.example # Template for API keys and webhooks
├── setup.sh # Setup script (Python 3.9+ check, venv, deps)
└── cron_setup.sh # Cron scheduling (4AM/4PM Europe/London)测试
# Run all 600 passing (post-Step-0 pre-flight)
python -m pytest backend/tests/ -v
# Run specific test file
python -m pytest backend/tests/test_scorer.py -v
# Run with output
python -m pytest backend/tests/ -v -s所有600次通过(飞行前步骤0后)都通过了。每个源都用模拟的HTTP响应(aioresponses)进行了测试。无需网络访问。在Windows上跳过3个测试(仅对setup.sh和cron_run.sh进行bash测试)。
输出
每次运行都会产生:
| 输出 | 位置 | 描述 |
|---|---|---|
| CSV | backend/data/exports/jobs_YYYYMMDD_HHMMSS.csv | 带有分数的完整工作数据 |
| Markdown | backend/data/reports/report_YYYYMMDD_HHMMSS.md | 排名工作表 |
| 丰富的桌子 | 终端(python -m src.cli view) | 带过滤器的时间戳终端表 |
| 电子邮件 | 收件箱 | 包含热门作业的HTML摘要+CSV附件 |
| Slack | Channel | 屏蔽工具包消息,列出前10个工作 |
| Discord | Channel | 嵌入前10个职位的消息 |
| 前端 | http://localhost:3000 | Next.js UI(需要打开FastAPI :8000) |
| 控制台 | 终端 | 找到的新作业的时间戳摘要 |
| 日志 | backend/data/logs/job360.log | 旋转日志文件(5MB,3个备份) |
