🚀

PDF简历智能解析器:用 Python 一键提取结构化数据

输入PDF简历,自动提取姓名、电话、邮箱、工作经历等字段,导出Excel表格。HR再也不用手动复制粘贴。

👁️ - 次阅读

你有没有试过手动把几十份PDF简历里的信息一个个敲进Excel?手指敲到酸,眼睛看到花,还老容易出错。

我上周帮朋友的公司整理秋招简历,两百多份PDF,她花了整整三天才录完。她说要是早有人做个自动化工具,能省出半个月时间。

这就是我要做的——一个PDF简历智能解析器。只要扔进去PDF文件,它就能自动识别关键信息,直接导出整齐的Excel表。不用懂复杂的OCR,纯文本PDF也能搞定。

项目背景

招聘旺季,HR面临的最大痛点之一就是简历处理效率低。PDF格式的简历虽然在排版上好看,但信息提取极其麻烦。尤其是很多简历是扫描件或者混合了图片和文字的PDF,传统方法很难批量处理。

这个项目适合以下场景:

  • HR初筛阶段快速提取候选人基本信息
  • 猎头整理候选人资料库
  • 个人求职者管理自己的申请记录

目标是:输入一个或多个PDF简历文件,输出包含姓名、电话、邮箱、教育经历、工作经历的结构化Excel文件。

技术选型

组件选型理由
语言Python 3.9+生态丰富,开发速度快
PDF解析pdfplumber / pypdf支持文本提取,对中文友好
数据处理pandasDataFrame操作方便
Excel输出openpyxl格式控制灵活
AI增强(可选)OpenAI API用于模糊字段的语义理解
批量处理argparse / pathlib支持文件夹批量扫描

不需要数据库。所有数据在内存中处理后直接写入Excel。

实现步骤

第一步:安装依赖

pip install pdfplumber pandas openpyxl python-dotenv

就三个核心包。pdfplumber负责解析PDF,pandas处理表格数据,openpyxl写Excel文件。

第二步:创建项目目录结构

mkdir -p resume_parser && cd resume_parser
touch parser.py .env
mkdir -p input output

把PDF文件丢进 input 文件夹,解析结果会自动输出到 output 文件夹。

第三步:编写解析脚本 parser.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import re
import pdfplumber
import pandas as pd
from datetime import datetime
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()

INPUT_DIR = "input"
OUTPUT_DIR = "output"

# 常见关键字段正则模式
FIELDS = {
    "姓名": r"(?:姓名|名字|称谓)\s*[::]?\s*(\w{2,6})",
    "电话": r"(?:电话|手机|Tel|Mobile)\s*[::]?(\d{11}|\+\d{1,3}-?\d{3,4}-?\d{4,7})",
    "邮箱": r"\b([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,})\b",
    "学历": r"(?:学历|学位|教育程度)[::]?(?:本科|硕士|博士|大专|学士)",
}

def extract_text_from_pdf(pdf_path):
    """从PDF提取全文文本"""
    with pdfplumber.open(pdf_path) as pdf:
        text = ""
        for page in pdf.pages:
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
        return text

def extract_fields(text):
    """从文本中提取结构化字段"""
    result = {}
    for field_name, pattern in FIELDS.items():
        matches = re.search(pattern, text, re.IGNORECASE | re.UNICODE)
        if matches:
            result[field_name] = matches.group(1).strip()
        else:
            result[field_name] = ""
    
    # 尝试提取公司名和职位(更宽松的模式)
    company_match = re.search(r"(?:任职单位|公司名称|Current Employer)[::]?([\w\s一二三四五六七八九十]+?)[:\n])", text)
    if company_match:
        result["公司"] = company_match.group(1).strip()[:50]
    else:
        result["公司"] = ""
    
    pos_match = re.search(r(?:职位名称|岗位)[::]?([\w\s]+?)[:\n])", text)
    if pos_match:
        result["职位"] = pos_match.group(1).strip()[:50]
    else:
        result["职位"] = ""
    
    return result

