社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

还在用收费的工具处理PDF?用Python助力冲破会员牢笼

happy科研 • 3 年前 • 360 次点击  

大家好,我是才哥。

今天的主题很简单:用python搞定pdf文件的各种操作需求!!

前言:害,又遇到了要处理 PDF 文件的活了,需求是提取表格,还要拜托有某软件会员的同事操作一下,没想到会员早就过期了。毕竟不常用,为了个 PDF 文件充值,大可不必。就凭我的码字速度,在输入支付密码之前就能把内容都敲下来。但转念一想,PDF 的自动化需求种类还是很多的,比如增删改页面、提取文字和图像等等,万一哪天遇到大批量操作的需求可就麻烦了。自动化之王(不是)Python 肯定有办法!让我们来瞅瞅吧。


先看看笔者遇到的问题,要处理的是这样一份 PDF 文件,前几页为文字,文末附了几个表格,其中有一个表格是跨页的。那要如何提取表格呢?核心代码仅需两行,打开 PDF 文件,读取表格即可,十分便利。

import pdfplumber

pdf = pdfplumber.open("test.pdf")
for i in range(24):
    tables = pdf.pages[i].extract_tables()
    for t in tables:
        print(t)

从输出结果可见,是一种嵌套列表的形式,而一个表格跨页后的部分会被识别为另外的表格。

[['序号', '标题 1', '标题 2', '标题 3'], ['1', '内容', '内容', '内容'], ['2', '内容', '内容', '内容'], ['3', '内容', '内容', '内容']] [['序号', '字段 1', '字段 2', '字段 3', '字段 4', '字段 5'], ['1', '内容', '内容', '内容', '内容', '内容'], ['2', '内容', '内容', '内容', '内容', '内容'], ['3', '内容', '内容', '内容', '内容', '内容'], ['4', '内容', '内容', '内容', '内容', '内容'], ['5', '内容', '内容', '内容', '内容', '内容']] [['6', '内容', '内容', '内容', '内容', '内容'], ['7', '内容', '内容', '内容', '内容', '内容'], ['8', '内容', '内容', '内容', '内容', '内容'], ['9', '内容', '内容', '内容', '内容', '内容'], ['10', '内容', '内容', '内容', '内容', '内容']] [['序号', '表头 1', '表头 2', '表头 3', '表头 4'], ['1', '内容', '内容', '内容', '内容'], ['2', '内容', '内容', '内容', '内容'], ['3', '内容', '内容', '内容', '内容'], ['4', '内容', '内容', '内容', '内容'], ['5', '内容', '内容', '内容', '内容']]

那么接下来就用传说能让 EXCEL 飞起来的 xlwings 库将数据写入吧!对代码稍加改造,详见注释。

import pdfplumber
import xlwings as xw


wb = xw.books.active  # 连接到活动的工作簿
sht = wb.sheets['Sheet1']  # 连接子表1
n = 1
pdf = pdfplumber.open("test.pdf")  # 打开PDF
for i in range(24):
    tables = pdf.pages[i].extract_tables()  # 获取第3、4页的表格
    for t in tables:
        for row in t:
            if '序号' in row and n>1:
                n += 1  # 不同表格之间隔一行
            sht.range(f'A{n}').value = row  # 将表格的一行从A1单元格开始写入
            n += 1  # 换行

果然起飞,这种看得见的效果,相比其他在内存中执行完才存表的 EXCEL 处理库要更加过瘾。还可以利用 xlwings 对各个表格添加边框、加粗表头等,在此不做赘述,有兴趣的同学可以自行探索,本文的主角可是 PDF 处理库啊,下面有请——


pdfplumber 是一个基于 pdfminer.six 的 PDF 内容抽取工具,如前文的体验一般,操作十分简单,可惜专攻识别而无法直接对 PDF 做修改保存。如果有更复杂的需求,可以学习 pdfminer,但需要对 PDF 文件模型有所了解,学起来有一定的难度。

官网:https://github.com/jsvine/pdfplumber

PyPDF2 也是一个为人所熟知的 PDF 页面级处理工具,它更加擅长对页面进行分割、合并、裁剪和转换等操作,而对内容的提取能力欠缺。

官网:https://pythonhosted.org/PyPDF2

就让我们从常用的 PDF 操作来认识这两位吧!

1、插入/增加页

我们先另外再准备一个 PDF 文件,用作插入试验。PyPDF2 通过读写器来操作 PDF 文件,假如要在第 1 页之后插入页面,需要通过 Reader 对象的 getPage 方法获取页面,再通过 Writer 对象的 addPage 方法来添加页面,最后写入文件流。

from PyPDF2 import PdfFileWriter, PdfFileReader


