1. 相关介绍

Python 操作 PDF 会用到两个库,分别是:PyPDF2 和 pdfplumber

其中 PyPDF2 可以更好的读取、写入、分割、合并PDF文件,而 pdfplumber 可以更好的读取 PDF 文件中内容和提取 PDF 中的表格

对应的官网分别是
PyPDF2:https://pythonhosted.org/PyPDF2/

pdfplumber:https://github.com/jsvine/pdfplumber
由于这两个库都不是 Python 的标准库,所以在使用之前都需要单独安装

win+r 后输入 cmd 打开 command 窗口,依次输入如下命令进行安装:
pip install PyPDF2

pip install pdfplumber
安装完成后显示 success 则表示安装成功

需要注意的是:

如果你是第一次运行代码,在运行过程中,会直接报如下的错误

如果是在 Pycharm 下,直接通过报错信息,点击 utils.py 文件,定位到第 238 行原文

原文中是这样的:
r = s.encode(‘latin-1’)
if len(s) < 2:
bc[s] = r
return r
修改为:
try:
r = s.encode(‘latin-1’)
if len(s) < 2:
bc[s] = r
return r
except Exception as e:
r = s.encode(‘utf-8’)
if len(s) < 2:
bc[s] = r
return r
如果你使用的是 anaconda,对应的文件路径应该为:anaconda\Lib\site-packages\PyPDF2\utils.py,进行同样的修改操作即可

1.按【win+r】快捷键打开运行;

2.在输入框中输入cmd,点击【确定】;

3.在打开的命令提示符中执行【conda info --envs】命令即可。

2. 批量拆分

将一个完整的 PDF 拆分成几个小的 PDF,因为主要涉及到 PDF 整体的操作,所以本小节需要用到 PyPDF2 这个库

拆分的大概思路如下:

读取 PDF 的整体信息、总页数等
遍历每一页内容,以每个 step 为间隔将 PDF 存成每一个小的文件块
将小的文件块重新保存为新的 PDF 文件
需要注意的是,在拆分的过程中,可以手动设置间隔,例如:每5页保存成一个小的 PDF 文件

拆分的代码如下:

import os
from PyPDF2 import PdfFileReader, 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)
save_dirpath = r"."
filename  = '易方达中小盘混合型证券投资基金2020年中期报告.pdf'
page =46
step =  5
save_path = os.path.join(save_dirpath, filename+str(int(page/step)+1)+'.pdf')
split_pdf("易方达中小盘混合型证券投资基金2020年中期报告","易方达中小盘混合型证券投资基金2020年中期报告.pdf",'.')
.\易方达中小盘混合型证券投资基金2020年中期报告1.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告2.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告3.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告4.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告5.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告6.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告7.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告8.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告9.pdf
.\易方达中小盘混合型证券投资基金2020年中期报告10.pdf
文件已成功拆分,保存路径为:.
os.getcwd()
'C:\\Users\\Chanjons\\Desktop\\OfficeAutomation'
os.path
<module 'ntpath' from 'C:\\ProgramData\\Anaconda3\\lib\\ntpath.py'>
os.path.exists("易方达中小盘混合型证券投资基金2020年中期报告.pdf") # 判断是否存在在当前文件夹中
True
pdf_reader  = PdfFileReader("易方达中小盘混合型证券投资基金2020年中期报告.pdf")
pdf_reader
<PyPDF2.pdf.PdfFileReader at 0x16c045b04c8>
pdf_reader.getNumPages()
46
pages = pdf_reader.getNumPages()
for page in range(0, pages, 5):print(page)
0
5
10
15
20
25
30
35
40
45
pdf_writer = PdfFileWriter() # 创建新的pdf
pdf_writer
<PyPDF2.pdf.PdfFileWriter at 0x16c0484c4c8>
pdf_writer.addPage(pdf_reader.getPage(0))
pdf_reader.getNumPages()
46
with open("temp.pdf", "wb") as out: # 写出PDFpdf_writer.write(out)
for page in range(0, pages, 5):print("page:",page)for index in range(page, page+5):print("index:",index)if index < pages:print("超出范围的index",index)
page: 0
index: 0
超出范围的index 0
index: 1
超出范围的index 1
index: 2
超出范围的index 2
index: 3
超出范围的index 3
index: 4
超出范围的index 4
page: 5
index: 5
超出范围的index 5
index: 6
超出范围的index 6
index: 7
超出范围的index 7
index: 8
超出范围的index 8
index: 9
超出范围的index 9
page: 10
index: 10
超出范围的index 10
index: 11
超出范围的index 11
index: 12
超出范围的index 12
index: 13
超出范围的index 13
index: 14
超出范围的index 14
page: 15
index: 15
超出范围的index 15
index: 16
超出范围的index 16
index: 17
超出范围的index 17
index: 18
超出范围的index 18
index: 19
超出范围的index 19
page: 20
index: 20
超出范围的index 20
index: 21
超出范围的index 21
index: 22
超出范围的index 22
index: 23
超出范围的index 23
index: 24
超出范围的index 24
page: 25
index: 25
超出范围的index 25
index: 26
超出范围的index 26
index: 27
超出范围的index 27
index: 28
超出范围的index 28
index: 29
超出范围的index 29
page: 30
index: 30
超出范围的index 30
index: 31
超出范围的index 31
index: 32
超出范围的index 32
index: 33
超出范围的index 33
index: 34
超出范围的index 34
page: 35
index: 35
超出范围的index 35
index: 36
超出范围的index 36
index: 37
超出范围的index 37
index: 38
超出范围的index 38
index: 39
超出范围的index 39
page: 40
index: 40
超出范围的index 40
index: 41
超出范围的index 41
index: 42
超出范围的index 42
index: 43
超出范围的index 43
index: 44
超出范围的index 44
page: 45
index: 45
超出范围的index 45
index: 46
index: 47
index: 48
index: 49

