20210622_26期_办公自动化_Task4_Python 操作 PDF

2023-11-09 07:59

本文主要是介绍20210622_26期_办公自动化_Task4_Python 操作 PDF,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

四、Python 操作 PDF

在这里插入图片描述

目录

  • 四、Python 操作 PDF
        • 来源
    • 0 基础
    • 1 PDF拆分
    • 2 批量合并
    • 3. 提取文字内容
    • 4. 提取表格内容
    • 5. 提取图片内容
    • 参考资料


来源

Datewhle26期__Python办公自动化 :
https://github.com/datawhalechina/team-learning-program/tree/master/OfficeAutomation
作者:牧小熊、刘雯静、张晓东、吴争光、隆军

论坛地址:
http://datawhale.club/t/topic/1574


0 基础

  • 主要包括PdfFileReader Class,PdfFileMerger,PageObject Class,PdfFileWriter这四个大类还有一个其他类

在这里插入图片描述

1.The PdfFileReader Class

  • 初始化一个 PdfFileReader 对象A,此操作可能需要一些时间,因为 PDF 流的交叉引用表被读入内存。
  • PdfFileReader常用函数:
相关属性以及函数描述备注
decrypt(password)可以对加密的文档进行解密操作
documentInfo通过getDocumentInfo()函数功能访问的只读属性
getDestinationPageNumber(destination)检索目标对象的页数若错误则返回-1
getDocumentInfo()检索PDF文件的字典信息是否存在存在会返回相关信息,不存在则会返回None部分PDF文件使用的是元数据流
getFields(tree=None, retval=None, fileobj=None)如果此 PDF文档中包含交互式表单字段,则提取字段数据返回类型是字典或者None
getFormTextFields()从文档中检索带有文本数据(输入,下拉列表)的表单域
getNamedDestinations(tree=None, retval=None)检索文档中的特定的目标返回字典类型
namedDestinations通过getNamedDestinations()函数的只读属性
getNumPages()计算此PDF的页数
numPages通过getNumPages()函数的只读属性
getOutlines(node = None,outlines = None )检索文档中存在的文档大纲
outlines通过getOutlines()函数的只读属性
getPage(pageNumber )按编号检索页面就是找到某页内容
getPageLayout()获取页面布局返回类型为字符串
pageLayout通过getPageLayout()的只读属性
getPageMode()获取页面模式返回类型为字符串
pageMode通过getPageMode的只读属性
getPageNumber(页面)检索给定页面的页码
getXmpMetadata()从PDF文档根目录检索XMP(可扩展元数据平台)数据
xmpMetadata通过getXmpMetadata()的只读属性
isEncrypted显示此文档是否被加密的属性如果为True调用decrypt()解密之后属性依旧为True
  1. The PdfFileMerger Class:
  • 初始化一个PdfFileMerger对象B,其可以将多个pdf合并成 一个,可以串联、切片或者插入
  • PdfFileMerger常用函数
相关函数描述
addBookmark(title, pagenum, parent=None)将书签添加到这个pdf里面
addMetadata(infos)将自定义元数据添加到输出中
addNamedDestination(title, pagenum)将目标添加到输出。
append(fileobj, bookmark=None, pages=None, import_bookmarks=True)与merge()方法相同,但是假定您要将所有页面连接到文件末尾,而不是指定位置
close()关闭所有文件描述符(输入和输出)并清除所有内存使用情况
merge(position, fileobj, bookmark=None, pages=None, import_bookmarks=True)以指定的页码将页面从给定文件合并到输出文件中
setPageLayout(layout)设置页面布局
setPageMode(mode)设置页面模式
write(fileobj)将已合并的所有数据写入给定的输出文件
  1. The PdfFileObject Class:

此类表示PDF文件中的单个页面。通常,将通过访问类的getPage()方法 来创建此对象 PdfFileReader,但是也可以使用createBlankPage()静态方法来创建一个空页面

C = PyPDF2.pdf.PageObject(pdf=None, indirectRef=None)

其中参数
pdf:页面所属的PDF文件
indirectRef:在该对象的源PDF中存储对该对象的原始间接引用(通俗来讲就是)

相关属性以及函数描述备注
mergeRotatedTranslatedPage(page2, rotation, tx, ty, expand=False)类似于mergePage,但是要合并的流通过应用转换矩阵进行缩放
mergeScaledPage(page2, scale, expand=False)类似于mergePage,但是要合并的流通过应用转换矩阵进行转换和缩放
rotateClockwise(angle)顺时针旋转页面90度
rotateCounterClockwise(angle)逆时针旋转页面90度
scale(sx, sy)通过将变换矩阵应用于其内容并更新页面大小,以给定的因子缩放页面
  1. The PdfFileWriter Class

此类支持将PDF文件写出,给定由另一类产生的页面(通常为PdfFileReader)
常见函数:

