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


87

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

看来PDFMiner更新了它们的API,我发现的所有相关示例都包含过时的代码(类和方法已更改)。我发现的那些使从PDF文件提取文本的任务更容易的库正在使用旧的PDFMiner语法,因此我不确定如何执行此操作。

照原样,我只是在查看源代码,以查看是否可以解决。


1
请查看stackoverflow.com/help/how-to-askstackoverflow.com/help/mcve并更新您的答案,以便采用更好的格式并符合准则。
帕克

您使用的是2.7.x或3.xx版的哪个Python版本?应该注意的是,作者明确地详细说明了PDFminer不适用于Python 3.xx的原因,这可能是您收到import错误的原因。pdfminer3k如果是这样,您应该使用它,因为它是上述库的常规Python 3导入。
NullDev 2014年

@Nanashi,对不起,我忘了添加我的Python版本。它是2.7,所以这不是问题。我一直在查看源代码,看起来他们重组了一些东西,这就是导入中断的原因。我也找不到PDFMiner的任何文档,否则我将无法使用它:(
DuckPuncher 2014年

我刚刚PDFminer从GitHub上安装了它,并且可以很好地导入。您能否发布代码并发布完整的错误回溯?
NullDev 2014年

@Nanashi,就像我在原始问题中所说的那样,依赖PDFMiner的库在完成导入以及我可以找到的任何示例之前就中断了。这不是PDFMiner问题。这是我在寻找文档,还是有关如何使用PDFMiner的示例。我所能找到的一切都是对PDFMiner使用旧语法。我继续并编辑了我的问题以使其清晰。我认为我使它变得比需要的更加混乱。对于那个很抱歉。
DuckPuncher 2014年

Answers:


181

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

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一起使用。我使用了Python库pdfminer.six,该库于2018年11月发布。


2
工作正常,但是如何处理例如名称中的空格?假设我有一个包含4列的pdf,其中我在一个列中有名字和姓氏,现在它在一行中被解析为firstname,在一行中被解析为lastname,这是一个示例docdro.id/rRyef3x
Deusdeorum,2016年

2
当前使用以下代码出现导入错误:ImportError:没有名为“ pdfminer.pdfpage”的模块
Jeffrey Swan,

1
谢谢,它可以在python v2.7.12和ubuntu 16.04上工作,尽管最好加载编码为utf-8的pdf文档,因为我的示例pdf存在一些编码问题,所以请在使用utf-8编码后尝试此操作并解决问题... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10

2
@DuckPuncher,现在还在吗?我不得不将其更改file(path, 'rb')为`open(path,'rb')才能使我的工作。
伸长了脖子

2
仍适用于Python3.7用户。已安装pdfminer.six == 20181108软件包。到目前为止,对于我的案例而言,这是最好的解决方案,我比较了许多解决方案。
aze45sq6d

29

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

1
它对我不起作用:ModuleNotFoundError:没有名为'pdfminer.pdfpage'的模块,我正在使用python 3.6
Atti

@Atti,以防万一,请确保您已安装pdfminer2,因为还有另一个pdfminer软件包(我讨厌这个)。冻结pip3时,适用于pdfminer2 == 20151206版本。
伊萨扎(Juan Isaza)

5
谢谢,我最终让它开始工作,我从conda forge安装了pdfminer.six
Atti

8
对于Python 3,推荐使用pdfminer.six
Mike Driscoll

这仍然是当前的。我收到相同的ImportError:消息

12

这项功能将于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(open('report.pdf','rb'))

使用内存中已存在的PDF

如果PDF已在内存中(例如,使用请求库从Web检索),则可以使用该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倍。

timeit使用15英寸MBP(2018)来定时文本提取,仅用10页PDF来定时提取功能(没有打开文件等),并得到以下结果:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six的占用空间也很大,需要pycryptodome,该pycryptodome需要安装GCC和其他工具,以将Alpine Linux上的最小安装docker映像从80 MB扩展到350 MB。PyPDF2没有明显的存储影响。


9

完全公开,我是pdfminer.six的维护者之一。

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

命令行

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

$ pdf2txt.py example.pdf

高级API

如果要使用Python提取文本,则可以使用高级api。如果要以编程方式从许多PDF提取文本,则此方法是首选解决方案。

from pdfminer.high_level import extract_text

text = extract_text('samples/simple1.pdf')

可组合的API

还有一个可组合的api,它在处理结果对象方面具有很大的灵活性。例如,您可以使用它来实现自己的布局算法。其他答案中建议使用此方法,但仅在需要自定义pdfminer.six行为方式时,才建议使用此方法。

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('samples/simple1.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())

0

此代码已通过pdfminer for python 3(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

我有可以使用Nitro Pro工具转换的PDF文件。但是,当我尝试使用此处发布的代码转换相同的PDF时,得到的输出表明存在权限错误。这是输出:('来自SAGE Social Science Collections。保留所有权利。\ n \ n \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c')
b00kgrrl

您是什么意思文件流?
文森特

@Vincent与open(file,'rb')作为流:[...]
Rodrigo Formighieri

您是否理想地将这个文件作为表格/大熊猫获取?groupe-psa.com/en/publication/monthly-world-sales-march-2020
诺诺伦敦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.