以“易方达中小盘混合型证券投资基金2020年中期报告”为例,整个 PDF 文件一共 46 页,每5页为间隔,最终生成了10个小的 PDF 文件

3. 批量合并

比起拆分来,合并的思路更加简单:

确定要合并的 文件顺序

循环追加到一个文件块中

保存成一个新的文件

对应的代码比较简单,基本不会出现问题:

def concat_pdf(filename, read_dirpath, save_filepath):"""合并多个PDF文件@param filename:文件名@param read_dirpath:要合并的PDF目录@param save_filepath:合并后的PDF文件路径@return:"""pdf_writer = PdfFileWriter()# 对文件名进行排序list_1 = []for i in os.listdir(read_dirpath):if i.find(filename) == 0:if len(i)>28:list_1.append(i)list_filename = list_1list_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)
list_1 = []
for i in os.listdir("."):if i.find(filename) == 0:if len(i)>28:list_1.append(i)
list_1
['易方达中小盘混合型证券投资基金2020年中期报告1.pdf','易方达中小盘混合型证券投资基金2020年中期报告10.pdf','易方达中小盘混合型证券投资基金2020年中期报告2.pdf','易方达中小盘混合型证券投资基金2020年中期报告3.pdf','易方达中小盘混合型证券投资基金2020年中期报告4.pdf','易方达中小盘混合型证券投资基金2020年中期报告5.pdf','易方达中小盘混合型证券投资基金2020年中期报告6.pdf','易方达中小盘混合型证券投资基金2020年中期报告7.pdf','易方达中小盘混合型证券投资基金2020年中期报告8.pdf','易方达中小盘混合型证券投资基金2020年中期报告9.pdf']
list_1.sort(key=lambda x: int(x[:-4].replace('易方达中小盘混合型证券投资基金2020年中期报告', "")))
concat_pdf("易方达中小盘混合型证券投资基金2020年中期报告", ".", r".\合并\合并报告.pdf")
易方达中小盘混合型证券投资基金2020年中期报告1.pdf
易方达中小盘混合型证券投资基金2020年中期报告2.pdf
易方达中小盘混合型证券投资基金2020年中期报告3.pdf
易方达中小盘混合型证券投资基金2020年中期报告4.pdf
易方达中小盘混合型证券投资基金2020年中期报告5.pdf
易方达中小盘混合型证券投资基金2020年中期报告6.pdf
易方达中小盘混合型证券投资基金2020年中期报告7.pdf
易方达中小盘混合型证券投资基金2020年中期报告8.pdf
易方达中小盘混合型证券投资基金2020年中期报告9.pdf
易方达中小盘混合型证券投资基金2020年中期报告10.pdf
文件已成功合并,保存路径为:.\合并\合并报告.pdf