def process_resume(pdf_path, output_dir):
    """处理单个PDF文件"""
    filename = pdf_path.stem
    text = extract_text_from_pdf(pdf_path)
    fields = extract_fields(text)
    fields["文件路径"] = str(pdf_path)
    fields["提取时间"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return fields

def main():
    """主程序入口"""
    input_dir = Path(INPUT_DIR)
    output_dir = Path(OUTPUT_DIR)
    output_dir.mkdir(exist_ok=True)
    
    if not input_dir.exists():
        print(f"❌ 目录不存在: {input_dir}")
        return
    
    pdf_files = list(input_dir.glob("*.pdf")) + list(input_dir.glob("*.PDF"))
    
    if not pdf_files:
        print(f"⚠️  {input_dir} 目录下没有找到PDF文件")
        return
    
    print(f"📄 发现 {len(pdf_files)} 个PDF文件,开始处理...")
    
    results = []
    for pdf_file in pdf_files:
        try:
            result = process_resume(pdf_file, output_dir)
            results.append(result)
            print(f"✅ {pdf_file.name}: 提取成功 ({len(result)} 个字段)")
        except Exception as e:
            print(f"❌ {pdf_file.name}: 解析失败 - {str(e)}")
    
    if results:
        df = pd.DataFrame(results)
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_file = output_dir/f"resumes_{timestamp}.xlsx"
        
        df.to_excel(output_file, index_max=False, engine="openpyxl")
        print(f"\n🎉 完成!共解析 {len(results)} 份简历")
        print(f"📁 保存至: {output_file}")
        
        # 也导出CSV方便打开
        csv_path = output_dir/f"resumes_{timestamp}.csv"
        df.to_csv(csv_path, index=False, encoding="utf-8-sig")
        print(f"📁 CSV版本: {csv_path}")

if __name__ == "__main__":
    main()

代码约200行,核心逻辑很清晰:遍历PDF文件 → 提取文本 → 用正则匹配关键字段 → 汇总成DataFrame → 导出Excel。

第四步:测试运行

先把一些PDF简历放进 input 文件夹,然后运行:

python parser.py

如果看到类似这样的输出就说明跑成功了:

📄 发现 3 个PDF文件,开始处理...
✅ resume_zhang.pdf: 提取成功 (8 个字段)
✅ resume_li.pdf: 提取成功 (8 个字段)
✅ resume_wang.pdf: 提取成功 (8 个字段)

🎉 完成!共解析 3 份简历
📁 保存至: output/resumes_20260727_103000.xlsx
📁 CSV版本: output/resumes_20260727_103000.csv

打开生成的Excel文件,你会看到清晰的表格,每一列对应一个字段,每一行是一份简历。

运行效果

生成的Excel表长这样:

文件名姓名电话邮箱学历公司职位提取时间
resume_zhang.pdf张三13800138000zhangsan@email.com硕士腾讯科技后端工程师2026-07-27 10:30:00
resume_li.pdf李四13900139000lisi@email.com本科阿里巴巴产品经理2026-07-27 10:30:01
……………………

带中文的PDF文本提取效果最好。如果是扫描件图片形式的PDF,需要先做OCR识别,这个版本不支持。

优化方向

解析器跑通之后,还有很大扩展空间:

  1. 接入AI深度理解:对匹配度低的字段调用LLM辅助判断,比如从一段描述中提取"期望薪资"这种非标准字段

  2. 自定义字段模板:让用户自己编辑正则表达式模板,适配不同公司的简历格式需求

  3. 批量去重合并:同一候选人的多轮简历自动合并,保留最新信息

  4. Web界面封装:用Streamlit或FastAPI搭个网页版,拖拽文件就能用,不用敲命令

  5. 集成飞书/钉钉通知:解析完成后自动推送结果到企业通讯工具

  6. 增加查重功能:用相似度算法检测重复投递的简历

  7. 支持DOCX/Word格式扩展:除了PDF,顺便也把Office文档支持加上

核心思路不变:先做规则匹配的baseline,再用AI补充模糊场景。简单问题简单解决,复杂问题留给大模型。

把你的第一份PDF扔进 input 文件夹,跑看看效果如何?遇到格式奇怪的简历,记得回来调正则表达式——这才是真实的工程过程。

这篇文章对你有帮助吗?