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

哪个是将PDF文件转换为文本的最佳Python模块?

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

http://www.unixuser.org/~euske/python/pdfminer/index.html

标记的PDF格式似乎是最干净的,剥离XML标签只剩下裸露的文本。

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

自从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的更新。 简而言之,我将LTTextItemreplace为LTTextItem ,并将一个LAParams实例传递给CsvConverter构造函数。

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

由于这些解决scheme都不支持最新版本的PDFMiner,我写了一个简单的解决scheme,将使用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]) 

pyPDF工作正常(假设你正在使用格式良好的PDF)。 如果你想要的只是文本(带空格),你可以这样做:

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

您还可以轻松访问元数据,图像数据等等。

extractText代码中的注释注释:

find所有文本绘图命令,按照它们在内容stream中提供的顺序,并提取文本。 这适用于某些PDF文件,但对其他文件很不好,这取决于所使用的发生器。 这将在未来完善。 不要依赖来自这个函数的文本的顺序,因为如果这个函数变得更复杂,它将会改变。

不pipe这是否是一个问题取决于你对文本做什么(例如,如果顺序没有关系,没关系,或者如果生成器按照显示的顺序向文本添加文本,那很好) 。 我在日常使用pyPdf提取代码,没有任何问题。

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

你也可以很容易地使用pdfminer作为一个库。 您可以访问pdf的内容模型,并可以创build自己的文本提取。 我这样做,将PDF内容转换为分号分隔的文本,使用下面的代码。

这个函数只是根据它们的y坐标和x坐标对TextItem内容对象进行sorting,并且输出具有与一个文本行相同的y坐标的项目,用“;”分隔同一行上的对象。 字符。

使用这种方法,我能够从PDF中提取文本,没有其他工具能够提取适合于进一步parsing的内容。 我尝试过的其他工具包括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编写的,请参阅下面的注释。

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

重新使用pdfminer自带的pdf2txt.py代码; 你可以做一个函数,将采取的pathPDF; 可选地,一个outtype(txt | html | xml |标签),并且像命令行pdf2txt {'-o':'/path/to/outfile.txt'…}一样select。 默认情况下,你可以调用:

 convert_pdf(path) 

将创build一个文本文件,在文件系统上的兄弟姐妹到原始的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 

另外还有PDFTextStream ,这是一个商业Java库,也可以从Python使用。

我已经使用pdftohtml和'-xml'参数,用subprocess.Popen()读取结果,这会给你pdf中每个'snippet'文本的x坐标,y坐标,宽度,高度和字体。 我认为这也是“evince”可能使用的,因为同样的错误信息也会出现。

如果你需要处理列数据,它会变得稍微复杂,因为你必须发明一个适合你的PDF文件的algorithm。 问题在于,制作PDF文件的程序并不一定是以任何逻辑格式排列文本。 你可以尝试一下简单的sortingalgorithm,它有时可以起作用,但是可能会有一些“落后者”和“stream浪者”,这些文本没有按照你认为的顺序排列……所以你必须有创意。

我花了大约5个小时才找出一个正在处理的PDF文件。 但是现在效果还不错。 祝你好运。

PDFminer给了我一个pdf文件的每个页面上我可能只有一行[第1页,共7页…]。

到目前为止,最好的答案是pdftoipe,或者是基于Xpdf的c ++代码。

看到我的问题是什么pdftoipe的输出看起来像。

今天find解决scheme 对我很好。 即使将PDF页面呈现为PNG图像。 http://www.swftools.org/gfx_tutorial.html