PDF文件批量去除密码

2024-05-17 11:19:21 浏览数 (2)

本文只讨论技术实现。请大家尊重版权,拒绝盗版。

背景

PDF加密是一种保护PDF文档内容的技术,通过密码或权限设置来控制对文档的访问和操作。PDF加密主要有两种类型:用户密码和所有者密码。

  1. 用户密码(User Password):需要在打开PDF文档时输入的密码。如果没有这个密码,文档将无法打开和查看。
  2. 所有者密码(Owner Password):用于控制文档的权限,比如打印、复制文本和图像、编辑文档等。这种密码可以让用户打开和查看文档,但限制其他操作。

PDF加密的实现

在不同的平台和工具上,可以通过多种方式实现PDF加密。以下是几种常见的方法:

使用Adobe Acrobat

Adobe Acrobat是一个流行的PDF处理工具,可以轻松地加密PDF文档:

  1. 打开Adobe Acrobat并加载你要加密的PDF文件。
  2. 选择“文件” > “保护” > “使用密码加密”。
  3. 在弹出的对话框中,设置用户密码和/或所有者密码。
  4. 选择要应用的权限(如是否允许打印或编辑文档)。
  5. 点击“确定”保存设置,然后保存加密后的PDF文件。

最近在备考架构师,在网上得到了一些资料,奈何这些PDF文件是有密码保护的,每次打开都要输入密码很不方便,尤其是在手机上用微信读书打开时。

于是就有了今天的话题,我们能不能把这些密码自动去掉方便我们的查看与学习。

我这种情况是预先知道了打开的密码,不涉及到暴力破解的问题。

技术依赖

我们主要使用Python的PyPDF2这个库的decrypt方法来去除密码。

实现思路

我们的目录大致如下图所示

这里每个文件夹都有若干个PDF文件,我们希望它能自动把每个PDF都去除密码,因此需要我们先能遍历出所有的PDF文件并使用PyPDF2的decrypt这个方法将密码移除,将移除后的PDF字节流保存为一个新的文件。

开始编码

首先,确保你已经安装了 PyPDF2 库。如果没有安装,可以使用 pip 进行安装:

代码语言:bash复制
pip install PyPDF2
pip install pycryptodome

我们先写一个获取指定目录下所有的PDF文件的脚本,包括子目录下的。

如果你想要包括目录下所有子目录中的 PDF 文件,你可以在 os.walk 函数中设置 topdown 参数为 True。这样可以确保在遍历子目录时,仍然能够遍历子目录中的所有文件

代码语言:python代码运行次数:0复制
import os

def get_pdf_files(directory):
    pdf_files = []
    # 遍历目录及其子目录中的所有文件
    for root, dirs, files in os.walk(directory, topdown=True):
        for file in files:
            # 检查文件是否以 .pdf 结尾
            if file.lower().endswith('.pdf'):
                # 如果是 PDF 文件,则将其路径添加到列表中
                pdf_files.append(os.path.join(root, file))
    return pdf_files

# 示例用法:
directory = '/path/to/directory'  # 替换为你要搜索的目录的路径
pdf_files = get_pdf_files(directory)
print("PDF 文件列表:")
for pdf_file in pdf_files:
    print(pdf_file)

在获取完所有的PDF文件后,我开始最主要的工作,以下代码演示了如何打开一个有密码保护的 PDF 文件,输入密码解锁并保存为一个没有密码的新文件。

具体代码如下:

代码语言:python代码运行次数:0复制
import PyPDF2

def remove_pdf_password(input_pdf, output_pdf, password):
    with open(input_pdf, 'rb') as input_file:
        pdf_reader = PyPDF2.PdfReader(input_file)
        
        # 判断PDF文件是否加密
        if pdf_reader.is_encrypted:
            pdf_reader.decrypt(password)
        
        # 创建一个新的PDF对象
        pdf_writer = PyPDF2.PdfWriter()
        
        # 将去除密码后的每页PDF添加到pdf_writer这个对象中
        for page_num in range(len(pdf_reader.pages)):
            pdf_writer.add_page(pdf_reader.pages[page_num])
        
        # 另存为新文件
        with open(output_pdf, 'wb') as output_file:
            pdf_writer.write(output_file)

input_file = 'encrypted.pdf'
output_file = 'decrypted.pdf'
password = 'your_password_here'

remove_pdf_password(input_file, output_file, password)

两个主要功能都实现之后,我们将两个脚本合并一下。合并后的完整代码如下:

代码语言:python代码运行次数:0复制
import os
import PyPDF2

def get_pdf_files(directory):
    pdf_files = []
    # 遍历目录及其子目录中的所有文件
    for root, dirs, files in os.walk(directory, topdown=True):
        for file in files:
            # 检查文件是否以 .pdf 结尾
            if file.lower().endswith('.pdf'):
                # 如果是 PDF 文件,则将其路径添加到列表中
                pdf_files.append(os.path.join(root, file))
    return pdf_files

def remove_pdf_password(input_pdf, output_pdf, password):
    with open(input_pdf, 'rb') as input_file:
        pdf_reader = PyPDF2.PdfReader(input_file)
        
        # 判断PDF文件是否加密
        if pdf_reader.is_encrypted:
            pdf_reader.decrypt(password)
        
        # 创建一个新的PDF对象
        pdf_writer = PyPDF2.PdfWriter()
        
        # 将去除密码后的每页PDF添加到pdf_writer这个对象中
        for page_num in range(len(pdf_reader.pages)):
            pdf_writer.add_page(pdf_reader.pages[page_num])
        
        # 另存为新文件
        with open(output_pdf, 'wb') as output_file:
            pdf_writer.write(output_file)

def main():
    directory = '/path/to/directory'  # 替换为你要搜索的目录的路径
    pdf_files = get_pdf_files(directory)    
    for pdf_file in pdf_files:
        output_file = pdf_file.replace('.pdf', '_new.pdf')
        password = 'xxxxxxx'  # 替换为PDF文件的密码
        remove_pdf_password(pdf_file, output_file, password)
        print(f"output_file: {output_file}")

if __name__ == "__main__":
    main()

最后

上面的代码只是一个demo,还有很多需要优化的地方,例如文件破损的异常判断,多密码的情况等。

好了,今天的内容就是这些,希望对你有所帮助,我们下期见。


我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

0 人点赞