如何在 Python 中解锁“安全”(读保护)PDF?
Posted
技术标签:
【中文标题】如何在 Python 中解锁“安全”(读保护)PDF?【英文标题】:How to unlock a "secured" (read-protected) PDF in Python? 【发布时间】:2015-03-27 09:29:51 【问题描述】:在 Python 中,我使用 pdfminer 从 pdf 中读取文本,并使用此消息下方的代码。我现在收到一条错误消息:
File "/usr/local/lib/python2.7/dist-packages/pdfminer/pdfpage.py", line 124, in get_pages
raise PDFTextExtractionNotAllowed('Text extraction is not allowed: %r' % fp)
PDFTextExtractionNotAllowed: Text extraction is not allowed: <cStringIO.StringO object at 0x7f79137a1
ab0>
当我用 Acrobat Pro 打开这个 pdf 文件时,发现它是安全的(或“读保护”)。但是,从this link 中,我了解到有许多服务可以轻松禁用这种读取保护(例如pdfunlock.com。当深入研究pdfminer 的源代码时,我看到上面的错误是在these lines 上生成的。
if check_extractable and not doc.is_extractable:
raise PDFTextExtractionNotAllowed('Text extraction is not allowed: %r' % fp)
由于有许多服务可以在一秒钟内禁用这种读保护,我认为这很容易做到。看来.is_extractable
是doc
的一个简单属性,但我觉得不是把.is_extractable
改成True那么简单..
有人知道如何使用 Python 禁用 pdf 的读取保护吗?欢迎所有提示!
================================================ =
您将在下面找到我目前用来从非读保护中提取文本的代码。
def getTextFromPDF(rawFile):
resourceManager = PDFResourceManager(caching=True)
outfp = StringIO()
device = TextConverter(resourceManager, outfp, codec='utf-8', laparams=LAParams(), imagewriter=None)
interpreter = PDFPageInterpreter(resourceManager, device)
fileData = StringIO()
fileData.write(rawFile)
for page in PDFPage.get_pages(fileData, set(), maxpages=0, caching=True, check_extractable=True):
interpreter.process_page(page)
fileData.close()
device.close()
result = outfp.getvalue()
outfp.close()
return result
【问题讨论】:
您是否尝试将 .is_extractable 更改为 True?实际上,它很有可能会起作用。 您是否尝试过传递密码?对于 PDFPage.get_pages(fileData, set(), maxpages=0, password=password,caching=True, check_extractable=True) 中的页面: 见下面我的帖子。此行为在 pdfminer.six 中进行了更改,显示警告而不是引发错误。 【参考方案1】:完全披露,我是pdfminer.six 的维护者之一。它是用于 python 3 的 pdfminer 的社区维护版本。
这个问题was fixed in 2020 默认禁用check_extractable
。它现在显示警告而不是引发错误。
类似问答here。
【讨论】:
【参考方案2】:我使用下面的代码使用pikepdf 并且能够覆盖。
import pikepdf
pdf = pikepdf.open('filepath', allow_overwriting_input=True)
pdf.save('filepath')
【讨论】:
【参考方案3】:如果您想解锁文件夹中的所有pdf文件而不重命名它们,您可以使用此代码:
import glob, os, pikepdf
p = os.getcwd()
for file in glob.glob('*.pdf'):
file_path = os.path.join(p, file).replace('\\','/')
init_pdf = pikepdf.open(file_path)
new_pdf = pikepdf.new()
new_pdf.pages.extend(init_pdf.pages)
new_pdf.save(str(file))
在pikepdf 库中,无法通过以相同名称保存现有文件来覆盖现有文件。相反,您想将页面复制到新创建的空 pdf 文件中,然后保存。
【讨论】:
这对我来说就像一个魅力。我只需要将密码参数添加到 init_pdf = pikepdf.open(file_path, password='mypass')【参考方案4】:我也遇到了解析安全 pdf 的相同问题,但使用 pikepdf 库已解决。我在我的 jupyter notebbok 和 windows os 上尝试了这个库,但它给出了错误,但它在 Ubuntu 上运行顺利
【讨论】:
【参考方案5】:“check_extractable=True”参数是设计使然。 一些 PDF 明确禁止提取文本,PDFMiner 遵循该指令。您可以覆盖它(提供 check_extractable=False),但风险自负。
【讨论】:
【参考方案6】:我在尝试让 qpdf 在我的程序中运行时遇到了一些问题。我找到了一个有用的库 pikepdf,它基于 qpdf 并自动将 pdf 转换为可提取的。
使用它的代码非常简单:
import pikepdf
pdf = pikepdf.open('unextractable.pdf')
pdf.save('extractable.pdf')
【讨论】:
如果 pdf 受密码保护,则可以使用 pikepdf.open('unextractable.pdf', password='thepassword') 设置密码【参考方案7】:在我的情况下,没有密码,但只需设置 check_extractable=False
即可绕过有问题文件的 PDFTextExtractionNotAllowed
异常(在其他查看器中打开正常)。
【讨论】:
文件未加密或密码保护时抛出错误时的最佳答案。 你能用例子分享一下吗【参考方案8】:据我所知,在大多数情况下,PDF 的全部内容实际上是加密的,使用密码作为加密密钥,因此简单地将 .is_extractable
设置为 True
对您没有帮助。
根据这个帖子:
Does a library exist to remove passwords from PDFs programmatically?
我建议使用qpdf
之类的命令行工具删除读取保护(易于安装,例如在 Ubuntu 上,如果您还没有 apt-get install qpdf
,请使用它):
qpdf --password=PASSWORD --decrypt SECURED.pdf UNSECURED.pdf
然后用pdfminer
打开解锁的文件,然后做你的事情。
对于纯 Python 解决方案,您可以尝试使用 PyPDF2
及其 .decrypt()
方法,但它不适用于所有类型的加密,所以说真的,您最好只使用 qpdf
-见:
https://github.com/mstamy2/PyPDF2/issues/53
【讨论】:
以上是关于如何在 Python 中解锁“安全”(读保护)PDF?的主要内容,如果未能解决你的问题,请参考以下文章