0 引言

信息抽取任务旨在从非结构化的自然语言文本中提取结构化信息。在本系列项目中,将讨论如何又好又快地实现一个简历信息提取任务。

作为该系列文章的第一篇,我们将首先从数据处理着手,探讨Word、PDF格式文档信息提取的一些基本方法。

数据集简介

本文使用的简历数据集是脱敏之后的中文人才简历数据和标注数据。

标注类别包括:姓名、出生年月、性别、电话、最高学历、籍贯、落户市县、政治面貌、毕业院校、工作单位、工作内容、职务、项目名称、项目责任、学位、毕业时间、工作时间、项目时间共18个字段。

在训练数据集中,每个“毕业院校、学位、毕业时间”为一组,以“教育经历”列表给出;每个“工作单位、工作内容、职务、工作时间”为一组,以“工作经历”列表给出;每个“项目名称、项目责任、项目时间”为一组,以“项目经历”列表给出。

训练数据同时给出了PDF和Word格式。

1 word文档信息提取

1.1 认识.docx格式

现在.docx格式是我们最常见到的一种Word文档格式了,它是微软采用类XML格式标准定义的Word文件。

正因如此,相比早期的.doc文件,.docx文件的兼容性大幅提升。

那么,.docx文件又是如何封装的?.docx实际上是一个zip的压缩文件,比如我们任选一个.docx文件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDww3qlB-1636944651045)(https://ai-studio-static-online.cdn.bcebos.com/acc7880fa91247a5a2e3fa8e7c5d3670aacca1de565f4c84ad3eb59072898d34)]

再把它的文件名后缀直接修改为.zip

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nb8vRFMz-1636944651047)(https://ai-studio-static-online.cdn.bcebos.com/14181f975e9848699ec46d5462ea9b87c12ed7c9ccb74022a865ab353d6b25f9)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RG7tYJCb-1636944651048)(https://ai-studio-static-online.cdn.bcebos.com/ae2c0b4c43074dab8f07bda0e0ec7d596809c919ef6f4fb6bae0f83484460c22)]

打开这个压缩包,我们会看到,其实文档的正文,是以XML格式表示的,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h3PlibKu-1636944651049)(https://ai-studio-static-online.cdn.bcebos.com/2ad3cac751834ffc987521534a5f05c07b3866a1f7f9460a8db4367ccea01e13)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m00tpBaH-1636944651050)(https://ai-studio-static-online.cdn.bcebos.com/000a892628ac40dba8aeb042b5e6d951772bd02d00c74c2abf630b42dfab9f03)]

因此,其实除了python-docx库之外,BeautifulSoup也可以用来提取Word文档信息。

1.2 提取word文档信息

1.2.1 用python-docx提取文档信息

python-docx其实在项目PaddleHub机器翻译:文档的批量翻译中提到过

这里不做过多赘述,我们直奔主题,选取一份word简历文档,尝试提取信息。

# 解压缩数据集
!unzip data/data40148/train_20200121.zip
# 安装依赖库
!pip install python-docx
from docx import Document
from docx.shared import Inches
def get_paragraphs_text(path):
    """
    获取所有段落的文本
    :param path: word路径
    :return: list类型,如:
        ['Test', 'hello world', ...]
    """
    document = Document(path) 
    # 有的简历是表格式样的,因此,不仅需要提取正文,还要提取表格
    col_keys = [] # 获取列名
    col_values = [] # 获取列值
    index_num = 0
    # 表格提取中,需要添加一个去重机制
    fore_str = ""
    cell_text = ""
    for table in document.tables:
        for row_index,row in enumerate(table.rows):
            for col_index,cell in enumerate(row.cells):
                if fore_str != cell.text:
                    if index_num % 2==0:
                        col_keys.append(cell.text)
                    else:
                        col_values.append(cell.text)
                    fore_str = cell.text
                    index_num +=1
                    cell_text += cell.text + '\n'
    # 提取正文文本
    paragraphs_text = ""
    for paragraph in document.paragraphs:
        # 拼接一个list,包括段落的结构和内容
        paragraphs_text += paragraph.text + "\n"
    return cell_text, paragraphs_text

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjR1FCv3-1636944651051)(https://ai-studio-static-online.cdn.bcebos.com/d65ae7bb5eab45e0901df04f08837eb21e0968a120f6402cac257da88b8d99aa)]

# 提取文档信息,这是一个表格式简历
cell_text, paragraphs_text = get_paragraphs_text('resume_train_20200121/docx/0043e770a330.docx')
print(cell_text, paragraphs_text)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9GJ9ghq-1636944651051)(https://ai-studio-static-online.cdn.bcebos.com/c0cc78f2688c4f9ab4f9934ea2584b946826aafa4d914d8a8246882e94a71f1c)]

# 提取文档信息,这是一个表格正文混搭式简历(会出现一些混乱的情况,因为在这个文件里,标题是以表格形式存在)
cell_text, paragraphs_text = get_paragraphs_text('resume_train_20200121/docx/0052b7958e89.docx')
print(cell_text, paragraphs_text)
杜素宁
MOBILE : 15904130130
E-MAIL:0da08x@163.com
Address:云南省昭通市


个人信息


民族:汉
籍贯:云南省昭通市	
性别:女	
 年龄: 18
教育经历


2008.08-2012.08 
北方工业大学
食品科学与工程
学士学位
主要经历
Project Experience

1997.06-2010.07
江苏华英企业管理股份有限公司
水处理工程师
1991年12月-2012年09月
和宇健康科技股份有限公司
市场营销专员
2007/05-2010/03
深圳市有棵树科技有限公司
拼多多运营
个人技能
Personal Skills


个人荣誉
Personal Honor



 			   			     		  
 								   
工作经历:
工作内容:
1.负责部门内日常用品的采购;2.做好与公司内其他部门的对接工作;3.协助部门进行办公环境管理和后勤管理工作;4.销售人员与公司的信息交流,随时保持与市场销售人员的电话沟通,销售政策及公司文件的及时传达。5.领导交办的其他工作


                                       
工作经历:
工作内容:
1、做好消费宾客的迎、送接待工作,接受宾客各种渠道的预定并加以落实;2、礼貌用语,详细做好预订记录;3、了解和收集宾客的建议和意见并及时反馈给上级领导;4、以规范的服务礼节,树立公司品牌优质,文雅的服务形象。


                                       
工作经历:
工作内容:
1.负责规定区域的产品销售,做好产品介绍,确认订单,回款等销售相关工作;2.做好客户背景资料调查,竞争对手分析,产品适用性分析;3.按公司规定完成SalesPipeline信息记录


                                       
吃饭                                                
优秀学生干部

1.2.2 用BeautifulSoup提取Word文档信息

如果说这种方法有什么缺点的话,就是遇到一些艺术字等标题,与后面的文字从语义上是连续的,但是XML格式不连续。

# 安装依赖库
!pip install bs4
from zipfile import ZipFile
from bs4 import BeautifulSoup

document = ZipFile('resume_train_20200121/docx/0052b7958e89.docx')
xml = document.read("word/document.xml")
wordObj = BeautifulSoup(xml.decode("utf-8"))
texts = wordObj.findAll("w:t")
for text in texts:
    print(text.text)
杜素宁
MOBILE 
: 
15904130130
E-MAIL
:
0da08x@163.com
A
ddress
:云南省昭通市
个人信息
民族:
汉
籍贯:
云南省昭通市
性别:
女
 年龄
: 18
 
 
 
教育经历
2008.08-2012.08
 
北方工业大学
食品科学与工程
学士学位
 
 
主要经历
P
roject Experience
工作经历:
1997.06-2010.07
江苏华英企业管理股份有限公司
水处理工程师
工作内容:
1.负责部门内日常用品的采购;2.做好与公司内其他部门的对接工作;3.协助部门进行办公环境管理和后勤管理工作;4.销售人员与公司的信息交流,随时保持与市场销售人员的电话沟通,销售政策及公司文件的及时传达。5.领导交办的其他工作
 
工作经历:
1991年12月-2012年09月
和宇健康科技股份有限公司
市场营销专员
工作内容:
1、做好消费宾客的迎、送接待工作,接受宾客各种渠道的预定并加以落实;2、礼貌用语,详细做好预订记录;3、了解和收集宾客的建议和意见并及时反馈给上级领导;4、以规范的服务礼节,树立公司品牌优质,文雅的服务形象。
 
工作经历:
2007/05-2010/03
深圳市有棵树科技有限公司
拼多多运营
工作内容:
1.负责规定区域的产品销售,做好产品介绍,确认订单,回款等销售相关工作;2.做好客户背景资料调查,竞争对手分析,产品适用性分析;3.按公司规定完成SalesPipeline信息记录
 
个人技能
Personal
 Skills
吃饭
 
个人荣誉
P
ersonal Honor
优秀学生干部

2 使用pdfplumber库提取PDF信息

!pip install pdfplumber
import pdfplumber
import pandas as pd

with pdfplumber.open("resume_train_20200121/pdf/0052b7958e89.pdf") as pdf:
    page = pdf.pages[0]   # 第一页的信息
    text = page.extract_text()
    print(text)
杜素宁 
MOBILE : 15904130130 
E-MAIL:0da08x@163.com 
 
Address:云南省昭通市 
个人信息   
 
民族:汉  籍贯:云南省昭通市   性别:女     年龄: 18 
                           
教育经历   
 
2008.08-2012.08   北方工业大学  食品科学与工程  学士学位 
                     
主要经历   
Project Experience 
工作经历: 
1997.06-2010.07  江苏华英企业管理股份有限公司  水处理工程师 
工作内容: 
1.负责部门内日常用品的采购;2.做好与公司内其他部门的对接工作;3.协助部门进行办公环境管理和后勤管理工作;4.销
售人员与公司的信息交流,随时保持与市场销售人员的电话沟通,销售政策及公司文件的及时传达。5.领导交办的其他工作 
 
 
                                        
工作经历: 
1991年12月-2012年 和宇健康科技股份有限公司  市场营销专员 
09月 
工作内容: 
1、做好消费宾客的迎、送接待工作,接受宾客各种渠道的预定并加以落实;2、礼貌用语,详细做好预订记录;3、了解和
收集宾客的建议和意见并及时反馈给上级领导;4、以规范的服务礼节,树立公司品牌优质,文雅的服务形象。 
 
 
                                        
工作经历: 
2007/05-2010/03  深圳市有棵树科技有限公司  拼多多运营 
工作内容: 
1.负责规定区域的产品销售,做好产品介绍,确认订单,回款等销售相关工作;2.做好客户背景资料调查,竞争对手分析,
产品适用性分析;3.按公司规定完成SalesPipeline信息记录 
with pdfplumber.open("resume_train_20200121/pdf/0052b7958e89.pdf") as pdf:
    page = pdf.pages[0]   # 第一页的信息
    table = page.extract_tables()
    for t in table:
        # 得到的table是嵌套list类型,转化成DataFrame更加方便查看和分析
        df = pd.DataFrame(t[1:], columns=t[0])
        print(t)
[['个人信息', None, None, '', None, None, None], ['民族:汉', '', '籍贯:云南省昭通市', None, '', '性别:女', '年龄: 18']]
[['教育经历', None, None, '', None, None], ['2008.08-2012.08', '', '北方工业大学', None, '食品科学与工程', '学士学位']]
[['主要经历 \nProject Experience', '']]
[['1997.06-2010.07', '江苏华英企业管理股份有限公司', '水处理工程师']]
[['', '1991年12月-2012年', '', '和宇健康科技股份有限公司', '市场营销专员'], [None, '09月', None, None, None]]
[['2007/05-2010/03', '深圳市有棵树科技有限公司', '拼多多运营']]

因此,对于同时有表格(标题用表格表示)和正文交错的文档,pdfplumber也能很好地识别,如果是布局标准的纵向PDF,效果还是非常稳定的。

3 通过PPOCR识别PDF

这个方式看起来有点绕,如果可以直接识别PDF和word,为什么还要转图片用OCR呢?

不过,在很多时候,它还是一个很必要的补充手段,毕竟,如果简历的PDF是那种扫描式的,甚至word文档万一就是个图片……

手段多一些,总是有备无患的。

在本文中,我们尝试的是PP-Structure工具包,它提供了PDF图片表格一键提取解决方案。

# 安装依赖库
# pywt可能要重启内核
!pip install pywt -i https://mirror.baidu.com/pypi/simple
!pip install "paddleocr>=2.2" --no-deps -r requirements.txt
# 安装依赖库
!pip install -U https://paddleocr.bj.bcebos.com/whl/layoutparser-0.0.0-py3-none-any.whl
!pip install PyMuPDF
import datetime
import os
import fitz  # fitz就是pip install PyMuPDF
import cv2
import shutil
from paddleocr import PPStructure,draw_structure_result,save_structure_res
import numpy as np

3.1 PDF批量转图片

def pyMuPDF_fitz(pdfPath, imagePath):
    startTime_pdf2img = datetime.datetime.now()  # 开始时间

    print("imagePath=" + imagePath)
    pdfDoc = fitz.open(pdfPath)
    for pg in range(pdfDoc.pageCount):
        page = pdfDoc[pg]
        rotate = int(0)
        # 每个尺寸的缩放系数为4,这将为我们生成分辨率提高4的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 4  # (1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 4
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)

        if not os.path.exists(imagePath):  # 判断存放图片的文件夹是否存在
            os.makedirs(imagePath)  # 若图片文件夹不存在就创建

        pix.writePNG(imagePath + '/' + 'images_%s.png' % pg)  # 将图片写入指定的文件夹内

    endTime_pdf2img = datetime.datetime.now()  # 结束时间
    print('pdf转图片时间=', (endTime_pdf2img - startTime_pdf2img).seconds)
