在python中使用PDFMiner从PDF文件中提取文本



我正在寻找关于如何使用PDFMiner和Python从PDF文件中提取文本的文档示例。

看起来PDFMiner更新了他们的API,我发现的所有相关示例都包含过时的代码(类和方法已经更改)。我发现的使从PDF文件中提取文本的任务更容易的库使用了旧的PDFMiner语法,所以我不知道如何做到这一点。

事实上,我只是在查看源代码,看看我是否能弄清楚。

以下是使用当前版本的PDFMiner(2016年9月)从PDF文件中提取文本的工作示例

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import StringIO
def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True):
        interpreter.process_page(page)
    text = retstr.getvalue()
    fp.close()
    device.close()
    retstr.close()
    return text

PDFMiner的结构最近发生了变化,因此这应该适用于从PDF文件中提取文本。

编辑:截至2018年6月7日仍在工作。在Python版本3.x 中验证

编辑:该解决方案于2019年10月3日与Python 3.7配合使用。我使用了2018年11月发布的Python库pdfminer.six

这将于2020年5月在Python3中使用PDFminer 6。

安装软件包

$ pip install pdfminer.six

导入包

from pdfminer.high_level import extract_text

使用保存在磁盘上的PDF

text = extract_text('report.pdf')

或者:

with open('report.pdf','rb') as f:
    text = extract_text(f)

使用内存中已存在的PDF

如果PDF已经在内存中,例如,如果使用请求库从web检索,则可以使用io库将其转换为流:

import io
response = requests.get(url)
text = extract_text(io.BytesIO(response.content))

与PyPDF2相比的性能和可靠性

PDFminer.ix比PyPDF2(在某些类型的PDF中失败)更可靠,尤其是PDF版本1.7

然而,使用PDFminer.six的文本提取明显比PyPDF2慢6倍。

我用CCD_ 3在一个15〃的时钟上定时文本提取;MBP(2018),只定时提取功能(无文件打开等)与10页PDF,并得到以下结果:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six也有巨大的占地面积,需要pycryptodome,它需要安装GCC和其他东西,在Alpine Linux上将最小的安装docker映像从80 MB推到350 MB。PyPDF2没有明显的存储影响。

更新(2022-08-04):根据Martin Thoma的说法,PyPDF2在过去两年中有了很大的改进,所以也要尝试一下。这是他的基准

DuckPuncher的精彩回答,对于Python3,请确保安装pdfminer2并执行:

import io
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage

def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos = set()
    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages,
                                  password=password,
                                  caching=caching,
                                  check_extractable=True):
        interpreter.process_page(page)

    fp.close()
    device.close()
    text = retstr.getvalue()
    retstr.close()
    return text

完全公开,我是pdfminer.six的维护者之一。它是用于python 3的pdfminer的社区维护版本。

如今,它有多个api可以根据您的需要从PDF中提取文本。在幕后,所有这些api都使用相同的逻辑来解析和分析布局。

(所有示例都假设您的PDF文件名为example.PDF

命令行

如果只想提取一次文本,可以使用命令行工具pdf2txt.py:

$ pdf2txt.py example.pdf

高级api

如果您想使用Python提取文本(属性),可以使用高级api。如果您想以编程方式从PDF中提取信息,这种方法是首选的解决方案。

from pdfminer.high_level import extract_text
# Extract text from a pdf.
text = extract_text('example.pdf')
# Extract iterable of LTPage objects.
pages = extract_pages('example.pdf')

可组合api

还有一个可组合的api,它在处理生成的对象时提供了很大的灵活性。例如,它允许您创建自己的布局算法。其他答案中建议使用这种方法,但我只建议您在需要自定义某些组件时使用这种方法。

from io import StringIO
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
output_string = StringIO()
with open('example.pdf', 'rb') as in_file:
    parser = PDFParser(in_file)
    doc = PDFDocument(parser)
    rsrcmgr = PDFResourceManager()
    device = TextConverter(rsrcmgr, output_string, laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.create_pages(doc):
        interpreter.process_page(page)
print(output_string.getvalue())

类似的问题和答案在这里。我会尽量让他们保持同步。

此代码使用python 3的pdfminer(pdfminer-20191125)进行测试

from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.layout import LTTextBoxHorizontal
def parsedocument(document):
    # convert all horizontal text into a lines list (one entry per line)
    # document is a file stream
    lines = []
    rsrcmgr = PDFResourceManager()
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.get_pages(document):
            interpreter.process_page(page)
            layout = device.get_result()
            for element in layout:
                if isinstance(element, LTTextBoxHorizontal):
                    lines.extend(element.get_text().splitlines())
    return lines

我意识到这是一个老问题。对于任何试图使用pdfminer的人,您应该切换到当前维护的版本pdfminer.six。

相关内容

  • 没有找到相关文章

最新更新