如何从压缩的PDF/A中提取文本?

4

为了机器学习的目的(使用sckit-learn),我需要从大量PDF文件中提取原始文本。首先,我使用xpdf pdftotext来完成这个任务:

exe = r'"'+os.path.join(xpdf_path,"pdftotext.exe")+'"'
cmd = exe+" "+"\""+pdf+"\""+" "+"\""+pdf+".txt"+"\""
subprocess.check_output(cmd)
with open(pdf+".txt") as f:
    texto_converted = f.read()

但不幸的是,其中一些文件我无法获取到文本,因为它们在其pdf源上使用了“流”,比如这个

结果就像这样:

59!"#$%&'()*+,-.#/#01"21"" 345667.0*(879:4$;<;4=<6>4?$@"12!/ 21#$@A$3A$>@>BCDCEFGCHIJKIJLMNIJILOCNPQRDS QPFTRPUCTCVQWBCTTQXFPYTO"21 "#/!"#(Z[12\&A+],$3^_3;9`Z &a# .2"#.b#"(#c#A(87*95d$d4?$d3e#Z"f#\"#2b?2"#`Z 2"!eb2"#H1TBRgF JhiO
jFK# 2"k#`Z !#212##"elf/e21m#*c!n2!!#/bZ!#2#`Z "eo ]$5<$@;A533> "/\ko/f\#e#e#p

我甚至试过使用zlib + regex:

import re
import zlib

pdf = open("pdfa.pdf", "rb").read()
stream = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)

for s in re.findall(stream,pdf):
    s = s.strip(b'\r\n')
    try:
        print(zlib.decompress(s).decode('UTF-8'))
        print("")
    except:
        pass

结果类似于这样:
1 0 -10 -10 10 10 d1
0.01 0 0 0.01 0 0 cm
1 0 -10 -10 10 10 d1
0.01 0 0 0.01 0 0 cm

我甚至试过使用pdftopng(xpdf)将PDF转为png后再用tesseract识别,但都没有成功。那么,有没有办法使用Python或第三方应用程序从这样的PDF中提取纯文本?

2个回答

2

如果你想解压PDF文件中的流,我可以推荐使用qpdf,但在这个文件上操作。

 qpdf --decrypt --stream-data=uncompress document.pdf out.pdf

但这也无法解决问题。

不过我不确定为什么你使用 xpdftesseract 的尝试没有成功,使用 image-magick 的 convert 在临时目录中创建 PNG 文件,并使用 tesseract,你可以执行以下操作:

import os
from pathlib import Path
from tempfile import TemporaryDirectory
import subprocess

DPI=600

def call(*args):
    cmd = [str(x) for x in args]
    return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode('utf-8')

def ocr(docpath, lang):
    result = []
    abs_path = Path(docpath).expanduser().resolve()
    old_dir = os.getcwd()
    out = Path('out.txt')
    with TemporaryDirectory() as tmpdir:
         os.chdir(tmpdir)
         call('convert', '-density', DPI, abs_path, 'out.png')
         index = -1
         while True:
             # names have no leading zeros on the digits, would be difficult to sort glob() output
             # so just count them
             index += 1
             png = Path(f'out-{index}.png')
             if not png.exists():
                 break
             call('tesseract', '--dpi', DPI, png, out.stem, '-l', lang)
             result.append(out.read_text())
         os.chdir(old_dir)
    return result

pages = ocr('~/Downloads/document.pdf', 'por')
print('\n'.join(pages[1].splitlines()[21:24]))

这将会给出:

DA NÃO REALIZAÇÃO DE AUDIÊNCIA DE AUTOCOMPOSIÇÃO NO CASO EM CONCRETO

Com vista a obter maior celeridade processual, assim como da impossibilidade de conciliação entre

如果你使用的是Windows系统,请确保PDF文件没有在其他进程中打开(比如PDF阅读器),因为Windows似乎不喜欢这样。最终的“print”输出被限制了,因为完整的输出非常大。转换和OCR处理需要一些时间,因此您可能想要取消注释“call()”中的“print”,以获取一些进度的感觉。

1

有两种相对简单的技术可供使用。

1)谷歌的“Tessaract”开源OCR(光学字符识别)。您可以将其均匀地应用于所有PDF文件,尽管将所有数据转换为像素,然后在其上进行操作会更加计算密集。哪个更重要,工程师的时间还是CPU的时间?有一个pytesseract模块。请注意,此工具适用于图像格式,因此您必须使用类似GhostScript(另一个开源项目)的东西将PDF的所有页面转换为图像,然后在这些图像上运行[py]tessaract。

2) pyPDF可以获取每一页,并以它们被绘制到页面上的顺序编程提取任何文本绘制操作。这可能与页面的逻辑阅读顺序完全不同...虽然PDF文件“可能”先绘制所有的“a”,然后再绘制所有的“b”(等等),但实际上将所有内容都绘制在“字体a”中,然后再绘制“字体b”中的所有内容更加高效。需要注意的是,“字体b”可能只是“字体a”的斜体版本。这会产生一个更短/更有效的绘图命令流,尽管可能不足以成为一个好的商业决策。

关键是,一堆随机的PDF文件可能需要你进行OCR识别。一个组装不良的PDF文件(其中一个字体子集没有“转换为Unicode”的数据)即使只有文本绘制操作,也无法正确地挖掘出文本。如果你不知道前五个字形是“g-l-y-p-h”,因为它们被使用的顺序,那么“从“字体C”中绘制第一到第五个字形”就没有意义。

另一方面,如果您有自制的PDF文件或所有PDF文件来自某些已知来源(例如Word的pdf转换器),您将事先知道可以期望什么。
请注意,上面提到的唯一我实际使用过的是Ghostscript。我记得它具有坚实的命令行界面,我们曾经用它生成一些在线PDF查看器的图像,那是很多年前的事情了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接