pdfDir = './resume_train_20200121/pdf'

def gci(filepath):
#遍历filepath下所有文件  
    files = os.listdir(filepath)  
    for fi in files:
        # 将转换的图片保存到对应imgs的对应子目录下     
        pyMuPDF_fitz(os.path.join(filepath,fi), os.path.join('imgs',fi[:-4]))
# 遍历PDF文件并转换图片。如果读者觉得转换时间比较长,可以提前中止cell。
gci(pdfDir)

3.2 对不同式样简历提取信息

下面这两张简历我们可以看出,对于一些表格式简历,版面分析会将其判定为表格。

其它的简历,可能被认为版面上是图片甚至既没有图片也没有表格。

如果使用PP-Structure,对这几种检测结果,需要分别进行后处理。

import cv2
import layoutparser as lp
image = cv2.imread('imgs/0043e770a330/images_0.png')
image = image[..., ::-1]

# 加载模型
model = lp.PaddleDetectionLayoutModel(config_path="lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config",
                                threshold=0.5,
                                label_map={0: "Text", 1: "Title", 2: "List", 3:"Table", 4:"Figure"},
                                enforce_cpu=False,
                                enable_mkldnn=True)
# 检测
layout = model.detect(image)

# 显示结果
show_img = lp.draw_box(image, layout, box_width=3, show_element_type=True)
show_img
from bs4 import BeautifulSoup
import re
# 表格类的预测结果已经封装在HTML标签中了
table_engine = PPStructure(show_log=True)
img = cv2.imread('imgs/0043e770a330/images_0.png')
result = table_engine(img)
result[0]['res']

