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

120 投票
6 回答
215790 浏览
提问于 2025-04-28 21:05

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

看起来PDFMiner更新了他们的接口,我找到的所有相关示例都包含过时的代码(类和方法都发生了变化)。我找到的一些库虽然可以让从PDF文件中提取文本的任务变得简单,但它们使用的是旧版的PDFMiner语法,所以我不太确定该怎么做。

目前,我只能查看源代码,看看能否搞明白。

暂无标签

6 个回答

2

这段代码是用 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
29

首先要说明的是,我是pdfminer.six的维护者之一。这个项目是一个社区维护的版本,专门用于Python 3的pdfminer。

现在,它有多种接口可以用来从PDF中提取文本,具体取决于你的需求。在后台,这些接口都使用相同的逻辑来解析和分析布局。

(所有示例都假设你的PDF文件叫做example.pdf

命令行工具

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

$ pdf2txt.py example.pdf

高级接口

如果你想用Python提取文本(属性),可以使用高级接口。这种方法是程序化提取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')

可组合接口

还有一个可组合接口,它在处理结果对象时提供了很大的灵活性。例如,它允许你创建自己的布局算法。这种方法在其他回答中也有提到,但我建议只有在你需要自定义某个组件时再使用。

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())

类似的问题和答案在这里。我会尽量保持它们的一致性。

33

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
34

这个内容是在2020年5月用Python3的PDFminer six库实现的。

安装这个库

$ 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已经在内存里,比如通过requests库从网上获取的,就可以用io库把它转换成流:

import io

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

与PyPDF2的性能和可靠性比较

PDFminer.six的可靠性比PyPDF2更高,特别是在处理某些类型的PDF时,尤其是PDF版本1.7。

不过,用PDFminer.six提取文本的速度比PyPDF2慢了大约6倍。

我在一台2018年的15寸MacBook Pro上用timeit测试了文本提取的速度,只测提取功能(不包括打开文件等),用的是一个10页的PDF,结果如下:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six的体积也很大,需要pycryptodome,这又需要安装GCC等其他东西,这样在Alpine Linux上最小的安装docker镜像从80MB变成了350MB。而PyPDF2对存储空间的影响几乎可以忽略不计。

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

215

这里有一个使用当前版本的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

撰写回答