使用 Python 和 Tkinter 构建简易职位推荐引擎
Source: Dev.to
是否曾想过创建一个根据你的技能推荐工作的桌面应用?在本教程中,我们将使用 Python、Tkinter 和 ttkbootstrap 构建一个 职位推荐引擎。
我们将涵盖:
- 项目搭建
- 定义职位数据结构
- 获取并筛选职位
- 构建简易推荐引擎
- 使用 Tkinter UI 显示结果
- 添加分页和搜索
让我们开始吧! 🚀
1. 设置与安装依赖
首先,确保已安装 Python 3。然后安装所需的包:
pip install ttkbootstrap pillow requests
包说明
| 包 | 用途 |
|---|---|
ttkbootstrap | 现代 Tkinter UI 样式 |
Pillow | 处理和显示图像(公司徽标) |
requests | 从 URL 获取徽标 |
2. 定义职位数据结构
我们将使用 dataclass 来表示每个职位。这使得存储和管理职位信息变得简单。
from dataclasses import dataclass
from typing import List
@dataclass
class Job:
title: str
company: str
url: str
description: str
skills: List[str]
location: str
logo_url: str = ""
score: float = 0.0
✅ 这为每个职位提供了标题、公司、地点、技能、徽标,以及用于推荐的评分。
3. 获取职位
在本教程中,我们将使用一个静态的职位列表。以后你可以将其替换为 API 调用。
from typing import List
def fetch_jobs(query: str) -> List[Job]:
jobs_data = [
Job(
"Python Developer",
"TechCorp",
"https://example.com/job1",
"Develop backend applications using Python.",
["Python", "Django"],
"Remote",
"https://via.placeholder.com/100x100.png?text=TechCorp",
),
Job(
"Frontend Engineer",
"Webify",
"https://example.com/job2",
"Build responsive web apps with React.",
["JavaScript", "React"],
"NY, USA",
"https://via.placeholder.com/100x100.png?text=Webify",
),
Job(
"Data Scientist",
"DataWorks",
"https://example.com/job3",
"Analyze large datasets and build ML models.",
["Python", "ML", "Pandas"],
"SF, USA",
"https://via.placeholder.com/100x100.png?text=DataWorks",
),
]
# Filter jobs by query keyword
query_tokens = set(query.lower().split())
matched_jobs = []
for job in jobs_data:
text_to_match = " ".join(
[
job.title.lower(),
job.description.lower(),
" ".join(job.skills).lower(),
]
)
if any(token in text_to_match for token in query_tokens):
matched_jobs.append(job)
return matched_jobs
💡 提示: 这个简单的搜索会匹配职位标题、描述或技能中的关键词。
4. 构建一个简单的推荐引擎
我们将根据关键字匹配为每个职位分配分数,以对结果进行排序。
def recommend_jobs(query: str, candidates: List[Job], top_n: int = 5):
query_tokens = set(query.lower().split())
recommendations = []
for job in candidates:
text_to_match = " ".join(
[
job.title.lower(),
job.description.lower(),
" ".join(job.skills).lower(),
]
)
score = sum(1 for token in query_tokens if token in text_to_match)
recommendations.append((job, score))
recommendations.sort(key=lambda x: x[1], reverse=True)
return recommendations[:top_n]
✅ 更高的分数意味着更好的匹配。这是一个简单的基于内容的推荐。
5. 加载公司标志
我们将使用 Pillow 在应用中获取并显示图像。
import io
import requests
from PIL import Image, ImageTk
logo_cache = {}
def load_image(url: str, size: tuple = (80, 80)):
"""Download an image, resize it, and cache the PhotoImage."""
if not url:
return None
if url in logo_cache:
return logo_cache[url]
try:
resp = requests.get(url, timeout=10)
resp.raise_for_status()
img = Image.open(io.BytesIO(resp.content))
img = img.resize(size, Image.ANTIALIAS)
photo = ImageTk.PhotoImage(img)
logo_cache[url] = photo
return photo
except Exception:
return None
💡 提示: 缓存可以避免多次下载相同的图像。
6. 构建 Tkinter UI
现在让我们使用 ttkbootstrap 构建用户界面。
import tkinter as tk
import ttkbootstrap as tb
from ttkbootstrap.widgets.scrolled import ScrolledText
# ----------------------------------------------------------------------
# Main window
# ----------------------------------------------------------------------
app = tb.Window(
title="Job Recommendation Engine",
themename="flatly",
size=(980, 720),
)
# ----------------------------------------------------------------------
# Top Section – Search Bar
# ----------------------------------------------------------------------
top = tb.Frame(app, padding=15)
top.pack(fill=tk.X)
tb.Label(
top,
text="Job Recommendation Engine",
font=("Segoe UI", 16, "bold"),
).pack(anchor=tk.W)
query_entry = tb.Entry(top, font=("Segoe UI", 12))
query_entry.pack(fill=tk.X, pady=8)
tb.Button(
top,
text="Search",
bootstyle="primary",
command=lambda: print("Search clicked!"),
).pack(anchor=tk.E)
# ----------------------------------------------------------------------
# Results Area
# ----------------------------------------------------------------------
result_frame = tb.Frame(app, padding=(15, 5))
result_frame.pack(fill=tk.BOTH, expand=True)
result_box = ScrolledText(result_frame, autohide=True)
result_box.pack(fill=tk.BOTH, expand=True)
text = result_box.text
text.configure(state="disabled", wrap="word")
# This is where job results will be displayed.
# ----------------------------------------------------------------------
# Pagination Controls
# ----------------------------------------------------------------------
nav = tb.Frame(app, padding=10)
nav.pack(fill=tk.X)
prev_btn = tb.Button(nav, text="← Prev", bootstyle="secondary")
prev_btn.pack(side=tk.LEFT)
page_label = tb.Label(nav, text="Page 1", font=("Segoe UI", 10))
page_label.pack(side=tk.LEFT, padx=10)
next_btn = tb.Button(nav, text="Next →", bootstyle="secondary")
next_btn.pack(side=tk.LEFT)
# ----------------------------------------------------------------------
# (Optional) Hook up pagination and search logic here
# ----------------------------------------------------------------------
💡 您现在可以将 Search、Prev 和 Next 按钮挂接到前面定义的函数,以在结果页面之间进行导航。
7. 综合示例
下面是一个将所有内容结合在一起的最小示例。可以随意添加更多功能(例如,详细的职位视图、保存收藏等)。
def display_results(recommendations):
"""Populate the ScrolledText widget with job cards."""
text.configure(state="normal")
text.delete("1.0", tk.END)
for job, score in recommendations:
# Load logo (cached)
logo = load_image(job.logo_url)
# Build a simple text block for each job
block = f"""\
{job.title} ({job.location})
Company: {job.company}
Score: {score}
Skills: {', '.join(job.skills)}
Link: {job.url}
"""
text.insert(tk.END, block + "\n" + "-" * 40 + "\n\n")
text.configure(state="disabled")
def on_search():
query = query_entry.get()
candidates = fetch_jobs(query) # In a real app, fetch all jobs first
recommendations = recommend_jobs(query, candidates, top_n=10)
display_results(recommendations)
# Bind the search button
search_btn = tb.Button(
top,
text="Search",
bootstyle="primary",
command=on_search,
)
search_btn.pack(anchor=tk.E, pady=5)
# Start the Tkinter main loop
if __name__ == "__main__":
app.mainloop()
就这样!现在你拥有一个使用 Python、Tkinter 和 ttkbootstrap 构建的功能完整的桌面职位推荐应用。 🎉
欢迎尝试更复杂的推荐算法、集成真实的职位 API,或进一步美化 UI。祝编码愉快!
将搜索输入与获取、推荐和显示职位关联
使用 threading 在执行搜索时保持 UI 响应。
import threading
def perform_search():
"""Called when the user presses the Search button."""
query = query_entry.get().strip()
if not query:
return
# Run the heavy work in a background thread
threading.Thread(target=search_thread, args=(query,), daemon=True).start()
def search_thread(query):
"""Background worker that fetches jobs, ranks them, and prints the results."""
candidates = fetch_jobs(query)
recommendations = recommend_jobs(query, candidates)
for job, score in recommendations:
print(f"{job.title} @ {job.company} | Score: {score}")
全屏控制
- 进入全屏模式
- 退出全屏模式
试一试
-
运行脚本
python job_recommender.py -
在搜索框中输入关键字(例如
Python或React)。 -
双击职位标题以打开其链接(如果你已经实现了此功能)。
-
使用 Prev / Next 按钮浏览结果。
完整源代码
完整项目已在 GitHub 上提供:
https://github.com/rogers-cyber/JOBREC
结论
恭喜! 🎉 现在你已经拥有一个可运行的 职位推荐引擎,具备以下功能:
- Python 数据类
- 简单的 基于内容的推荐
- 带有搜索、结果显示和分页功能的 Tkinter UI
后续步骤
- 用真实的 API 调用替换静态职位列表。
- 添加模糊匹配,实现更智能的搜索。
- 为 UI 增强图片、图标和过滤器等功能。