# 折行问题需要在后续进一步解决
html = BeautifulSoup(result[0]['res'],'html.parser', from_encoding='utf-8')
list(html.strings)
['姓名',
 '郝淑宁',
 '性别',
 '男',
 '出生日期',
 '2000.04',
 '民族',
 '汉族',
 '联系电话',
 '13602173036',
 '籍贯',
 '黑龙江省双鸭山「邮箱 市',
 'bhluo@live.com',
 '教育背景',
 '毕业时间:',
 '2012.08 - 2016.08',
 '毕业学校:北京政法职业学院',
 '学历/学位:大学本科/学士学位',
 '专业:动物生产',
 '工作经验',
 '时间:1991年07月-2016年12月',
 '部门:研发部',
 '公司:江苏达科信息科技有限公司',
 '职位:渠道商务',
 '1、申请票据,购***,准备和报送会计报表,会报税及报税流程;2、现金及银行收付处理,制作记帐',
 '凭证,银行对帐,单据审核,开具与保管发票;3、协助财会文件的准备、归档和保管;4、固定资产和',
 '工作;',
 '低值易耗品的登记和管理;5、负责与银行、税务等部门的对外联络;6、协助领导完成其他日常事务性',
 '时间:1992年05月-2015年05月',
 '公司:盛趣信息技术有限公司部门:研发部',
 '职位:商场空调工5.5k',
 '1、根据公司制定的目标,制定有效销售计划,开发客户,完成销售任务;2、关注市场变化,收集有效',
 '的市场信息,为公司的销售策略作参考资料依据;3、做好客户管理工作,根据不同客户的需求特点和 相关的信息、数据,提供解决方案;4、统筹客户维系工作,做好客户拜访计划,并按计划进行拜访,',
 '推进项目;5、协助领导做好公司其他工作。',
 '时间:2006.06-2018.06',
 '公司:广州市华粤行仪器有限公司',
 '部门:研发部',
 '职位:Golang开发工程师',
 '1、登记收集资料,整理文件表格;2、辅助就业指导老师为鹏程学员推荐工作;3、发布招聘信息,与',
 '鹏程学员互动;4、对接好企业,为鹏程学员推荐心仪工作到面到岗服务。',
 '项目经验',
 '2001.12-2012.01 1、协助制定市场活动计划,组织落实市场活动;2、负责展会活动策划与相关活动支持,市场推广资料',
 '珠三角最低工资标准的执行、影响与对策研究']
