如何在不写入本地驱动器的情况下访问远程和加密的 PDF 文本

问题描述

我对编码世界很陌生,并且已经被这个问题困住了 3 天,到处寻找答案,因此将不胜感激。我需要从位于 url 的 Pdf 文件提取少量文本。我使用 sessions.get(chart_PDF) 作为定位 URL 的驱动程序,其中 chart_PDF 是下面的示例 URL。

示例网址为 https://www.airservicesaustralia.com/aip/pending/dap/PADGN01-166_09SEP2021.pdf

我知道我可以将其写入本地驱动器,但我不想这样做,我希望能够远程执行,因为我只需要从中获取几个数字。

我曾尝试从 url 页面找到密码进行解密,但找不到。我曾尝试使用 PyPDF2pdfminerpikepdf(可能不太好)。

我只需要检索 PDF 底部附近的两个数字,这些数字可用于我的其余代码。请帮助,即使这是一个简单的修复,我对这一切都很陌生,需要一些帮助。谢谢。

from io import BytesIO
from pikepdf import Pdf as PDF
from pdfminer import high_level
chart_PDF = https://www.airservicesaustralia.com/aip/pending/dap/PADGN01-166_09SEP2021.pdf
retrieve = s.get(chart_PDF)
content = retrieve.content

response =urllib.request.urlopen(chart_PDF)
p = BytesIO(content)
p.getbuffer()
check = pdfpage.get_pages(p,check_extractable=False)
extract = high_level.extract_text(p)

我得到:

PDFTextExtractionNotAllowedWarning:位于 ​​0x000001B007ABEC20 处的 PDF <_io.bytesio pdftextextractionnotallowedwarning>

或者,如果我尝试这个:

from pikepdf import Pdf as PDF
from pdfminer.pdfpage import pdfpage
from PyPDF2 import PdfFileReader
new_pdf = PDF.new()
with PDF.open(p) as pdf:
    print(len(pdf.pages))
    page1 = pdf.pages[0]
    if PdfFileReader.getIsEncrypted(pdf):
        print(True)
        PdfFileReader.decrypt(page1,password='')
pdf.close()

我明白了:

第 1987 行,解密 返回 self._decrypt(password) 属性错误:_decrypt

更新 3/8/21 非常感谢KJ!你真的帮了大忙!

from io import BytesIO
from pdfminer.pdfpage import pdfpage
from pdfminer import high_level

retrieve = s.get(chart_PDF)
content = retrieve.content
bytes = BytesIO(content)
bytes.getbuffer()
pdfpage.get_pages(bytes,check_extractable=False)
extract = high_level.extract_text(bytes,password='') #THIS LINE THROWS ERROR
joined = ''.join(extract)
find_txt = re.findall(r'[(]\d*[-]\d[.]\d[)]',joined)
print(find_txt)
bytes.close()

现在运行良好,我已经能够提取我需要的数字(我基本上已经从 PDF 的括号内提取了所有数字)。我会整理一下,找到我需要的。

奇怪的是,虽然它给了我我需要的东西,但我的 extract = high_level.extract_text(bytes,password='') 行仍然抛出警告:(warning_msg,PDFTextExtractionNotAllowedWarning),这很烦人。不确定这个过程是如何运作的,但它仍然会泄露信息。

我不能使用 try except 否则它会跳过它。解决这个问题的方法是什么?我怎样才能阻止出现这个错误

最终更新

我绕过了警告,现在运行良好。

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    extract = high_level.extract_text(bytes)

为忍受我的无知而干杯,你们帮了很多忙。

解决方法

整个文件必须通过 RAM 下载到设备,这样 blob 作为 FILE 可以在最后解析 一个或多个 %%EOF 和页面 0 的位置(它被转换为 1 或 i)它可以是流中的任何地方,

然后,您可以按照构建的 RANDOM 顺序导航到其他连续编号的页面。如有任何投诉,请联系 Adob​​e。

然而,如果它被缓存为一个物理 FILE 对象是最简单的。如果您不想在磁盘上使用浏览器的内存驱动器

同样,第一页底部的这两个对象可以任何地方混合到“页面”99 的对象的内容中,或者以其他方式混合。 PDF 中的每个字母在极端情况下可以是文件中任何位置的多个对象。但是一个好的创作编辑器会尝试将它们逐行保留。 (没有像单词或段落这样的 PDF 东西。)

我们可以将文件打印为纯文本,看看它是如何合成的,虽然(安全)是允许的。

enter image description here

我尝试从浏览器打印但收效甚微,但我知道这可能取决于浏览器系统和操作系统打印驱动程序。在这里,我使用 Acrobat 便携版将页面打印为文本,因此我们可以看到每个文本块从左边距开始的顺序偏移量,就像 PDF 阅读器需要重建它们一样。

enter image description here

更新 你说你的目标是 (1380-4.4) 到 ALTERNATE 的右边,但是 PDF 没有左右或之前或之后的概念,所以我们在这个文件中发现变量目标是在已知字符之前的 2 个独立部分幸运的是是一个完整的单块(替代)。因此,如果捕获仅限于附近的位置,那么这里纯文本的接近性可能会很好地工作。但是,不能保证 ALTERNATE 始终是单个块。

enter image description here

展示打印机获得顺序数据流的方式可能不是一个好主意 这是一个 PDF 查看器解密文件的方式 enter image description here

正如在这种情况下所说的,ALTERNATE 这个词被定义为文本,但是下一项是“B”下的“3”,它是作为向量路径的文本,它不被称为“字符”,尽管它看起来像一个字体表中的编号字形。我们稍后确实看到其中一些数字存储为“文本”,并且对于您的目标,它与同一对象中的类似文本混合在一起。

enter image description here

因此您需要调用 PDF 解释器来为您提供所有对象的点点滴滴的有意义的翻译,以便您可以提取“正确”的文本。

对于复杂文件中的“简单”单行目标,最简单的方法是先使用 MuPDF 整理文件

    mutool clean -gggg -D infile.pdf outfile.pdf

结合

    PDFTOTXT -layout outfile.pdf outfile.txt

或类似于希望逐行导出该文本,这样您就可以始终之前立即找到您的目标!或在 ALTERNATE 之后。

N.B Mutool 转换为 HTML 会将目标值放在关键字后面的表条目中,如果行数一致,则是一种更简单的查找或 grep 方法。