【Python实战】完美实现 WPS 会员功能,自动化处理 PDF 文档(建议收藏)

数字化办公已成常态,文档管理和处理是很多小伙伴的日常工作。

PDF(Portable Document Format)文档因其跨平台兼容性和格式固定性而备受青睐。

然而,对于非WPS会员用户而言,一些高级功能如批量处理、格式转换、添加水印等常常受限。

即便是充了会员,有些文档的水印也无法完全去除。

本文旨在揭示如何通过 Python 和相关库,自动化处理 PDF 文档,从而完美实现类似WPS会员的高级功能,无需额外付费。

文章目录如下(按需取用):

  • 生成水印 —— 创建专属水印,保护你的文档版权。
  • 添加水印 —— 将水印无缝融合到PDF文档中,增强文档的专业性和安全性。
  • 提取文本内容 —— 从PDF中快速抽取文字,便于二次编辑和使用。
  • 多个PDF合并 —— 将分散的PDF文件整合成一份,简化文档管理和阅读体验。
  • 单个PDF分割 —— 按页或章节拆分大型PDF文档,便于分享和管理。
  • PDF转图片 —— 将PDF页面转换为图像格式,适用于各种展示场景。
  • 图片转PDF —— 反向操作,将多张图片合成为一份PDF文档,方便打印和分享。

0. 前置准备

首先需要在电脑上准备好 Python 环境,有不了解的小伙伴,送你一份保姆级教程:【7天Python入门系列】Day1:环境准备之Conda和VS code安装

PDF 文档处理,一般会用到下面三个库,打开终端,一键安装:

pip install PyPDF2
pip install PyMuPDF
pip install reportlab

1. 生成水印

采用 reportlab 的画布功能,先引入必要的模块:

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics   # 注册字体
from reportlab.pdfbase.ttfonts import TTFont # 字体类
from reportlab.lib.pagesizes import letter  # 页面的标志尺寸(8.5*inch, 11*inch)

然后,我们引入本地电脑支持的字体,注册字体类:

pdfmetrics.registerFont(TTFont('simkai', 'C:\Windows\Fonts\simkai.ttf'))

Windows 电脑中,字体默认保存在 C:\Windows\Fonts\,文件后缀为 .ttf,在其中找到想要想要生成的字体路径,填入上述代码片段对应位置。

最后,给出函数实现:

def create_watermark(watermark_text='公众号:猴哥的AI知识库', font=15, pagesize=(30*cm, 30*cm)):
    watermark_canvas = canvas.Canvas("data/watermark.pdf", pagesize) # 指定存放位置和画布大小
    watermark_canvas.setFont("simkai", font) 
    watermark_canvas.setFillAlpha(0.1) # 设置透明度,1为不透明
    watermark_canvas.translate(10*cm, 5*cm)
    watermark_canvas.rotate(30) # 水印旋转角度
    for i in range(5):
        for j in range(10):
            a = 10*(i-1)
            b = 5*(j-2)
            watermark_canvas.drawString(a*cm, b*cm, watermark_text)
    watermark_canvas.save()

注意:画布大小可以作为一个参数传入,可根据 pdf 页面的大小进行设置。此外,你还可以任意修改水印的位置和字体。

如何获取 pdf 页面的大小,接着往下看。

我们先来看下生成的水印效果:

2. 添加水印

如何将上面生成的水印,添加到我们的 PDF 文档中?

首先,我们引入 PyPDF2 中的读写类,给定要插入水印的 PDF (input_pdf)和输出的 PDF (output_pdf)。

然后,根据输入的 PDF 首页大小创建水印文件。

page_size = (first_page.mediabox.width, first_page.mediabox.height)  # 获取页面大小

最后,调用 .merge_page 方法为每一页插入水印,当然也可以设置间隔几页插入,或者只插入特定页。

实现代码如下:

from tqdm import tqdm
from PyPDF2 import PdfReader, PdfWriter

def add_watermark(input_pdf, output_pdf, watermark_text='公众号:猴哥的AI知识库'):
    pdf_reader = PdfReader(input_pdf)  # 读取需要添加水印的文件
    first_page = pdf_reader.pages[0]
    page_size = (first_page.mediabox.width, first_page.mediabox.height)  # 获取页面大小
    create_watermark(watermark_text, pagesize=page_size)  # 创建水印PDF

    pdf_writer = PdfWriter()  # 创建PDF文件写入对象
    watermark_file = PdfReader("data/watermark.pdf")  # 读取水印PDF(假设水印页只有一页)

    for page_num in tqdm(range(len(pdf_reader.pages)), desc='add_watermark'):  # 遍历每一页PDF对象
        pdf_page = pdf_reader.pages[page_num]  # 获取PDF的当前页对象
        pdf_page.merge_page(watermark_file.pages[0])  # 将水印页合并到当前页中
        pdf_writer.add_page(pdf_page)  # 将合并后的PDF对象页添加到PDF写入对象中
    with open(output_pdf, 'wb') as output:  # 打开输出文件
        pdf_writer.write(output)  # 写入PDF内容到输出文件

最终效果,我们拿南瓜书来举个例子:

3. 提取文本内容

手动复制 PDF 中的文本实在太麻烦了,能否一键提取所有内容?

不但能,而且还可以转存成 MarkDown 格式。

