原文: How to Build a Résumé Screening System Using Python and Multiprocessing

招聘合适的人选,往往从一项耗时的工作开始:筛选简历。如果你发布过职位招聘,一定体会过收件箱里有数百份申请,而你得花数小时手动审阅每份简历的烦恼。

本文将带你用纯 Python 搭建一个简历筛选系统,重点讲解核心编程概念和多进程的运用。你会创建一个自定义系统,通过将非结构化的简历文档转化为排名榜单,实现评估流程的自动化。

阅读完本指南后,你将能够:

  • 解析文档:使用 Python 从 PDF 和 DOCX 简历中提取文本
  • 提取信息:从简历内容中识别技能与关键词
  • 设计评分算法:用加权逻辑客观地为候选人排序
  • 构建 Web 界面:使用 Streamlit 完成
  • 部署应用:在 Streamlit Cloud 上部署应用,供公众访问

按照本教程操作,你将构建一个能在几秒内处理数百份简历的工具。

源代码见 GitHub 仓库

目录

  • 前置要求
  • 项目概览
  • 系统如何工作
  • 系统架构
  • 项目结构
  • 步骤 1:搭建项目
  • 步骤 2:构建简历解析器
  • 步骤 3:构建关键词提取器
  • 步骤 4:实现评分引擎
  • 步骤 5:构建 Web 界面
  • 步骤 6:测试系统
  • 步骤 7:部署应用
  • 总结

前置要求

要学习本教程,你需要具备:

  • Python 基础知识(函数、循环、字典)
  • 已安装 Python 3.8 或更高版本
  • 会用 pip 安装包
  • 代码编辑器(如 VS Code、PyCharm 或任意你喜欢的编辑器)

项目概览

本指南将开发一个系统:输入一个简历文件夹和一份职位描述(JD),系统会处理每份简历、提取相关信息,并根据候选人与职位要求的匹配程度计算得分。

系统如何工作

项目包含四个核心组件:

  • 简历解析器:读取 PDF 和 DOCX 文件并提取文本
  • 职位描述解析器:分析职位描述以识别所需技能
  • 关键词提取器:将简历内容与技能分类体系进行匹配
  • 评分引擎:使用加权算法对候选人排序

评分公式

使用的评分公式如下:

总分 =
(必备技能 × 50%)+
(优先技能 × 25%)+
(经验 × 15%)+
(关键词 × 10%)

这样设计可以确保核心技能比次要关键词权重更高。

这种方法如何有助于减少偏见

本系统基于预定义标准评估简历,而不是主观判断。每份简历都根据同一套必备技能、优先技能、经验指标和关键词进行打分。

由于所有候选人都使用同一套加权公式评估,写作风格、排版或个人偏好等主观因素不会影响排名。评分逻辑只关注简历与职位要求的匹配程度。

通过将评估过程标准化,系统促进了更一致、更客观的筛选,有助于在简历初筛阶段减少偏见。

系统架构

输入                    处理                       输出
─────                   ──────────                  ─────

简历 ──► 简历解析器 ──► 关键词提取器 ──┐
(PDF/DOCX)                             │
                                        ├──► 评分引擎 ──► 排名结果
职位描述 ──► 职位描述解析器 ────────────┘
(TXT/PDF)

系统遵循简单的“输入—处理—输出”流程。

简历和职位描述作为输入。简历解析器从每份简历中提取文本,职位描述解析器从职位描述中识别必备技能和优先技能。

提取出的简历文本随后传给关键词提取器,该模块根据预定义的技能分类体系匹配技能和关键词。

最后,评分引擎应用加权公式为每位候选人计算得分,并输出一份按分数排序的简历列表。

项目结构

resume_screening_system/
├── app.py                    # Streamlit Web 界面
├── main.py                   # 命令行界面
├── parsers/
│   ├── resume_parser.py      # PDF/DOCX 文本提取
│   └── jd_parser.py          # 职位描述解析
├── extractors/
│   └── keyword_extractor.py  # 技能与经验提取
├── matcher/
│   └── scorer.py             # 评分算法
├── data/
│   ├── config.json           # 评分权重配置
│   └── skills_taxonomy.json  # 技能数据库
└── requirements.txt          # 依赖

项目按清晰的模块化目录组织。解析逻辑、关键词提取和评分分别放在各自文件夹中,配置文件与数据单独存放,便于浏览、维护和扩展。

步骤 1:搭建项目

创建目录结构并设置虚拟环境:

mkdir resume_screening_system
cd resume_screening_system
mkdir parsers extractors matcher data input output
python -m venv venv

然后激活虚拟环境:

# Windows
source venv/Scripts/activate

# macOS / Linux
source venv/bin/activate

安装所需依赖:

pip install PyPDF2 python-docx streamlit pandas

