Python 및 Tkinter로 간단한 직업 추천 엔진 구축

발행: (2026년 1월 31일 오후 12:19 GMT+9)
8 min read
원문: Dev.to

Source: Dev.to

스킬에 기반해 직업을 추천해주는 데스크톱 앱을 만들고 싶으셨나요? 이 튜토리얼에서는 Python, Tkinter, 그리고 ttkbootstrap을 사용해 Job Recommendation Engine을 구축합니다.

다룰 내용:

  • 프로젝트 설정
  • 직업 데이터 구조 정의
  • 직업 가져오기 및 필터링
  • 간단한 추천 엔진 구축
  • Tkinter UI로 결과 표시
  • 페이지네이션 및 검색 추가

시작해봅시다! 🚀

1. 설정 및 의존성 설치

먼저 Python 3이 설치되어 있는지 확인하십시오. 그런 다음 필요한 패키지를 설치합니다:

pip install ttkbootstrap pillow requests

패키지 설명

패키지목적
ttkbootstrap현대적인 Tkinter UI 스타일링
Pillow이미지(회사 로고) 처리 및 표시
requestsURL에서 로고 가져오기

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

💡 Tip: 이 간단한 검색은 채용 제목, 설명 또는 기술에 포함된 키워드를 매칭합니다.

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}")

전체 화면 제어

  • 전체 화면 모드 진입
  • 전체 화면 모드 종료

직접 사용해 보기

  1. 스크립트를 실행합니다

    python job_recommender.py
  2. 검색 상자에 키워드(예: Python 또는 React)를 입력합니다.

  3. 작업 제목을 더블 클릭하여 링크를 엽니다(해당 기능을 구현한 경우).

  4. Prev / Next 버튼으로 결과를 탐색합니다.

전체 소스 코드

전체 프로젝트는 GitHub에서 확인할 수 있습니다:

https://github.com/rogers-cyber/JOBREC

결론

축하합니다! 🎉 이제 Job Recommendation Engine이 정상적으로 작동합니다. 주요 기능:

  • Python 데이터 클래스
  • 간단한 콘텐츠 기반 추천
  • 검색, 결과 및 페이지네이션이 포함된 Tkinter UI

다음 단계

  • 정적 직업 목록을 실제 API 호출로 교체합니다.
  • 더 똑똑한 검색을 위해 퍼지 매칭을 추가합니다.
  • 이미지, 아이콘 및 필터를 포함하도록 UI를 개선합니다.

Job Recommendation Engine Screenshot

Back to Blog

관련 글

더 보기 »