PyMuPDF提取PDF简历文本不全及区块分类错误的技术求助
解决PyMuPDF提取简历PDF文本的两大问题:提取不全与区块识别错误
问题分析
- 文本提取不全:常见原因包括PDF是扫描生成的图片格式(无原生文本)、文本被图层遮挡、或使用默认提取参数未捕获所有文本块。
- 区块识别/章节归属错误:简历布局灵活,PyMuPDF默认按PDF内部流顺序返回文本块,而非视觉阅读顺序;且简单的关键词匹配逻辑容易误判,导致内容跨章节归属。
解决方案及代码示例
以下是优化后的脚本,同时解决上述两个问题:
import fitz import pytesseract from PIL import Image def extract_and_classify_resume(pdf_path): doc = fitz.open(pdf_path) text_blocks = [] for page in doc: # 提取带坐标的原生文本块 page_text = page.get_text("dict") if page_text["blocks"]: # 遍历所有文本块,提取有效文本及位置、格式信息 for block in page_text["blocks"]: if "lines" in block: for line in block["lines"]: for span in line["spans"]: clean_text = span["text"].strip() if clean_text: text_blocks.append({ "text": clean_text, "top": block["bbox"][1], "font_size": span["size"], "is_bold": bool(span["flags"] & 1) }) else: # 无原生文本,判定为扫描件,执行OCR pix = page.get_pixmap(dpi=300) # 提高DPI提升OCR准确率 img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples) ocr_lines = pytesseract.image_to_string(img, lang="chi_sim").split("\n") for line in ocr_lines: clean_line = line.strip() if clean_line: # 模拟扫描件文本块的位置顺序 text_blocks.append({ "text": clean_line, "top": len(text_blocks), "font_size": 12, "is_bold": False }) # 按文本块顶部y坐标排序,还原视觉阅读顺序 text_blocks.sort(key=lambda x: x["top"]) # 定义目标章节及匹配规则 target_sections = { "个人信息": [], "教育背景": [], "工作经历": [], "项目经验": [], "技能特长": [] } current_section = None # 章节标题关键词+格式特征(加粗/大字号)双重判定 section_rules = { "个人信息": {"keywords": ["个人信息", "基本信息"], "min_font_size": 14}, "教育背景": {"keywords": ["教育背景", "教育经历"], "min_font_size": 14}, "工作经历": {"keywords": ["工作经历", "职业经历"], "min_font_size": 14}, "项目经验": {"keywords": ["项目经验", "项目经历"], "min_font_size": 14}, "技能特长": {"keywords": ["技能", "专业技能"], "min_font_size": 14} } for block in text_blocks: text = block["text"] # 检查是否匹配章节标题 matched_section = None for section, rules in section_rules.items(): if any(k in text for k in rules["keywords"]) and \ (block["font_size"] >= rules["min_font_size"] or block["is_bold"]): matched_section = section break if matched_section: current_section = matched_section continue # 跳过标题本身,只收集内容 # 将内容归入当前匹配的章节 if current_section is not None: target_sections[current_section].append(text) # 合并章节内容为可读字符串 final_result = {sec: "\n".join(content) for sec, content in target_sections.items()} return final_result # 测试调用 if __name__ == "__main__": resume_data = extract_and_classify_resume("test_resume.pdf") for section, content in resume_data.items(): print(f"=== {section} ===") print(content if content else "无匹配内容") print("\n")
关键优化点
解决提取不全:
- 优先提取带坐标的原生文本,确保捕获所有可访问的文本块;
- 自动检测扫描件PDF,调用OCR工具补充提取图片中的文本;
- 提高OCR的DPI参数,提升识别准确率。
解决区块/章节归属错误:
- 按文本块的顶部y坐标排序,严格遵循视觉阅读顺序;
- 采用**关键词+格式特征(字号/加粗)**的双重判定规则,减少标题误判;
- 动态切换当前归属章节,确保后续文本块归入正确分类。
额外优化建议
- 针对多列布局的简历:可通过文本块的x坐标划分左右列,先处理完左列所有内容再处理右列;
- 调整章节规则:根据目标简历的格式,修改
section_rules中的关键词、字号阈值; - 加入段落合并:若相邻文本块的y坐标差小于设定阈值,可合并为同一段落,提升内容可读性。
内容的提问来源于stack exchange,提问作者emma
相关产品推荐
相关产品推荐

