Day4-Python自动化办公-Python与PDF(DataWhale)

Python操作PDF

  • 初级操作
    • 批量拆分
    • 批量合并
    • 提取文字内容
    • 提取表格内容
    • 提取图片内容
    • 转换为PDF图片
    • 添加水印
    • 加密和机密

1. 相关介绍

  1. PyPDF2库
  • 更好地读取、写入、分割、合并PDF。

  • 主要是处理PDF文件

  1. pdfplumber库
  • 更好的读取PDF文件中的内容和PDF文件中的表格
  • 主要是处理PDF文件中的内容
  1. PyMuPDF库
  • 提取图片
  • 按装PyMuPDF库,但是import fitz
  1. 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. 提取文字内容

  1. 提取固定页的内容
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')
  1. 提取所有页的内容
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')
  1. 将提取内容输出为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. 提取表格内容

  1. 提取一页的单张表格
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')
  1. 提取一页的多张表格
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')
  1. 补充说明
  • .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)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值