本文只讨论技术实现。请大家尊重版权,拒绝盗版。
背景
PDF加密是一种保护PDF文档内容的技术,通过密码或权限设置来控制对文档的访问和操作。PDF加密主要有两种类型:用户密码和所有者密码。
- 用户密码(User Password):需要在打开PDF文档时输入的密码。如果没有这个密码,文档将无法打开和查看。
- 所有者密码(Owner Password):用于控制文档的权限,比如打印、复制文本和图像、编辑文档等。这种密码可以让用户打开和查看文档,但限制其他操作。
PDF加密的实现
在不同的平台和工具上,可以通过多种方式实现PDF加密。以下是几种常见的方法:
使用Adobe Acrobat
Adobe Acrobat是一个流行的PDF处理工具,可以轻松地加密PDF文档:
- 打开Adobe Acrobat并加载你要加密的PDF文件。
- 选择“文件” > “保护” > “使用密码加密”。
- 在弹出的对话框中,设置用户密码和/或所有者密码。
- 选择要应用的权限(如是否允许打印或编辑文档)。
- 点击“确定”保存设置,然后保存加密后的PDF文件。
最近在备考架构师,在网上得到了一些资料,奈何这些PDF文件是有密码保护的,每次打开都要输入密码很不方便,尤其是在手机上用微信读书打开时。
于是就有了今天的话题,我们能不能把这些密码自动去掉方便我们的查看与学习。
我这种情况是预先知道了打开的密码,不涉及到暴力破解的问题。
技术依赖
我们主要使用Python的PyPDF2这个库的decrypt方法来去除密码。
实现思路
我们的目录大致如下图所示
这里每个文件夹都有若干个PDF文件,我们希望它能自动把每个PDF都去除密码,因此需要我们先能遍历出所有的PDF文件并使用PyPDF2的decrypt
这个方法将密码移除,将移除后的PDF字节流保存为一个新的文件。
开始编码
首先,确保你已经安装了 PyPDF2
库。如果没有安装,可以使用 pip 进行安装:
pip install PyPDF2
pip install pycryptodome
我们先写一个获取指定目录下所有的PDF文件的脚本,包括子目录下的。
如果你想要包括目录下所有子目录中的 PDF 文件,你可以在 os.walk
函数中设置 topdown
参数为 True
。这样可以确保在遍历子目录时,仍然能够遍历子目录中的所有文件
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腾讯技术创作特训营最新征文,快来和我瓜分大奖!