408

PDFファイルをテキストに変換するPythonモジュールはありますか?Activestateで見つかったpypdfを使用するコードを1つ試しましたが、生成されたテキストの間にスペースがなく、役に立たなかった。

4

13 に答える 13

158

PDFMinerをお試しください。PDFファイルからHTML、SGML、または「タグ付きPDF」形式でテキストを抽出できます。

タグ付きPDF形式が最もクリーンなようで、XMLタグを削除すると裸のテキストだけが残ります。

Python3バージョンは次の場所で入手できます。

于 2008-08-25T05:21:22.927 に答える
142

codeapeが投稿されてから、PDFMinerパッケージが変更されました。

編集(再度):

PDFMiner のバージョンが再度更新されました20100213

インストールしたバージョンは、次の方法で確認できます。

>>> import pdfminer
>>> pdfminer.__version__
'20100213'

これが更新されたバージョンです(私が変更/追加したものについてのコメント付き):

def pdf_to_csv(filename):
    from cStringIO import StringIO  #<-- added so you can copy/paste this to try it
    from pdfminer.converter import LTTextItem, TextConverter
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.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, LTTextItem):
                    (_,_,x,y) = child.bbox                   #<-- changed
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)  #<-- changed

            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, codec="utf-8")  #<-- changed 
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       #<-- changed
    parser.set_document(doc)     #<-- added
    doc.set_parser(parser)       #<-- added
    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()

編集(もう一度):

これはpypiの最新バージョンの更新です20100619p1。要するに、LAParams のインスタンスを置き換えLTTextItemLTCharCsvConverter コンストラクターに渡しました。

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter    #<-- changed
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.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, LTChar):               #<-- changed
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)

            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, codec="utf-8", laparams=LAParams())  #<-- changed
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

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

    interpreter = PDFPageInterpreter(rsrc, device)

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

    device.close()
    fp.close()

    return outfp.getvalue()

編集(もう一度):

バージョンの更新20110515(Oeufcoque Penteano のおかげです!):

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.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:                #<-- changed
                if isinstance(child, LTChar):
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child._text.encode(self.codec) #<-- changed

            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, codec="utf-8", laparams=LAParams())
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

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

    interpreter = PDFPageInterpreter(rsrc, device)

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

    device.close()
    fp.close()

    return outfp.getvalue()
于 2009-08-10T20:47:36.627 に答える
73

これらのソリューションは最新バージョンの PDFMiner をサポートしていないため、PDFMiner を使用して PDF のテキストを返す簡単なソリューションを作成しました。これは、インポートエラーが発生している場合に機能しますprocess_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])  
于 2014-02-04T22:16:06.440 に答える
52

Pdftotext Python から呼び出すことができるオープン ソース プログラム (Xpdf の一部) (あなたが求めたものではありませんが、役に立つかもしれません)。問題なく使えました。GoogleデスクトップでGoogleが使用していると思います。

于 2008-08-28T09:46:53.123 に答える
45

pyPDFは問題なく動作します (整形式の PDF を使用していると仮定します)。必要なのがテキスト (スペースを含む) だけの場合は、次のようにすることができます。

import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
    print page.extractText()

また、メタデータや画像データなどにも簡単にアクセスできます。

extractText コードのコメントには次のように記載されています。

すべてのテキスト描画コマンドを、コンテンツ ストリームで提供されている順序で見つけて、テキストを抽出します。これは、使用するジェネレーターに応じて、一部の PDF ファイルではうまく機能しますが、他のファイルではうまく機能しません。これは今後洗練される予定です。この関数がより高度になると変更されるため、この関数から出てくるテキストの順序に依存しないでください。

これが問題であるかどうかは、テキストに対して何を行っているかによって異なります (たとえば、順序が重要でない場合は問題ありません。または、ジェネレーターが表示される順序でストリームにテキストを追加する場合は問題ありません)。 . 問題なくpyPdf抽出コードを日常的に使用しています。

于 2008-09-07T04:47:09.267 に答える
21

pdfminer をライブラリとして簡単に使用することもできます。PDF のコンテンツ モデルにアクセスでき、独自のテキスト抽出を作成できます。以下のコードを使用して、pdf コンテンツをセミコロン区切りのテキストに変換するためにこれを行いました。

この関数は、TextItem コンテンツ オブジェクトを y 座標と x 座標に従って単純に並べ替え、同じ y 座標を持つアイテムを 1 つのテキスト行として出力し、同じ行のオブジェクトを「;」で区切ります。文字。

このアプローチを使用して、他のツールではさらに解析するのに適したコンテンツを抽出できなかった 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 に対して書かれています。以下の私のコメントを参照してください。

于 2008-11-24T14:20:18.960 に答える
17

slateライブラリから PDFMiner を使用することを非常に簡単にするプロジェクトです。

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   
于 2011-01-31T00:27:17.413 に答える
9

Python モジュール内で特定の PDF をプレーン テキストに変換する必要がありました。PDFMiner 20110515を使用し、 pdf2txt.pyツールを読んだ後、次の簡単なスニペットを書きました。

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() 
于 2013-05-28T16:01:27.173 に答える
6

pdfminer に付属する pdf2txt.py コードの転用。PDFへのパスを取る関数を作成できます。オプションで、outtype (txt|html|xml|tag) と、コマンドライン 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
于 2010-07-18T19:17:56.633 に答える
1

私は引数で使用pdftohtmlし、結果を で読み取ります。これにより、pdf 内のテキストのすべてのスニペットのx 座標、y 座標、幅、高さ、およびフォントが得られます。同じエラーメッセージが吐き出されるので、これはおそらく「evince」も使用するものだと思います。-xmlsubprocess.Popen()

列データを処理する必要がある場合は、pdf ファイルに適したアルゴリズムを考案する必要があるため、少し複雑になります。問題は、PDF ファイルを作成するプログラムが、必ずしもテキストを論理的な形式でレイアウトするとは限らないことです。単純なソート アルゴリズムを試してみると、うまくいく場合もありますが、「はぐれ者」や「はぐれ者」、つまり、思ったとおりの順序にならないテキストが少しある可能性があります。だからあなたは創造的にならなければなりません。

私が取り組んでいたpdfの1つを理解するのに約5時間かかりました。しかし、今ではかなりうまく機能しています。幸運を。

于 2010-11-12T22:34:05.550 に答える
1

PDFminer は、私が試した PDF ファイルのすべてのページでおそらく 1 行 [page 1 of 7...] を与えてくれました。

私がこれまでに持っている最良の答えは、pdftoipe、または Xpdf に基づいた c++ コードです。

pdftoipe の出力がどのように見えるかについての私の質問を参照してください。

于 2008-08-26T02:04:10.897 に答える
1

さらに、Python からも使用できる商用 Java ライブラリであるPDFTextStreamがあります。

于 2008-11-12T17:08:47.040 に答える
0

今日その解決策を見つけました。私にとってはうまくいきます。PDF ページを PNG 画像にレンダリングすることもできます。 http://www.swftools.org/gfx_tutorial.html

于 2011-01-31T00:22:57.110 に答える