用于将PDF转换为文本的Python模块

用于将PDF转换为文本的Python模块,python,pdf,text-extraction,pdf-scraping,Python,Pdf,Text Extraction,Pdf Scraping,是否有任何python模块可以将PDF文件转换为文本?我尝试在使用pypdf的Activestate中查找,但生成的文本之间没有空格,没有任何用处 试试看。它可以从PDF文件中提取HTML、SGML或“标记PDF”格式的文本 带标签的PDF格式似乎是最干净的,去掉XML标签只留下裸文本 Python 3版本可在以下位置获得: PDFminer在我尝试使用的pdf文件的每一页上都给了我一行[第1页,共7页…] P>我至今为止最好的答案是PDFToPE,或者C++代码,它基于XPDF。 有关p

是否有任何python模块可以将PDF文件转换为文本?我尝试在使用pypdf的Activestate中查找,但生成的文本之间没有空格,没有任何用处

试试看。它可以从PDF文件中提取HTML、SGML或“标记PDF”格式的文本

带标签的PDF格式似乎是最干净的,去掉XML标签只留下裸文本

Python 3版本可在以下位置获得:


PDFminer在我尝试使用的pdf文件的每一页上都给了我一行[第1页,共7页…]

<> P>我至今为止最好的答案是PDFToPE,或者C++代码,它基于XPDF。 有关pdftoipe的输出,请参见。

一个开源程序(Xpdf的一部分),您可以从python调用它(不是您要求的,但可能有用)。我使用它没有任何问题。我认为谷歌会在谷歌桌面上使用它。

效果很好(假设您使用的是格式良好的PDF)。如果您只需要文本(带空格),可以执行以下操作:

import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
    print page.extractText()
您还可以轻松访问元数据、图像数据等

extractText代码注释中的注释:

在中找到所有文本图形命令 它们在中提供的顺序 内容流,并提取文本。 这适用于某些PDF文件, 但对其他人来说很糟糕,这取决于 这台发电机用的是汽油。这将是 在未来完善。不要依赖 由此产生的文本顺序 函数,因为如果 功能变得更加复杂


这是否是一个问题取决于您对文本所做的操作(例如,如果顺序无关紧要,则无所谓;如果生成器按照文本的显示顺序向流中添加文本,则无所谓)。我有日常使用的pyPdf提取代码,没有任何问题。

此外,还有一个商业Java库,也可以从Python中使用。

您也可以非常轻松地将pdfminer用作库。您可以访问pdf的内容模型,并可以创建自己的文本提取。我这样做是为了使用下面的代码将pdf内容转换为分号分隔的文本

该函数只是根据TextItem内容对象的y和x坐标对其进行排序,并输出与一个文本行具有相同y坐标的项目,用“;”分隔同一行上的对象人物

使用这种方法,我能够从pdf中提取文本,而其他工具无法从中提取适合进一步解析的内容。我尝试过的其他工具包括pdftotext、ps2ascii和在线工具pdftextonline.com

pdfminer是一个非常有用的pdf刮片工具


def pdf_to_csv(filename):
    from pdflib.page import TextItem, TextConverter
    from pdflib.pdfparser import PDFDocument, PDFParser
    from pdflib.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, TextItem):
                    (_,_,x,y) = child.bbox
                    line = lines[int(-y)]
                    line[x] = child.text

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, "ascii")

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(doc, fp)
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

更新


上面的代码是针对旧版本的API编写的,请参见下面我的评论。

自发布后,软件包已更改

编辑(再次):

PDFMiner在版本
20100213中再次更新

您可以通过以下方式检查已安装的版本:

>>> import pdfminer
>>> pdfminer.__version__
'20100213'
以下是最新版本(对我更改/添加的内容进行了评论):

编辑(再编辑一次):

更新版本
20110515
(感谢Oeufcoque Penteano!):

def pdf_to_csv(文件名):
从cStringIO导入StringIO
从pdfminer.converter导入LTChar、TextConverter
从pdfminer.layout导入LAParams
从pdfminer.pdfparser导入PDFDocument,pdfparser
从pdfminer.pdfinterp导入PDFResourceManager、pdfpageexplorer
类别CSV转换器(文本转换器):
定义初始化(self,*args,**kwargs):
TextConverter.\uuuuu初始化(self,*args,**kwargs)
def end_页面(自我,i):
从集合导入defaultdict
lines=defaultdict(lambda:{})

对于self.cur_项中的子项。_objs:#重新调整pdfminer附带的pdf2txt.py代码的用途;您可以创建一个函数,该函数将采用pdf的路径;(可选)输出类型(txt | html | xml |标记)和命令行pdf2txt{'-o':'/path/to/outfile.txt'.}之类的选项。默认情况下,您可以调用:

convert_pdf(path)
将创建一个文本文件,它是文件系统上原始pdf的同级文件