output = PdfFileWriter()
input = PdfFileReader(open("test.pdf""rb"))
insert = PdfFileReader(open("insert.pdf""rb"))

for i in range(04):
    output.addPage(input.getPage(i))
    if i ==0:
        output.addPage(insert.getPage(0))

output.write(open("output.pdf""wb"))

2、选取/删除页

通过插入页的方式,相信大家已经能想到选取/删除页的办法了,那就是选择需要的 page 索引来 addPage。比如对上一步的 output.pdf 仅保留第 1 和第 3 页.

from PyPDF2 import PdfFileWriter, PdfFileReader


new_output = PdfFileWriter()
input = PdfFileReader(open("output.pdf""rb"))

for i in range(0 4):
    if i==0 or i==2:
        new_output.addPage(input.getPage(i))

new_output.write(open("new_output.pdf""wb"))

3、提取文本信息

不得不说,pdfplumber 封装得很精炼,用非常直观的语句就能实现需求,通过页面对象的 extract_text 方法即可提取文本。要注意的是,pdfplumber 只能提取原生内容,如果是图片,则需要另外借助 OCR 工具。

import pdfplumber

pdf = pdfplumber.open("test.pdf")
pages = pdf.pages
for p in pages:
    print(p.extract_text())

1 1 1 2 2 2 3 3 3 表一 序号 标题 1 标题 2 标题 3 1 内容 内容 内容 2 内容 内容 内容 3 内容 内容 内容 表二 ......

4、提取表格信息

之前笔者用 extract_tables() 批量提取了表格,我们还可以 extract_table() 提取指定页面的表格,然后可将其装载进 DataFrame 以便后续分析操作。

import pdfplumber
import pandas as pd


pdf = pdfplumber.open("test.pdf")
table = pdf.pages[2].extract_table()
df = pd.DataFrame(table[1:], columns=table[0])
print(df)

但是却发现它提取的是该页面的表二,难道默认不是提取页面中第一个表吗?

经查阅官方资料得知:extract_table() 返回页面上最大的表,如果多个表的大小相同(以单元格数衡量),则返回最靠近页面顶部的表。

5、提取图片信息

下面我们再准备一个带图片的 PDF 文件,用作提取试验。 依照官方提示,想进行可视化操作还需要安装两个依赖工具。(此外,笔者发现还有其他库能提取 PDF 的图片元素或转化 PDF 页面为图片,如 PyMuPDF、pdf2image等,可以拓展学习)安装地址如下,注意要选择和 python 对应位数的版本。

https://imagemagick.org/script/download.php#windows https://ghostscript.com/download/gsdnld.html

通过页面对象的 images 属性即可获取图像参数列表,在此我们只有一张图,获取其图像流数据并写入文件,成功提取图片。

import pdfplumber


pdf_pic = pdfplumber.open("picture.pdf")
page = pdf_pic.pages[0]
img = page.images
data = img[0]['stream'].get_data()
with open('pic.png''wb'as f:
    f.write(data)

同时我们也可以验证一下对图片中文字和表格的提取,发现是不可行的。

print(page.extract_text())
print(page.extract_table())

我是文字 None

6、页面转换成图片

除了可以提取页面中的图片元素,也可以将整个页面转成图片输出,我们换回最初的那一份 PDF 来试验。页面对象具有 to_image 方法,比单个元素的操作更加简单。

import pdfplumber


pdf = pdfplumber.open("test.pdf")
pages = pdf.pages
for i, p in enumerate(pages):
    p.to_image().save(f"第{i+1}页.png", format="PNG")

之后我们还可以将多个图片连接成长图,适合移动端浏览。

from os import listdir
from PIL import Image


imgs = [Image.open(f) for f in listdir('.'if f.endswith('.png')]  # 获取当前目录下的图像
width, height = imgs[0].size  # 单幅图像尺寸
result = Image.new(imgs[0].mode, (width, height * len(imgs)))  # 创建空白长图

for i, im in  enumerate(imgs):  # 拼接图片
    result.paste(im, box=(0, i * height))

result.save('长条图.png')
移动端效果


本篇通过 1 个实际案例和 6 个小操作演示了两个 PDF 库的基本功能,还有很多隐藏的属性等待我们去探索,比如添加水印、加/解密等,这还不赶快自己开发一个 PDF 工具去收费?暴富指日可待!这里是妄图暴富的 Seon塞翁,下一篇见。

☝推荐一本python自动化书籍



推荐阅读


40行代码自己动手写pdf转word小工具(文末附工具下载)

2021-05-25

140行代码自己动手写一个词云制作小工具(文末附工具下载)

2021-06-09

80行代码自己动手写一个表格拆分与合并小工具(文末附工具下载)

2021-05-30

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/122614
 
360 次点击