Python操作PDF
- 初级操作
- 批量拆分
- 批量合并
- 提取文字内容
- 提取表格内容
- 提取图片内容
- 转换为PDF图片
- 添加水印
- 加密和机密
1. 相关介绍
- PyPDF2库
-
更好地读取、写入、分割、合并PDF。
-
主要是处理PDF文件
- pdfplumber库
- 更好的读取PDF文件中的内容和PDF文件中的表格
- 主要是处理PDF文件中的内容
- PyMuPDF库
- 提取图片
- 按装PyMuPDF库,但是
import fitz
- pdf2image库
- 将PDF转换为图片
1.1 PyPDF2常用函数
- PdfFileReader(filename):读取文件
- pdf.getNumPages():读取PDF总页数
- pdf.isEncrypted:判断文件是否加密
- pdf.getDocumentInfo():获取PDF基本信息
- PdfFileWriter(filename):写入文件
- pdf_writer.addPage():添加页面
- pdf_writer.write():
# 导入模块
import PyPDF2
from PyPDF2 import PdfFileReader
# 导入PdfFileReader后可以不加前缀
pdf_reader = PyPDF2.PdfFileReader(open('report1.pdf','rb'))
print('总页面数:{}'.format(pdf_reader.getNumPages())) #总页面
print('加密:{}'.format(pdf_reader.isEncrypted)) #是否加密
print('PDF基本信息:{}'.format(pdf_reader.getDocumentInfo())) #获取PDF基本信息
1.2 pdfplumber常用函数
- pdfplumber.open(filepath):打开文件
- pdf.pages[1]:获取页
- page.extract_text():提取页面文字
- page.extract_table():提取最后的表格内容
- page.extract_tables():提取所有表格内容
with pdfplumber.open(filepath) as pdf:
# 获取第2页数据
page = pdf.pages[1]
print(page.extract_text())
1.3 fitz
- fitz.open(path):打开文件
- pdf.xref_length():获取对象数量
- pdf.xref_object(i):获取对象信息
- pix = fitz.Pixmap(pdf, i):生成图片对象
- pix.writePNG(filepath):输出图片
2. 批量拆分
将一个完整的PDF拆分成几个小的PDF,使用PyPDF2库
拆分思路:
- 读取PDF的整体信息、总页数
- 遍历每一页的内容、以每个step为间隔将PDF存成每一个小的文件块。【可以手动设置间隔,例如:每5页保存一个小的PDF文件】
- 将小的文件块重新保存为新的PDF文件
def split_pdf(filename, filepath, save_dirpath, step=5):
'''
filename:文件名
filepath:文件路径
save_dirpath:保存小的PDF的文件路径
step:每step间隔页面生成一个文件。step=5,表示0-4页、5-9页为一个文件
'''
if not os.path.exists(save_dirpath):
os.mkdir(save_dirpath)
pdf_reader = PdfFileReader(filepath+'\\'+filename)
# 读取每一页
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)
应用:
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
import os
split_pdf('report1.pdf', 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04', 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test' )
> 文件已成功拆分,保存路径为:D:\ZZ_Downloads\B6_OfficeAutomation\task04\test
3. 批量合并
合并思路:
- 确定要合并的文件顺序
- 循环追加到一个文件块中
- 保存为一个新文件
def concat_pdf(filename, read_dirpath, save_filepath):
'''
filename:需要合并的PDF文件的共同部分,不需要后缀'.pdf'
read_dirpath:需要合并的PDF目录
save_filepath:合并后的PDF文件目录+前缀名
'''
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))
# 保存合并后的文件
save_filename = save_filepath+'.pdf'
with open(save_filename, 'wb') as out:
pdf_writer.write(out)
print("文件已成功合并,保存路径为:"+save_filename)
应用:
import os
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
filename = 'report'
read_dirpath = 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test'
save_filepath = 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test2'
concat_pdf(filename, read_dirpath, save_filepath)
4. 提取文字内容
- 提取固定页的内容
def extract_text_info(filepath):
with pdfplumber.open(filepath) as pdf:
page = pdf.pages[1]
print(page.extract_text())
应用:
import pdfplumber
import os
os.chdir('D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test')
extract_text_info('report11.pdf')
- 提取所有页的内容
def extract_text_all_info(filepath):
with pdfplumber.open(filepath) as pdf:
for page in pdf.pages:
print(page.extract_text())
应用:
extract_text_all_info('report11.pdf')
- 将提取内容输出为word文档
def extract_text_info_word(filepath):
with pdfplumber.open(filepath) as pdf:
page = pdf.pages[1]
text = page.extract_text()
doc = Document()
paragraph = doc.add_paragraph()
run = paragraph.add_run(text)
doc.save('new.docx')
应用:
from docx import Document
import os
import pdfplumber
extract_text_info_word('report11.pdf')
5. 提取表格内容
- 提取一页的单张表格
def extract_table_info(filepath):
with pdfplumber.open(filepath) as pdf:
page = pdf.pages[0]
# 如果一页有表格,设置表格的第一行为表头,其余为数据
table_info = page.extract_table()
df_table = pd.DataFrame(table_info[1:], columns=table_info[0])
df_table.to_csv('demo.csv', index=False, encoding='gbk')
应用:
import pdfplumber
import pandas as pd
extract_table_info('report11.pdf')
- 提取一页的多张表格
def extract_table_info_all(filepath):
with pdfplumber.open(filepath) as pdf:
page = pdf.pages[0]
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])
df_table.to_csv('demo2.csv', index=False, encoding='gbk', mode='a') #设置mode,使内容不被覆盖
应用:
import pdfplumber
import pandas as pd
extract_table_info('report11.pdf')
- 补充说明
-
.extract_table()
- 默认提取指定页面的第一个表格
- 结构式row-cell
with pdfplumber.open('report11.pdf') as pdf: page = pdf.pages[0] table_info = page.extract_table() for row in table_info: print(row) print(row[0]) # 打印每个列表对应的第一个元素 > ['净利润(Non-GAAP)增长率', 'NA', 'NA', 'NA', 'NA', '112.50%'] 净利润(Non-GAAP)增长率 ['EPS(元)', '-1.51', '-1.43', '-1.06', '1.07', '2.97'] EPS(元) ['EPA(美元)', '-0.93', '-0.88', '-0.65', '0.66', '1.83'] EPA(美元)
-
.extract_tables()
- 输出页面中所有表格,并返回一个嵌套列表
- 结构层次为table-row-cell
with pdfplumber.open('report11.pdf') as pdf:
page = pdf.pages[0]
for row in page.extract_tables():
print(row)
print(row[0]) #打印外层列表第一个元素
6. 提取图片内容
将内容中的图片提取出来,转存为图片。首先安装PyMuPDF
库,使用时直接imoprt fitz
思路:
- 使用fitz打开文档,获取文档详细数据
- 遍历每一个元素,通过正则找到图片的索引位置
- 使用Pixmap将索引对应的元素生成图片
- 通过size函数过滤较小的图片
def extract_picture_info(filepath, pic_dirpath):
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)
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):
text = pdf_info.xref_object(index)
is_XObject = re.search(check_XObject, text)
is_Image = re.search(check_Image, text)
#如果不是对象也不是照片,则不操作
if not is_XObject or not is_Image:
continue
img_count += 1
#根据索引生成图像,index要为包含图片对应的索引位置
pix = fitz.Pixmap(pdf_info, index)
pic_filepath = os.path.join(pic_dirpath, 'img_' + str(img_count) +'.png')
'''
pix.size反映像素是多少,可以通过设置一个阈值过滤该值较低的简单色素。
if pix.size < 10000:
continue
'''
#3. 将图像存为png格式
if pix.n >=5:
# 先转换CMYK
pix = fitz.Pixmap(fitz.csRGB, pix)
pix.writePNG(pic_filepath)
应用:
import fitz
import re
extract_picture_info('report11.pdf', 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test')
补充方法
import fitz,os
doc = fitz.open('report11.pdf')
imgcount=0
for page in doc:
imageList = page.getImageList()
print(imageList)
for imginfo in imageList:
pix = fitz.Pixmap(doc, imginfo[0])
pix.writePNG(os.path.join('D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test',str(imgcount)))
imgcount+=1
7. 转换为图片
将一页页的PDF转换为一张张的图片
- 安装pdf2image:
pip install pdf2image
- 安装配置poppler,(http://blog.alivate.com.au/poppler-windows/),并将
bin\
文件添加到PATH - 重启电脑
- 安装pillow:
pip install pillow
import os
from pdf2image import convert_from_bytes
os.chdir('D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test')
filepath = 'report11.pdf'
pic_dirpath = 'pic'
if not os.path.exists(pic_dirpath):
os.makedirs(pic_dirpath)
images = convert_from_bytes(open(filepath, 'rb').read())
# images = convert_from_path(filepath, dpi=200)
for image in images:
# 保存图片
pic_filepath = os.path.join(pic_dirpath, 'img_'+str(images.index(image))+'.png')
image.save(pic_filepath, 'PNG')
8. 添加水印
参考:https://mp.weixin.qq.com/s/_oJA6lbsdMlRRsBf6DPxsg
思路:
- 生成一张透明的水印
- 将水印添加到一张空白图片上生成水印背景
- 将水印背景粘贴到原图对应的位置上
水印的方式:
- 固定位置的水印
- 全屏水印
def create_watermark(input_filename, output_filename, watermark):
watermark_doc = PdfFileReader(watermark)
watermark_page = watermark_doc.getPage(0)
pdf_reader = PdfFileReader(input_filename)
pdf_writer = PdfFileWriter()
# 全部页打水印
for page in range(pdf_reader.getNumPages()):
page = pdf_reader.getPage(page)
page.mergePage(watermark_page)
pdf_writer.addPage(page)
with open(output_filename, 'wb') as out:
pdf_writer.write(out)
应用:
from PyPDF2 import PdfFileWriter, PdfFileReader
input_filename = 'report11.pdf'
output_filename = 'waterprint.pdf'
watermark = 'img.pdf'
create_watermark(input_filename, output_filename, watermark)
9. 文档加密与解密
使用encrypt函数
filepath = 'report12.pdf'
save_filepath = 'D:\\ZZ_Downloads\\B6_OfficeAutomation\\task04\\test\\tt.pdf'
passwd = '111'
pdf_reader = PdfFileReader(filepath)
pdf_writer = PdfFileWriter()
for page_index in range(pdf_reader.getNumPages()):
pdf_writer.addPage(pdf_reader.getPage(page_index))
# 添加密码
pdf_writer.encrypt(passwd)
with open(save_filepath, 'wb') as out:
pdf_writer.write(out)