这里提供两种方式~

方式一:采用 PyPDF2:调用.extract_text()方法

def pypdf_to_txt(input_pdf, output_path='output.md'):
    pdf_reader = PdfReader(input_pdf)
    markdown_lines = []
    # 遍历PDF的每一页
    for page_num in range(len(pdf_reader.pages)):
        page = pdf_reader.pages[page_num]
        text = page.extract_text()
        markdown_lines.append(text)
        markdown_lines.append("\n\n")  # 分页
    # 将文本写入Markdown文件
    with open(output_path, "w", encoding="utf-8") as f:
        f.writelines(markdown_lines)

方式二:采用 PyMuPDF

注:fitz 是 PyMuPDF 库的一个模块

import fitz
def pymupdf_to_txt(input_pdf, output_path='output.md'):
    pdf_document = fitz.open(input_pdf)
    markdown_lines = []
    # 遍历PDF的每一页
    for page_num in range(pdf_document.page_count):
        page = pdf_document.load_page(page_num)
        text = page.get_text("text")
        if not text:
            pm = page.get_pixmap()
            pm.save("temp.png")
            img = cv2.imread("temp.png")
            texts = img_ocr(img_data=img)
            # os.remove("temp.png")
            markdown_lines.append("\n".join(texts))
        else:
            markdown_lines.append(text+"\n\n")
    # 将文本写入Markdown文件
    with open(output_path, "w", encoding="utf-8") as f:
        f.writelines(markdown_lines)

上述函数中,还加了一层判断,也即如果识别到当前 PDF 页是一张图片,没有文字,怎么办?

此时,我们可以调用 OCR 方法,识别出所有文字再进行拼接,市面上开源的 OCR 方案有很多,大家都在用哪款 OCR,欢迎评论区告诉我。

关于如何优雅地使用 OCR,如果感兴趣的小伙伴多的话,猴哥再单独出一篇分享。

4. 多个 PDF 合并

了解了上述操作以后,实现 PDF 合并就很简单了。

首先,新建一个 writer 用于写入新文件;

然后,每一个输入文件都对应一个 reader。

直接上代码:

def merge_pdf(input_pdfs, output_pdf):
    pdf_writer = PdfWriter()
    for input_pdf in input_pdfs:
        pdf_reader = PdfReader(input_pdf)
        for page in pdf_reader.pages:
            pdf_writer.add_page(page)
    with open(output_pdf, 'wb') as f:
        pdf_writer.write(f)

5. 单个 PDF 分割

如果想把一个大型 PDF 按需切割成多个文件,比如按页切割 或者 按章节切割,怎么处理?

假设我们每 10 页切割成一个 PDF,这里给一个示例代码:

def split_pdf(input_pdf, per_num=10):
    pdf_reader = PdfReader(input_pdf)
    total_pages = len(pdf_reader.pages)
    file_dir, file_name = os.path.split(input_pdf)
    file_base, file_ext = os.path.splitext(file_name)
    new_folder_path = os.path.join(file_dir, file_base)
    os.makedirs(new_folder_path, exist_ok=True)
    for start in range(0, total_pages, per_num):
        end = min(start + per_num, total_pages) 
        pdf_writer = PdfWriter()
        for i in range(start, end):
            pdf_writer.add_page(pdf_reader.pages[i])
        output_file_path = os.path.join(new_folder_path, f'{file_base}_{start}_{end}{file_ext}')
        with open(output_file_path, 'wb') as f:
            pdf_writer.write(f)

6. PDF 转成图片

按照本文第 2 部分的方式添加水印,很容易被一键去水印,比如 WPS 的会员功能。

如果要使得自己的水印变得更为隐蔽,最好是将 PDF 转为图片,然后在图片中添加水印。

如何将 PDF 转成图片?

这里我们采用 fitz 进行处理:

def pdf2imgs(input_pdf, png_path, zoom=200):
    doc = fitz.open(input_pdf)
    total = doc.page_count
    for pg in tqdm(range(total), total=total, desc='pdf2imgs'):
        page = doc[pg]
        zoom = int(zoom)  # 值越大,分辨率越高,文件越清晰
        trans = fitz.Matrix(zoom / 100.0, zoom / 100.0)
        pm = page.get_pixmap(matrix=trans, alpha=False)
        os.makedirs(png_path, exist_ok=True)
        pm.save(os.path.join(png_path, '%s.png' %(pg)))
    doc.close()
    return total

7. 图片转 PDF

接上一步,将加了水印的图片再合成为 PDF 文件。

def imgs2pdf(image_paths, output_path='1.pdf'):
    doc = fitz.open()
    for img in tqdm(image_paths, desc='imgs2pdf'):
        imgdoc = fitz.open(img)
        pdfbytes = imgdoc.convert_to_pdf()
        imgpdf = fitz.open("pdf", pdfbytes)
        doc.insert_pdf(imgpdf)
    doc.save(output_path)
    doc.close()

写在最后

本文带大家采用 Python 和相关库,自动化批量处理 PDF 文档,完美实现了类似 WPS 会员的高级功能,旨在帮助大家提供办公效率。

这些功能已足够我们解放双手了,还有未尽功能,欢迎评论区留言告诉我。

如果本文对你有帮助,欢迎点赞收藏备用。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值