library(tidyverse)
library(docxtractr)
最近看到烟草局招聘,想报个名,结果发现招聘信息表都放在pdf里,不方便做筛选,于是想用R来提取数据框并处理一下。
1 提取pdf中数据框的常见方案
回顾用R从pdf中读取数据的常见方案及其弊端:
-
实际上就是用正则表达式清洗文本数据,步骤比较繁琐。
表格页数较多或者表格的格式较复杂的时候容易出错。
-
需要配置java,非常麻烦。
提取的结果不准确。
-
- 需要在网站上注册,每次使用还需要输入账号和密码。
- 提取的结果不准确。
下面这个表格存在单元格内换行的情况,用pdftools
根本就无从下手,用tabulizer
或pdftables
也容易出错。
2 用docxtractr
提取
我发现了一个包doxtractr
可以很轻松的提取word中的数据,对于一些格式复杂的pdf可以转换成word,然后用doxtractr
包读取数据。
为什么pdf转换成word后就能准确提取表格了呢?我猜测这是因为pdf是一种矢量结构,不具备并不会用code注明哪些元素是表格哪些元素是文字,pdf中的元素只有位置的区别而没有属性的区别。而word会标明哪些元素是表格,就像在编程里声明了表格这种class,因此容易提取。
将pdf用word打开并另存为word后,用docxtratr
包的read_docx()
读入
<- read_docx("071052144z0f.docx")
docs docs
Word document [071052144z0f.docx]
Table 1
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 2
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 3
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 4
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 5
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 6
total cells: 88
row count : 8
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 7
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 8
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 9
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 10
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 11
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 12
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 13
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 14
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 15
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 16
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 17
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 18
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 19
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 20
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 21
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 22
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 23
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 24
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 25
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 26
total cells: 77
row count : 7
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
Table 27
total cells: 33
row count : 3
uniform : likely!
has header : likely! => possibly [用人单位, 具体单位, 岗位名称, 岗位简介(主要职责描述), 岗位代码, 招聘人数, 所需专业名称, 学历学位, 政治面貌, 毕业年限, 备注]
No comments in document
可以看到文档中的表格被自动识别,并且推断出的表格的表头都是正确的。
使用docx_extract_tbl()
提取表格
docx_extract_tbl(docs, tbl_number = 1)
# A tibble: 7 × 11
用人单位 具体单位 岗位名称 岗位简介.主要职责描述. 岗位代码 招聘人数
<chr> <chr> <chr> <chr> <chr> <chr>
1 河南省烟草专卖局(… 内设机构 经济运… 负责经济运行管理等工… 10101 1
2 河南省烟草专卖局(… 内设机构 科技项… 负责科技项目管理等工… 10102 1
3 河南省烟草专卖局(… 内设机构 企业法… 负责法治建设等工作。 10103 1
4 河南省烟草专卖局(… 内设机构 资金管… 负责会计核算工作;负… 10104 1
5 河南省烟草专卖局(… 内设机构 营销管… 负责卷烟营销数据采集… 10105 1
6 河南省烟草专卖局(… 内设机构 营销管… 负责卷烟营销数据采集… 10106 1
7 河南省烟草专卖局(… 内设机构 综合管… 负责行政后勤管理等工… 10107 1
# ℹ 5 more variables: 所需专业名称 <chr>, 学历学位 <chr>, 政治面貌 <chr>,
# 毕业年限 <chr>, 备注 <chr>
这里我们的pdf有27页,每页的表格都是固定的表头,可以用docx_extract_all_tbls()
提取全部表格再按行合并。
<- docx_extract_all_tbls(docs)
tbls <- bind_rows(tbls)
recruitment recruitment
# A tibble: 164 × 11
用人单位 具体单位 岗位名称 岗位简介.主要职责描述. 岗位代码 招聘人数
<chr> <chr> <chr> <chr> <chr> <chr>
1 河南省烟草专卖局… 内设机构 经济运行… 负责经济运行管理等工… 10101 1
2 河南省烟草专卖局… 内设机构 科技项目… 负责科技项目管理等工… 10102 1
3 河南省烟草专卖局… 内设机构 企业法律… 负责法治建设等工作。 10103 1
4 河南省烟草专卖局… 内设机构 资金管理… 负责会计核算工作;负… 10104 1
5 河南省烟草专卖局… 内设机构 营销管理… 负责卷烟营销数据采集… 10105 1
6 河南省烟草专卖局… 内设机构 营销管理… 负责卷烟营销数据采集… 10106 1
7 河南省烟草专卖局… 内设机构 综合管理… 负责行政后勤管理等工… 10107 1
8 河南省烟草专卖局… 内设机构 网络安全… 负责网络和信息安全等… 10108 1
9 河南省烟草专卖局… 内设机构 质量监督… 负责烟草制品质量监督… 10109 1
10 中国烟草河南进出… 内设机构 会计(审… 负责会计核算工作;负… 10110 1
# ℹ 154 more rows
# ℹ 5 more variables: 所需专业名称 <chr>, 学历学位 <chr>, 政治面貌 <chr>,
# 毕业年限 <chr>, 备注 <chr>
数据的提取到这里就完成了,可以进行下一步的分析,或者将数据导出成excel。