【python办公自动化】将Word文本和Pdf表格数据提取并整合到同一个Exeel下的多sheet中

1. 背景及前期准备

1.1 背景介绍

在参加比赛过程中,需要获取江苏省科学技术奖近十年的数据,因此需要在官网上获取相应的数据,再查找数据的过程中发现,官网中给出的数据,并不是完整的可以直接拿来用的

比如:

① 2018-2019年的人员及项目名单是pdf的形式给出,

② 2015、2017年的内容直接附在发布的公告后面(纯文字的)

③ 2008-2011、 2014、2016年的内容是以doc的形式给出

④ 2012-2013年的可以找到xls形式数据

因此需要将数据进行整合,数据最后的表现形式就是每一年的数据,都提取整合到Excel表中。

具体要求:

① 将doc、pdf和网页里面的文字数据提取到Excel表格中,表格的名称为:xxx年年度江苏省科学技术奖.xlsx

扫描二维码关注公众号,回复: 11263944 查看本文章

② 将一、二、三等奖数据分别放置在该表格下的三个sheet中,sheet的名称为:一等奖、二等奖、三等奖

1.2 需要安装的库

这里用到python自带的库:os库(系统文件创建)、re(字符数据匹配)、glob(文件路径选择)

用到的python第三方库有:pandas(数据处理的)、pdfplumber(pdf表格数据提取)、python-docx(doc文本数据提取)

安装上诉第三方库,推荐使用镜像安装,安装的指令如下

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandas pdfplumber python-docx

2. 数据处理

2.1 数据提取

① 因为获取的doc形式的数据,使用python-docx库无法直接处理,所以将doc形式的数据转到新建的docx文件中

② 网页的文本数据,直接复制粘贴到docx文件中

③ xls数据直接转化为目标格式的xlsx数据

④ pdf数据直接提取表格数据

2.2 具体过程

2.2.1 docx数据的处理

难点:

① 目标数据的提取

② 一二三等奖的数据划分

③ 将数据写入同一个Excel表格的不同sheet中并命名

前面的数据提取已经将所有待处理的doc数据都转化为docx数据,这里进行数据提取,docx文件中的数据格式如下:
在这里插入图片描述
通过观察发现,docx中列举出的数据是有一定的数据格式的,因此可以将数据读取之后用正则表达式进行目标数据的匹配

这里以2016年的数据进行试错,代码如下

import re
from docx import Document
import pandas as pd

doc = Document('2016年度江苏省科学技术奖.docx')
content = ''
for paragraph in doc.paragraphs:
  content += paragraph.text

print(content[:1000])

→ 输出的结果为:(可以发现数据直接存在着空格,为了方便匹配数据,需要将空格先去掉)
在这里插入图片描述
接着进行空格的替换处理

s = content[:1000].replace('  ','')
print(s)

→ 输出的结果为:(之前的空格已经被剔除了)
在这里插入图片描述
★★★★★难点1: 提取目标字段的数据,这一步需要有一定正则匹配数据的功底,代码如下,提取的数据格式可以直接转化为用来生成DataFrame的数据

infos = re.findall(r'(\d+).(.*?)完成单位:(.*?)主要完成人:(\D+)',content)
data = pd.DataFrame(infos, columns = ['序号','项目名称','完成单位','完成人'])

→ 输出的结果为:(直接查看data变量的值,这里只列举部分)
在这里插入图片描述
★★★★难点2: 因为一、二、三等奖都是整个DataFrame中,因此困难在于找到数据的分割点,好在这里公布的数据是每个奖项进行排序,都是从1开始,因此只要找到1的位置并获取对应的索引即可,然后获取一、二、三等奖

split_row = data[data['序号'].isin(['1'])].index.tolist()
print(split_row)
data_1 = data.iloc[:split_row[1]]
data_2 = data.iloc[split_row[1]:split_row[2]]
data_3 = data.iloc[split_row[2]:]

→ 输出的结果为:(数据提取就是基于1所在的索引位置进行切片)

[0, 30, 78]

★★★ 难点3: 多DataFrame数据写入同一个Excel表格中,这里处理的方式属于先命名每一个sheet的名称,然后进行遍历数据写入,代码如下

ls = ['一等奖','二等奖','三等奖']
writer = pd.ExcelWriter('demo.xlsx')
for i in range(3):
    eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
writer.save()
writer.close()

→ 输出的结果为:(数据已经按要求整理好了,唯一需要手动清理的就是最后一行的多出来的一点数据)
在这里插入图片描述

2.2.2 docx数据的处理完整代码

保留数据接口,可以使用glob进行文件路径的获取,然后遍历循环进行所有文件数据的转化,可以查看之前的使用glob整合多个Excel文件