4. 提取文字内容

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

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

具体代码如下:

可以直接使用pip进行python包的安装,执行指令:
pip install pdfplumber

import pdfplumber
---------------------------------------------------------------------------ModuleNotFoundError                       Traceback (most recent call last)<ipython-input-64-b3d6737fd8e1> in <module>
----> 1 import pdfplumberC:\ProgramData\Anaconda3\lib\pdfplumber\__init__.py in <module>8 9 from ._version import __version__
---> 10 from .pdf import PDF11 from . import utils12 import pdfminerC:\ProgramData\Anaconda3\lib\pdfplumber\pdf.py in <module>
----> 1 from .container import Container2 from .page import Page3 from .utils import resolve_and_decode4 5 import loggingC:\ProgramData\Anaconda3\lib\pdfplumber\container.py in <module>1 from itertools import chain
----> 2 from . import utils, convert3 4 5 class Container(object):C:\ProgramData\Anaconda3\lib\pdfplumber\utils.py in <module>
----> 1 from pdfminer.utils import PDFDocEncoding2 from pdfminer.psparser import PSLiteral3 from pdfminer.pdftypes import PDFObjRef4 from decimal import Decimal, ROUND_HALF_UP5 import numbersModuleNotFoundError: No module named 'pdfminer'
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())
  File "<ipython-input-65-22a8e9b5f50f>", line 3for page in pdf.pages^
SyntaxError: invalid syntax

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

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

5. 提取表格内容

同样的,本节是对具体内容的操作,所以也需要用到 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')
---------------------------------------------------------------------------AttributeError                            Traceback (most recent call last)<ipython-input-67-a0931f0f9473> in <module>1 # 如果一页有多个表格,对应的数据是一个三维数组
----> 2 tables_info = page.extract_tables()3 for index in range(len(tables_info)):4     # 设置表格的第一行为表头,其余为数据5     df_table = pd.DataFrame(tables_info[index][1:], columns=tables_info[index][0])AttributeError: 'int' object has no attribute 'extract_tables'

6. 提取图片内容

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

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

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

使用 fitz 需要先安装 PyMuPDF 模块,安装方式如下:
pip install PyMuPDF
提取图片的整体逻辑如下:

使用 fitz 打开文档,获取文档详细数据

遍历每一个元素,通过正则找到图片的索引位置

使用 Pixmap 将索引对应的元素生成图片

通过 size 函数过滤较小的图片

实现的具体代码如下:

import os
import fitz
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)
---------------------------------------------------------------------------NameError                                 Traceback (most recent call last)<ipython-input-73-58c4e80959bf> in <module>
----> 1 if not os.path.exists(pic_dirpath):2     os.makedirs(pic_dirpath)3 # 使用正则表达式来查找图片4 check_XObject = r"/Type(?= */XObject)"5 check_Image = r"/Subtype(?= */Image)"NameError: name 'pic_dirpath' is not defined

7. 转换为图片

转换为照片比较简单,就是将一页页的 PDF 转换为一张张的图片。大致过程如下:

7.1 安装 pdf2image
首先需要安装对应的库,最新的 pdf2image 库版本应该是 1.14.0

它的 github地址 为:https://github.com/Belval/pdf2image ,感兴趣的可以自行了解

安装方式如下:
pip install pdf2image