def convert_pdf(path, outtype='txt', opts={}):
    import sys
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
    from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter, TagExtractor
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfdevice import PDFDevice
    from pdfminer.cmapdb import CMapDB

    outfile = path[:-3] + outtype
    outdir = '/'.join(path.split('/')[:-1])

    debug = 0
    # input option
    password = ''
    pagenos = set()
    maxpages = 0
    # output option
    codec = 'utf-8'
    pageno = 1
    scale = 1
    showpageno = True
    laparams = LAParams()
    for (k, v) in opts:
        if k == '-d': debug += 1
        elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') )
        elif k == '-m': maxpages = int(v)
        elif k == '-P': password = v
        elif k == '-o': outfile = v
        elif k == '-n': laparams = None
        elif k == '-A': laparams.all_texts = True
        elif k == '-D': laparams.writing_mode = v
        elif k == '-M': laparams.char_margin = float(v)
        elif k == '-L': laparams.line_margin = float(v)
        elif k == '-W': laparams.word_margin = float(v)
        elif k == '-O': outdir = v
        elif k == '-t': outtype = v
        elif k == '-c': codec = v
        elif k == '-s': scale = float(v)
    #
    CMapDB.debug = debug
    PDFResourceManager.debug = debug
    PDFDocument.debug = debug
    PDFParser.debug = debug
    PDFPageInterpreter.debug = debug
    PDFDevice.debug = debug
    #
    rsrcmgr = PDFResourceManager()
    if not outtype:
        outtype = 'txt'
        if outfile:
            if outfile.endswith('.htm') or outfile.endswith('.html'):
                outtype = 'html'
            elif outfile.endswith('.xml'):
                outtype = 'xml'
            elif outfile.endswith('.tag'):
                outtype = 'tag'
    if outfile:
        outfp = file(outfile, 'w')
    else:
        outfp = sys.stdout
    if outtype == 'txt':
        device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
    elif outtype == 'xml':
        device = XMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams, outdir=outdir)
    elif outtype == 'html':
        device = HTMLConverter(rsrcmgr, outfp, codec=codec, scale=scale, laparams=laparams, outdir=outdir)
    elif outtype == 'tag':
        device = TagExtractor(rsrcmgr, outfp, codec=codec)
    else:
        return usage()

    fp = file(path, 'rb')
    process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password)
    fp.close()
    device.close()

    outfp.close()
    return

我使用了
pdftohtml
-xml
参数,使用
subprocess.Popen()
读取结果,这将为您提供pdf中每个文本片段的x坐标、y坐标、宽度、高度和字体。我认为这也是“evince”可能使用的方法,因为同样的错误消息也会出现

如果您需要处理列数据,它会变得稍微复杂一些,因为您必须发明一种适合您的pdf文件的算法。问题是,制作PDF文件的程序实际上不一定要以任何逻辑格式排列文本。你可以尝试简单的排序算法,它有时会起作用,但可能会有一些“散乱者”和“散乱者”,这些文本片段没有按你认为的顺序排列。所以你必须要有创造力


我花了大约5个小时才为我正在制作的pdf找到一个。但现在效果很好。祝你好运

今天找到了解决方案。这对我很有用。甚至可以将PDF页面渲染为PNG图像。

是一个使从库中使用PDFMiner变得非常简单的项目:

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   

我需要在python模块中将特定的PDF转换为纯文本。我使用了20110515,在阅读了他们的工具后,我写了这个简单的片段:

from cStringIO import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

def to_txt(pdf_path):
    input_ = file(pdf_path, 'rb')
    output = StringIO()

    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    process_pdf(manager, converter, input_)

    return output.getvalue() 

因为这些解决方案都不支持最新版本的PDFMiner,所以我编写了一个简单的解决方案,使用PDFMiner返回pdf文本。这将适用于那些通过
process\u pdf

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
from cStringIO import StringIO

def pdfparser(data):

    fp = file(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print data

if __name__ == '__main__':
    pdfparser(sys.argv[1])  
请参阅以下适用于Python 3的代码:

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

def pdfparser(data):

    fp = open(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print(data)

if __name__ == '__main__':
    pdfparser(sys.argv[1])  

我刚刚添加了一个答案,描述了如何将pdfminer用作库。没有python 3支持:(我在中提供的答案可能对那些看到这个答案并想知道如何使用库的人有用。我举了一个例子
from cStringIO import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

def to_txt(pdf_path):
    input_ = file(pdf_path, 'rb')
    output = StringIO()

    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    process_pdf(manager, converter, input_)

    return output.getvalue() 
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
from cStringIO import StringIO

def pdfparser(data):

    fp = file(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print data

if __name__ == '__main__':
    pdfparser(sys.argv[1])  
import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io

def pdfparser(data):

    fp = open(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print(data)

if __name__ == '__main__':
    pdfparser(sys.argv[1])