相关属性以及函数描述备注
addAttachment(fname, fdata)将文件嵌入PDF
addBlankPage(width=None, height=None)将一个空白页添加到PDF文件里 具体页数没有确定的话,添加到最后一页
getNumPages()获取页数返回值为整数
getPage(pageNumber)从此PDF文件中按编号检索页面 返回类型为Pageobject
getPageLayout()获取页面布局
getPageMode()获取页面模式
insertBlankPage(width=None, height=None, index=0)插入空白页到PDF文件 未指定则默认最后一页
insertPage(page, index=0)插入一页内容到PDF文件
setPageLayout(layout)设置页面布局
setPageMode(mode)设置页面模式
updatePageFormFieldValues(page, fields)从字段字典更新给定页面的表单字段值。将字段文本和值从字段复制到页面
write(stream)将添加到该对象的页面集合写为PDF文件

1 PDF拆分


#拆分pdf
import os
from PyPDF2 import PdfFileReader 
from PyPDF2 import PdfFileWriter
def split_pdf(filename, filepath, save_dirpath, step=5):"""拆分PDF为多个小的PDF文件,@param filename:文件名@param filepath:文件路径@param save_dirpath:保存小的PDF的文件路径@param step: 每step间隔的页面生成一个文件,例如step=5,表示0-4页、5-9页...为一个文件@return:"""if not os.path.exists(save_dirpath):os.mkdir(save_dirpath)pdf_reader = PdfFileReader(filepath)# 读取每一页的数据pages = pdf_reader.getNumPages()for page in range(0, pages, step):pdf_writer = PdfFileWriter()# 拆分pdf,每 step 页的拆分为一个文件for index in range(page, page+step):if index < pages:pdf_writer.addPage(pdf_reader.getPage(index))# 保存拆分后的小文件save_path = os.path.join(save_dirpath, filename+str(int(page/step)+1)+'.pdf')print(save_path)with open(save_path, "wb") as out:pdf_writer.write(out)print("文件已成功拆分,保存路径为:"+save_dirpath)
path = "C:/Users/GJX/Desktop/OfficeAutomation/"
split_pdf("易方达中小盘混合型证券投资基金2020年中期报告.pdf",path+"易方达中小盘混合型证券投资基金2020年中期报告.pdf",path, step=5)

在这里插入图片描述

  • 小坑:
    (1) 文件路径后需要加文件名., 要不然报权限的错误

在这里插入图片描述

(2) 运行报错'latin-1' codec can't encode characters in position 8-9: ordinal not in range(256)


在这里插入图片描述
解决方法: 修改utils.py文件

r = s.encode('latin-1')
if len(s) < 2:
bc[s] = r
return r

改为:
在这里插入图片描述
(3) 修改utils.py文件运行报错

tab和空格混用:
在这里插入图片描述
在这里插入图片描述

2 批量合并

def concat_pdf(filename, read_dirpath, save_filepath):"""合并多个PDF文件@param filename:文件名@param read_dirpath:要合并的PDF目录@param save_filepath:合并后的PDF文件路径@return:"""pdf_writer = PdfFileWriter()# 对文件名进行排序list_filename = os.listdir(read_dirpath)list_filename.sort(key=lambda x: int(x[:-4].replace(filename, "")))for filename in list_filename:print(filename)filepath = os.path.join(read_dirpath, filename)# 读取文件并获取文件的页数pdf_reader = PdfFileReader(filepath)pages = pdf_reader.getNumPages()# 逐页添加for page in range(pages):pdf_writer.addPage(pdf_reader.getPage(page))# 保存合并后的文件with open(save_filepath, "wb") as out:pdf_writer.write(out)print("文件已成功合并,保存路径为:"+save_filepath)

3. 提取文字内容

涉及到具体的 PDF 内容 操作,本小节需要用到 pdfplumber 这个库

在进行文字提取的时候,主要用到 extract_text 这个函数

具体代码如下:

def extract_text_info(filepath):"""提取PDF中的文字@param filepath:文件路径@return:"""with pdfplumber.open(filepath) as pdf:# 获取第2页数据page = pdf.pages[1]print(page.extract_text())

可以看到,直接通过下标即可定位到相应的页码,从而通过 extract_text 函数提取该也的所有文字

而如果想要提取所有页的文字,只需要改成:

with pdfplumber.open(filepath) as pdf:# 获取全部数据for page in pdf.pagesprint(page.extract_text())

例如,提取“易方达中小盘混合型证券投资基金2020年中期报告” 第一页的内容时,源文件是这样的:

运行代码后提取出来是这样的:

4. 提取表格内容

同样的,本节是对具体内容的操作,所以也需要用到 pdfplumber 这个库

和提取文字十分类似的是,提取表格内容只是将 extract_text 函数换成了 extract_table 函数

对应的代码如下:

def extract_table_info(filepath):"""提取PDF中的图表数据@param filepath:@return:"""with pdfplumber.open(filepath) as pdf:# 获取第18页数据page = pdf.pages[17]# 如果一页有一个表格,设置表格的第一行为表头,其余为数据table_info = page.extract_table()df_table = pd.DataFrame(table_info[1:], columns=table_info[0])df_table.to_csv('dmeo.csv', index=False, encoding='gbk')