import cv2
import layoutparser as lp
image = cv2.imread('imgs/0052b7958e89/images_0.png')
image = image[..., ::-1]

# 加载模型
model = lp.PaddleDetectionLayoutModel(config_path="lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config",
                                threshold=0.5,
                                label_map={0: "Text", 1: "Title", 2: "List", 3:"Table", 4:"Figure"},
                                enforce_cpu=False,
                                enable_mkldnn=True)
# 检测
layout = model.detect(image)

# 显示结果
show_img = lp.draw_box(image, layout, box_width=3, show_element_type=True)
show_img
with open(os.path.join('data', 'res.txt'), 'w', encoding='utf8') as f:
    for img in os.listdir('imgs/0043e770a330'):
        img_path = os.path.join(fi_d,img)
        img = cv2.imread(img_path)
        result = table_engine(img)
        print(result[0]['res'])
        for box, rec_res in zip(result[0]['res'][0], result[0]['res'][1]):
            f.write('{}\t{}\n'.format(np.array(box).reshape(-1).tolist(), rec_res))
table_engine = PPStructure(show_log=True)
img = cv2.imread('imgs/0052b7958e89/images_0.png')
result = table_engine(img)
result[0]['res']
for box, rec_res in zip(result[0]['res'][0], result[0]['res'][1]):
    print(rec_res[0])