import re
from docx import Document
import pandas as pd

def filter_docx_data(file_name):
    doc = Document(f'{file_name}.docx')
    content = ''
    for paragraph in doc.paragraphs:
      content += paragraph.text
    # print(content[:1000])
    content = content.replace('\xa0','')
    infos = re.findall(r'(\d+).(.*?)完成单位:(.*?)主要完成人:(\D+)',content)
    data = pd.DataFrame(infos, columns = ['序号','项目名称','完成单位','完成人'])
    # print(data.head())
    split_row = data[data['序号'].isin(['1'])].index.tolist()
    # print(split_row)
    data_1 = data.iloc[:split_row[1]]
    data_2 = data.iloc[split_row[1]:split_row[2]]
    data_3 = data.iloc[split_row[2]:]
    
    ls = ['一等奖','二等奖','三等奖']
    writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
    for i in range(3):
        eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
    writer.save()
    writer.close()
    
if __name__ == '__main__':

  filter_docx_data('2016年度江苏省科学技术奖')
  

2.2.3 pdf数据的处理及完整代码

查看一下pdf的数据样式,文件中的数据如下:
在这里插入图片描述
针对表格数据的提取,这里使用到了pdfplumber模块,首先提取数据,这里进行第一页的表格数据的提取代码如下

import pdfplumber
import pandas as pd
import os

with pdfplumber.open("2018年度江苏省科学技术奖.pdf") as pdf:
     page_num = len(pdf.pages)
     data= pdf.pages[0].extract_table()
     print(data)

→ 输出的结果为:(可以发现pdf第一页表格的第一行是标题栏,对应提取表格的第一个元素,因此就可以获取第一个元素作为DataFrame数据的列标题)
在这里插入图片描述
接下来的处理就有点和docx数据的处理类似了,转化为DataFrame数据后进行一、二、三等奖的提取,最后再存入Excel中。

但是这里有个小细节的问题,2018年pdf的列举获奖名单的方式和2019年的不一样,其中2018年的是按照docx数据一样,一二三等奖都是以1开头,但是2019年的是只有一个1,其余的二三等奖的序号都是基于一等奖序号的累加,因此这里需要着重注意一下,代码如下

import pdfplumber
import pandas as pd
import os

#这一步是创建一个文件夹,将处理好的数据文件放置在其中
if not os.path.exists('filtered_data'):
    os.mkdir('filtered_data')

def filtering_data_2018(file_name):
    data_list = []
    with pdfplumber.open(f"{file_name}.pdf") as pdf:
        page_num = len(pdf.pages)
        data_columns = pdf.pages[0].extract_table()[0]
        for i in range(page_num):
            data_page = pdf.pages[i].extract_table()[1:]
            data_list.extend(data_page)
    
        data = pd.DataFrame(data_list,columns = data_columns)
        split_row = data[data['序号'].isin(['1'])].index.tolist()
        print(split_row)
        data_1 = data.iloc[:split_row[1]]
        data_2 = data.iloc[split_row[1]:split_row[2]]
        data_3 = data.iloc[split_row[2]:]
        
        ls = ['一等奖','二等奖','三等奖']
        writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
        for i in range(3):
            eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
        writer.save()
        writer.close()

def filtering_data_2019(file_name):
    data_list = []
    with pdfplumber.open(f"{file_name}.pdf") as pdf:
        page_num = len(pdf.pages)
        data_columns = pdf.pages[0].extract_table()[0]
        for i in range(page_num):
            data_page = pdf.pages[i].extract_table()[1:]
            data_list.extend(data_page)
    
        data = pd.DataFrame(data_list,columns = data_columns)
        split_row = data[data['序号'].isin(['46','129'])].index.tolist()
        print(split_row)
        data_1 = data.iloc[:split_row[0]]
        data_2 = data.iloc[split_row[0]:split_row[1]]
        data_3 = data.iloc[split_row[1]:]
        
        ls = ['一等奖','二等奖','三等奖']
        writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
        for i in range(3):
            eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
        writer.save()
        writer.close()

if __name__ == '__main__':
    filtering_data_2018('2018年度江苏省科学技术奖')
    filtering_data_2019('2019年度江苏省科学技术奖')

关于xls数据的处理,就不介绍了,本来数据整理的格式就是很好,只需要将表格的数据复制粘贴到对应的sheet中命名,最后另存为xlsx数据即可(只是为了和之前生成文件的格式一致)

3. 最终结果

数据处理完毕后,就会在创建的filtered_data文件夹下,如下图
在这里插入图片描述
代码测试所需要的文件已经全部上传到资源

猜你喜欢

转载自blog.csdn.net/lys_828/article/details/106160383