上面代码可以获取到第 18 页的第一个表格内容,并且将其保存为 csv 文件存在本地

但是,如果说第 18 页有多个表格内容呢?

因为读取的表格会被存成二维数组,而多个二维数组就组成一个三维数组

遍历这个三位数组,就可以得到该页的每一个表格数据,对应的将 extract_table 函数 改成 extract_tables 即可

具体代码如下:

# 如果一页有多个表格,对应的数据是一个三维数组
tables_info = page.extract_tables()
for index in range(len(tables_info)):# 设置表格的第一行为表头,其余为数据df_table = pd.DataFrame(tables_info[index][1:], columns=tables_info[index][0])print(df_table)# df_table.to_csv('dmeo.csv', index=False, encoding='gbk')

以“易方达中小盘混合型证券投资基金2020年中期报告” 第 xx 页的第一个表格为例:

源文件中的表格是这样的:

提取并存入 excel 之后的表格是这样的:

5. 提取图片内容

提取 PDF 中的图片和将 PDF 转存为图片是不一样的(下一小节),需要区分开。

提取图片:顾名思义,就是将内容中的图片都提取出来;转存为图片:则是将每一页的 PDF 内容存成一页一页的图片,下一小节会详细说明

转存为图片中,需要用到一个模块叫 fitz,fitz 的最新版 1.18.13,非最新版的在部分函数名称上存在差异,代码中会标记出来

使用 fitz 需要先安装 PyMuPDF 模块,安装方式如下:

pip install PyMuPDF

提取图片的整体逻辑如下:

  • 使用 fitz 打开文档,获取文档详细数据
  • 遍历每一个元素,通过正则找到图片的索引位置
  • 使用 Pixmap 将索引对应的元素生成图片
  • 通过 size 函数过滤较小的图片

实现的具体代码如下:

if not os.path.exists(pic_dirpath):os.makedirs(pic_dirpath)
# 使用正则表达式来查找图片
check_XObject = r"/Type(?= */XObject)"
check_Image = r"/Subtype(?= */Image)"
img_count = 0"""1. 打开pdf,打印相关信息"""
pdf_info = fitz.open(filepath)
# 1.16.8版本用法 xref_len = doc._getXrefLength()
# 最新版本写法
xref_len = pdf_info.xref_length()
# 打印PDF的信息
print("文件名:{}, 页数: {}, 对象: {}".format(filepath, len(pdf_info), xref_len-1))"""2. 遍历PDF中的对象,遇到是图像才进行下一步,不然就continue"""
for index in range(1, xref_len):# 1.16.8版本用法 text = doc._getXrefString(index)# 最新版本text = pdf_info.xref_object(index)is_XObject = re.search(check_XObject, text)is_Image = re.search(check_Image, text)# 如果不是对象也不是图片,则不操作if is_XObject or is_Image:img_count += 1# 根据索引生成图像pix = fitz.Pixmap(pdf_info, index)pic_filepath = os.path.join(pic_dirpath, 'img_' + str(img_count) + '.png')"""pix.size 可以反映像素多少,简单的色素块该值较低,可以通过设置一个阈值过滤。以阈值 10000 为例过滤"""# if pix.size < 10000:#     continue"""三、 将图像存为png格式"""if pix.n >= 5:# 先转换CMYKpix = fitz.Pixmap(fitz.csRGB, pix)# 存为PNGpix.writePNG(pic_filepath)

以本节示例的“易方达中小盘混合型证券投资基金2020年中期报告” 中的图片为例,代码运行后提取的图片如下:

这个结果和文档中的共 1 张图片的 结果符合

参考资料

  1. https://pythonhosted.org/PyPDF2/官方文档
  2. https://blog.csdn.net/qq_44885233/article/details/113568903PyPDF2–如何使用python操作你的PDF文档

这篇关于20210622_26期_办公自动化_Task4_Python 操作 PDF的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/374907

相关文章

Python判断for循环最后一次的6种方法

《Python判断for循环最后一次的6种方法》在Python中,通常我们不会直接判断for循环是否正在执行最后一次迭代,因为Python的for循环是基于可迭代对象的,它不知道也不关心迭代的内部状态... 目录1.使用enuhttp://www.chinasem.cnmerate()和len()来判断for

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

使用Python合并 Excel单元格指定行列或单元格范围

《使用Python合并Excel单元格指定行列或单元格范围》合并Excel单元格是Excel数据处理和表格设计中的一项常用操作,本文将介绍如何通过Python合并Excel中的指定行列或单... 目录python Excel库安装Python合并Excel 中的指定行Python合并Excel 中的指定列P

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Python将大量遥感数据的值缩放指定倍数的方法(推荐)

《Python将大量遥感数据的值缩放指定倍数的方法(推荐)》本文介绍基于Python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处理,并将所得处理后数据保存为新的遥感影像... 本文介绍基于python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处