PDFファイルをテキストに変換するPythonモジュールはありますか?pypdfを使用するActivestateで見つかったコードの1つを試してみましたが、生成されたテキストの間にスペースがなく、役に立ちませんでした。
PDFファイルをテキストに変換するPythonモジュールはありますか?pypdfを使用するActivestateで見つかったコードの1つを試してみましたが、生成されたテキストの間にスペースがなく、役に立ちませんでした。
回答:
PDFMinerをお試しください。HTML、SGMLまたは「タグ付きPDF」形式としてPDFファイルからテキストを抽出できます。
タグ付きPDF形式は最もクリーンなようで、XMLタグを削除すると、テキストのみが残ります。
Python 3バージョンは次の場所にあります。
PDFMinerのため、パッケージが変更されましたcodeapeを掲載しました。
編集(もう一度):
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
。要するに、私は交換しLTTextItem
てLTChar
とCsvConverterコンストラクタにLAParamsのインスタンスを通過しました。
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()
LTTextItem
ようLTChar
です。 unixuser.org/~euske/python/pdfminer/index.html#changes
20110515
コメントごとにバージョンの回答に別のセクションを追加しました。
これらのソリューションはいずれも最新バージョンの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])
python3
、後に明らかに括弧以外にprint
交換するコマンド、1が持っているfile
と、コマンドをopen
し、インポートStringIO
パッケージからio
Pdftotextオープンソースプログラム(Xpdfの一部)で、Pythonから呼び出すことができます(要求したものではありませんが、役に立つ場合があります)。問題なく使用しました。私はグーグルがグーグルデスクトップでそれを使用すると思います。
-layout
は、PDFと同じ位置にテキストを保持するオプションがあるため、ここにリストされているツールの中で最も便利なようです。ここで、PDFのコンテンツをそれにパイプする方法を理解できたとしたら。
pdftotext
非常にうまく機能しているようですが、標準出力で結果を表示するには、ハイフンである2番目の引数が必要です。
find . -iname "*.pdf" -exec pdftotext -enc UTF-8 -eol unix -raw {} \;
により、現在のフォルダーから始まるすべてのPDFファイルが再帰的に変換されます。デフォルトでは、生成されたファイルには元の名前に.txt
拡張子が付いています。
pyPDFは正常に動作します(整形式のPDFで作業していると想定しています)。必要なのがテキスト(スペースを含む)だけの場合は、次のようにします。
import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
print page.extractText()
また、メタデータや画像データなどに簡単にアクセスできます。
extractTextコードノートのコメント:
すべてのテキスト描画コマンドを、コンテンツストリームで提供される順序で見つけ、テキストを抽出します。これは、使用するジェネレーターによっては、一部のPDFファイルではうまく機能しますが、他のファイルではうまく機能しません。これは将来的に改良されます。この関数から出てくるテキストの順序に依存しないでください。この関数がより洗練されたものになると変更されるためです。
これが問題であるかどうかは、テキストで何をしているのかに依存します(たとえば、順序が重要でない場合は問題ありません。ジェネレータがテキストを表示される順序でストリームに追加する場合は問題ありません) 。私は問題なくpyPdf抽出コードを日常的に使用しています。
ライブラリとして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に対して作成されています。以下のコメントを参照してください。
pdfminer
、ではなくなりましたpdflib
)。pdf2txt.py
PDFminerソースのソースを確認することをお勧めします。上記のコードは、そのファイルの古いバージョンに触発されたものです。
slate
ライブラリからPDFMinerを使用することを非常に簡単にするプロジェクトです。
>>> with open('example.pdf') as f:
... doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'
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()
C:\Python27\Scripts\pdfminer\tools\pdf2txt.py
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
PDFminerは、私が試したpdfファイルのすべてのページにおそらく1行[7ページの1ページ目...]を与えてくれました。
私がこれまでに得た最良の答えは、pdftoipe、またはそれがXpdfに基づいているc ++コードです。
さらに、Pythonからも使用できる商用JavaライブラリであるPDFTextStreamがあります。
私は引数pdftohtml
とともに使用し、-xml
結果をで読み取りました。これにより、PDF内のsubprocess.Popen()
すべてのテキストスニペットのx座標、y座標、幅、高さ、およびフォントが得られます。同じエラーメッセージが出力されるため、「evince」もおそらくこれを使用していると思います。
柱状データを処理する必要がある場合は、PDFファイルに適したアルゴリズムを発明する必要があるため、少し複雑になります。問題は、PDFファイルを作成するプログラムが、必ずしもテキストを論理的な形式でレイアウトするとは限らないことです。単純なソートアルゴリズムを試すこともできますが、時々機能しますが、「ストラグラー」や「ストレイ」など、思い通りの順序で配置されないテキストが存在する可能性があります。だからあなたは創造的になる必要があります。
私が取り組んでいるPDFの1つを見つけるのに約5時間かかりました。しかし、今はかなりうまくいきます。幸運を。
今日、そのソリューションが見つかりました。私にとってはうまくいきます。PDFページをPNG画像にレンダリングすることもできます。 http://www.swftools.org/gfx_tutorial.html