Task 04 Python 操作 PDF相关推荐

  1. task04 办公自动化之Python 操作 PDF

    # 基本库导入 import pandas as pd import numpy as np 1.相关库了解 利用python操作pdf会用到两个库,分别是:PyPDF2 和 pdfplumber 其 ...

  2. python操作pdf做文档的分割、合并,内容提取

    Python 操作 PDF 会用的库:PyPDF2 和 pdfplumber PyPDF2 可以更好的读取.写入.分割.合并PDF文件: pdfplumber 可以更好的读取 PDF 文件中内容和提取 ...

  3. python怎么玩pdf_最全总结!聊聊 python 操作PDF的几种方法

    作者:陈熹 来源:早起Python 一.前言 大家好,有关Python操作PDF的案例之前已经写过一个PDF批量合并,这个案例初衷只是给大家提供一个便利的脚本,并没有太多讲解原理,其中涉及的就是PDF ...

  4. Python 操作 PDF 的几种方法

    作者 | 陈熹 来源 | 早起Python(ID:zaoqi-python) 头图 |  CSDN 下载自视觉中国 前言 大家好,有关 Python 操作 PDF 的案例之前已经写过一个????PDF ...

  5. python 操作PDF文件 之 A3页面转A4

    python 操作PDF文件 A3页面转A4页面 文章目录 1. 需求概述 2. 代码实现 1. 需求概述 最近接到一份PDF资料需要打印,奈何页面是如图所示的A3格式的,奈何目前条件只支持打印A4. ...

  6. python批量上传pdf,Python 操作 PDF 的几种方法

    以下文章来源于早起 Python ,作者陈熹 作者 | 陈熹 来源 | 早起 Python(ID:zaoqi-python) 头图 | CSDN 下载自视觉中国 前言 大家好,有关 Python 操作 ...

  7. Python自动化办公系列之Python操作PDF

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 输 作者介绍: 大家可以叫我黄同学(博客名:Huang Supre ...

  8. 干货!Python操作PDF的神器——PyMuPDF

    点击上方"菜鸟学Python",选择"星标"公众号 超级无敌干货,第一时间送达!!! 来源:网络 01 PyMuPDF简介 1. 介绍 大家好,我是菜鸟哥.长假 ...

  9. 【实用篇】Python操作PDF文件

    PDF是Portable Document Format的缩写,这类文件通常使用 .pdf 作为其扩展名.在日常开发工作中,最容易遇到的就是从PDF中读取文本内容以及用已有的内容生成PDF文档这两个任 ...

  10. nsga2代码解读python_python自动化办公系列 | python操作pdf—— PyPDF2 和 pdfplumber模块(1)...

    看了好多代码,目前为止都是散乱的分享,接下来将整理作为专题,进行系统化的一个分享整理,也是我自己学习的过程.第一个的系统化的分享专题--python办公自动化.代码后面的#所表示的是注释,对本行代码进 ...

最新文章

  1. Python培训中有哪些是必须学的运算符
  2. 斯坦福重磅报告:2030年的人工智能与生活
  3. pthread相关介绍
  4. WP7-网络-读取网页源码
  5. Java中resource文件夹
  6. plsql 中的一些好的设置和快捷键总结
  7. 每日小记2017.2.28
  8. [UML]UML系列——时序图(顺序图)sequence diagram
  9. SAP License:ERP财务软件简介
  10. python vector_[流畅的Python]读书笔记之十三运算符重载
  11. 计算机在剪辑方面的应用,多媒体技术对影视后期制作的应用
  12. python三方库是什么_python第三方库有哪几种
  13. label怎么换行 vb_ASP.NET Lable中进行换行
  14. python下stl格式转换off格式
  15. 20200308模拟赛
  16. 一文搞懂Object.create()、new Object()和{}创建对象的区别
  17. 原生JS实现网页导航条特效
  18. 2021半年度博客总结
  19. CGAL Arrangements and Their Applications: A Step-By-Step Guide
  20. 写给工程师的 10 条精进原则

热门文章

  1. 东华大学2021计算机OJ题——基本练习(15 abc数字)
  2. Vue--$watch()源码分析
  3. python模拟老师授课下课情景
  4. [数学] 线性微分方程中的“线性性“
  5. Android 仿京东头部滚动头像动态变化
  6. Tomcat报错:org.apache.catalina.core.StandardWrapperValve invoke 严重: Servlet.service() for servlet
  7. Java虚拟机笔记-2
  8. webpack打包上传到服务器(小白)
  9. 生活就是会开一些不经意的玩笑,给你转个弯,绊个道,然后给你不一样的视角。有些人很幸运发现了,有些人一辈子在无视。然后忆往昔,恨当下。把一切都怪给命运。
  10. [Python3]时间戳与时间的相互转换