杜素宁
MOBILE:15904130130
E-MAIL:0da08x@163.com
Address:云南省昭通市
个人信息
性别:女
民族:汉
籍贯:云南省昭通市
年龄:18
教育经历
北方工业大学
食品科学与工程
2008.08-2012.08
学士学位
主要经历
Project Experience
工作经历:
1997.06-2010.07
江苏华英企业管理股份有限公司
水处理工程师
工作内容:
1.负责部门内日常用品的采购;2.做好与公司内其他部门的对接工作;3.协助部门进行办公环境管理和后勤管理工作;4.销
售人员与公司的信息交流,随时保持与市场销售人员的电话沟通,销售政策及公司文件的及时传达。5.领导交办的其他工作
工作经历:
1991年12月-2012年
和宇健康科技股份有限公司
市场营销专员
09月
工作内容:
1、做好消费宾客的迎、送接待工作,接受宾客各种渠道的预定并加以落实;2、礼貌用语,详细做好预订记录;3、了解和
收集宾客的建议和意见并及时反馈给上级领导;4、以规范的服务礼节,树立公司品牌优质,文雅的服务形象
工作经历:
2007/05-2010/03
深圳市有棵树科技有限公司
拼多多运营
工作内容:
1.负责规定区域的产品销售,做好产品介绍,确认订单,回款等销售相关工作;2.做好客户背景资料调查,竞争对手分析
产品适用性分析;3.按公司规定完成SalesPipeline信息记录

4 小结

在本文中,我们探索并比较了Word、PDF、图片格式的简历文件信息提取方法,在后续项目中,将结合PaddleNLP的信息提取技术,尝试将非结构化的简历文件,提取成标注文件指定的格式,并验证性能。

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