步骤 2:构建简历解析器

简历解析器针对不同文件格式使用不同的提取方法。

对于 PDF,解析器逐页打开文档,用 PDF 阅读器从每页提取文本,再合并成单个字符串供后续处理。

对于 DOCX,解析器读取文档中的每个段落,将段落文本拼接成一块。这样无论简历格式如何,都能得到一致的文本输出。

将简历统一转为纯文本后,关键词提取和评分等组件就能高效工作。

文件: parsers/resume_parser.py

def _extract_pdf(self, file_path: Path) -> str:
    text = ""
    with open(file_path, "rb") as file:
        pdf_reader = PyPDF2.PdfReader(file)
        for page in pdf_reader.pages:
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
    return text.strip()

def _extract_docx(self, file_path: Path) -> str:
    from docx import Document
    doc = Document(file_path)
    return "\n".join(
        para.text for para in doc.paragraphs
    ).strip()

步骤 3:构建关键词提取器

本项目使用 Kaggle 上的简历数据集,确保逻辑在真实职业数据上可用。关键词提取器通过扫描简历文本来识别技能。

简历文本先转为小写,以便不区分大小写地匹配。预定义的技能分类体系存储每个技能及其可能变体,提取器用这些变体与简历文本比对。

匹配时使用词边界,避免部分匹配(例如在 “JavaScript” 里匹配到 “Java”)。匹配到的技能存入集合以避免重复。

这种方式能在所有简历上实现一致、可控的技能识别。

文件: extractors/keyword_extractor.py

def extract_skills(self, text: str) -> Set[str]:
    text_lower = text.lower()
    found_skills = set()

    for category, skills_dict in self.skills_taxonomy.items():
        for skill_name, variations in skills_dict.items():
            for variation in variations:
                # 防止 "Java" 匹配到 "JavaScript"
                pattern = r"\b" + re.escape(variation) + r"\b"
                if re.search(pattern, text_lower):
                    found_skills.add(skill_name)
                    break

    return found_skills

步骤 4:实现评分引擎

为得到客观排名,系统使用加权评分公式。

组件 权重 说明
必备技能 50% 核心技术需求
优先技能 25% 差异化竞争力
经验 15% 专业深度
关键词 10% 领域熟悉度
总分 =
(S_req × 0.50) +
(S_pref × 0.25) +
(E_exp × 0.15) +
(K_key × 0.10)

评分引擎用上述权重为每份简历计算最终得分。

它统计简历中出现的必备技能、优先技能、经验指标和关键词数量,每个数量乘以其对应权重(必备技能权重最高),加权值相加得到单一分数,再按该分数对简历排序,生成候选人排名列表。

步骤 5:构建 Web 界面

Streamlit 为简历筛选系统提供了简单的 Web 界面。

文本区域用于输入职位描述,文件上传器用于上传多份简历。点击按钮后,Streamlit 触发后端逻辑解析简历、提取数据并计算得分,结果在浏览器中展示,用户无需使用命令行即可完成筛选。

文件: app.py

import streamlit as st

jd_text = st.text_area(
    "在此粘贴职位描述:",
    height=300
)

uploaded_files = st.file_uploader(
    "上传简历文件:",
    type=["pdf", "docx", "txt"],
    accept_multiple_files=True
)

if st.button("筛选简历", type="primary"):
    st.success("正在处理简历...")

运行应用:

streamlit run app.py

应用将运行在 http://localhost:8500

步骤 6:测试系统

示例职位描述输入

下面是一份可用于测试的示例职位描述:

我们正在寻找一名具有扎实后端开发经验的高级 Python 开发工程师。

必备技能:
- Python
- Django
- REST API
- SQL

优先技能:
- PostgreSQL
- Docker
- AWS

经验要求:
- 3 年以上 Python 专业开发经验
- 有构建 Web 应用的经验

该输入帮助系统识别必备技能、优先技能和经验关键词,供评分引擎对简历排序。

python main.py

示例输出

============================================================
筛选结果
============================================================
第 1 名:Alice Johnson | 得分:85.42/100 | 匹配:python、django、postgresql
第 2 名:Carol Davis   | 得分:72.50/100 | 匹配:python、django

步骤 7:部署应用

若要让系统对外可访问:

  1. 将代码推送到 GitHub
  2. 打开 share.streamlit.io
  3. 选择你的 app.py 文件
  4. 部署应用

应用将发布在:

https://your-app-name.streamlit.app

总结

在本教程中,你使用 Python 从零搭建了一个完整的简历筛选系统。通过结合文本处理、结构化评分和自动化,该项目展示了如何将手动简历筛选转变为高效、客观的流程。

该系统有助于减少偏见、节省时间,并更一致地评估候选人。Happy coding!