【问题标题】:How do I use pdfminer as a library如何使用 pdfminer 作为库
【发布时间】:2011-08-09 04:15:26
【问题描述】:

我正在尝试使用pdfminer 从 pdf 中获取文本数据。我可以使用 pdfminer 命令行工具 pdf2txt.py 成功地将这些数据提取到 .txt 文件中。我目前这样做,然后使用 python 脚本清理 .txt 文件。我想将 pdf 提取过程合并到脚本中并为自己节省一步。

I thought I was on to something when I found this link,但我没有成功解决任何问题。也许那里列出的功能需要再次更新,因为我使用的是更新版本的 pdfminer。

I also tried the function shown here, but it also did not work.

我尝试的另一种方法是使用os.system 在脚本中调用脚本。这也失败了。

我正在使用 Python 版本 2.7.1 和 pdfminer 版本 20110227。

【问题讨论】:

  • 你试过this吗?
  • 我确实看过api谢谢,但不幸的是我的python技能不够强,无法获得工作功能。
  • 您可能会发现此解决方案对类似问题很有用:stackoverflow.com/a/61857301/7483211

标签: python pdf pdfminer


【解决方案1】:

完全披露,我是pdfminer.six 的维护者之一。它是用于 python 3 的 pdfminer 的社区维护版本。

现在,它有多个 api 用于从 PDF 中提取文本,具体取决于您的需要。在幕后,所有这些 api 都使用相同的逻辑来解析和分析布局。

(所有示例都假定您的 PDF 文件名为 example.pdf

命令行

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

$ pdf2txt.py example.pdf

高级 API

如果你想用 Python 提取文本(属性),你可以使用高级 api。如果您想以编程方式从 PDF 中提取信息,这种方法是首选解决方案。

from pdfminer.high_level import extract_text

# Extract text from a pdf.
text = extract_text('example.pdf')

# Extract iterable of LTPage objects.
pages = extract_pages('example.pdf')

可组合的 api

还有一个可组合的 api,它在处理生成的对象时提供了很大的灵活性。例如,它允许您创建自己的布局算法。其他答案中建议使用此方法,但仅当您需要自定义某些组件时,我才会推荐此方法。

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('example.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())

【讨论】:

【解决方案2】:

这是我的解决方案

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
import os 

def convert_pdf_to_txt(path, pages=None):
    if not pages:
        pagenums = set()
    else:
        pagenums = set(pages)
    output = StringIO()
    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    interpreter = PDFPageInterpreter(manager, converter)

    infile = open(path, 'rb')
    for page in PDFPage.get_pages(infile, pagenums):
        interpreter.process_page(page)
    infile.close()
    converter.close()
    text = output.getvalue()
    output.close()
    return text

例如,您只想阅读 pdf 文件的前 3 页:

text = convert_pdf_to_txt('../Data/EN-FINAL Table 9.pdf', pages=[0,1,2])

pdfminer.six==20160614

python: 3.x

【讨论】:

  • 不错!这对我有用。 Python 3.6.2 pdfminer.six
  • Python 3.6 / pdfminer.six / Windows 7下的最佳解决方案
  • 嗨。这将为我的pdf返回这样的字符串。 '(cid:42)(cid:82)(cid:89)(cid:72)(cid:85)(cid:81)(cid:80)(cid:72)(cid:81)(cid:87 )(cid:3)(cid:57)(cid:72)(cid:75)(cid:76)(cid:70)(cid:79)(cid:72)(cid:86)\n\n (cid:20)(cid:25)(cid:18)(cid:19)(cid:2id:87)(cid:86)(cid:15)(cid:3)(cid:37)(cid: 79)'
【解决方案3】:

这个在 python 3 中为我工作。 它需要 PDFMiner.six 包

pip install pdfminer.six

代码如下(和大家的代码一样,有小修正):

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from six 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)
    fp.close()
    device.close()
    str = retstr.getvalue()
    retstr.close()

    return str.replace("\\n","\n")

【讨论】:

    【解决方案4】:

    这适用于我使用最新版本的 pdfminer(截至 2014 年 9 月):

    from pdfminer.pdfparser import PDFParser
    from pdfminer.pdfdocument import PDFDocument
    from pdfminer.pdfpage import PDFPage
    from pdfminer.pdfpage import PDFTextExtractionNotAllowed
    from pdfminer.pdfinterp import PDFResourceManager
    from pdfminer.pdfinterp import PDFPageInterpreter
    from pdfminer.pdfdevice import PDFDevice
    from pdfminer.converter import TextConverter
    from pdfminer.layout import LAParams
    import unicodedata, codecs
    from io import StringIO
    
    def getPDFText(pdfFilenamePath):
        retstr = StringIO()
        parser = PDFParser(open(pdfFilenamePath,'r'))
        try:
            document = PDFDocument(parser)
        except Exception as e:
            print(pdfFilenamePath,'is not a readable pdf')
            return ''
        if document.is_extractable:
            rsrcmgr = PDFResourceManager()
            device = TextConverter(rsrcmgr,retstr, codec='ascii' , laparams = LAParams())
            interpreter = PDFPageInterpreter(rsrcmgr, device)
            for page in PDFPage.create_pages(document):
                interpreter.process_page(page)
            return retstr.getvalue()
        else:
            print(pdfFilenamePath,"Warning: could not extract text from pdf file.")
            return ''
    
    if __name__ == '__main__':
        words = getPDFText(path)
    

    【讨论】:

    • 当它说pdf不可读时该怎么办?
    【解决方案5】:

    这是一个适用于运行 python 3.6 的 pdfminer.six 的答案。如果您只想从简单的 PDF 文件中提取原始文本,它使用 pdfminer.high_level 模块抽象出许多底层细节。

    import pdfminer
    import io
    
    def extract_raw_text(pdf_filename):
        output = io.StringIO()
        laparams = pdfminer.layout.LAParams() # Using the defaults seems to work fine
    
        with open(pdf_filename, "rb") as pdffile:
            pdfminer.high_level.extract_text_to_fp(pdffile, output, laparams=laparams)
    
        return output.getvalue()
    

    【讨论】:

      【解决方案6】:

      以下代码 sn-ps 能够使用最新版本的 pdfminer(截至 2016 年 3 月 23 日)从 pdf 文档中提取纯文本。希望这会有所帮助。

      from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
      from pdfminer.converter import TextConverter
      from pdfminer.layout import LAParams
      from pdfminer.pdfpage import PDFPage
      from cStringIO 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 = file(path, 'rb')
      
          parser = PDFParser(fp)
          doc = PDFDocument(parser)
          parser.set_document(doc)
      
          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()
          print text
          return text
      
      convert_pdf_to_txt(<path_of_the_pdf_file>)
      

      【讨论】:

        【解决方案7】:

        以防万一还有人需要这个, 让它与请求和python 3.4一起工作。 感谢@bahmait 在上面的回答:)

        import requests
        
        from io import StringIO
        from pdfminer.pdfinterp import PDFResourceManager, process_pdf
        from pdfminer.converter import TextConverter
        from pdfminer.layout import LAParams
        
        
        def pdf_to_text(url=None):
            text = None
            pdf = requests.get(url)
        
            if pdf.ok:
                fp = StringIO(str(pdf.content, 'utf-8'))
                outfp = StringIO()
        
                rsrcmgr = PDFResourceManager()
                device = TextConverter(rsrcmgr, outfp, laparams=LAParams())
                process_pdf(rsrcmgr, device, fp)
                device.close()
        
                text = outfp.getvalue()
                outfp.close()
                fp.close()
            return text
        
        
        if __name__ == "__main__":
            hello_world_text = pdf_to_text("https://bytebucket.org/hsoft/pdfminer3k/raw/28edfc91caed830674ca0b928f42571f7dee6091/samples/simple1.pdf")
            no_pdf = pdf_to_text('http://www.google.com/404')
            print(hello_world_text)
            print(no_pdf)
        

        【讨论】:

        • 你试过这个人吗? [链接]pypi.python.org/pypi/pdfminer3k ... 看起来不再支持它,但它给了我一个很好的起点。最后,我使用他们的 pdf2txt 模块混合了 pypdf2 中的一些方法用于我的特定用例。
        【解决方案8】:

        这是我最终制作的对我有用的清理版本。以下只是简单地返回 PDF 中的字符串,给定它的文件名。我希望这可以节省一些时间。

        from pdfminer.pdfinterp import PDFResourceManager, process_pdf
        from pdfminer.converter import TextConverter
        from pdfminer.layout import LAParams
        from cStringIO import StringIO
        
        def convert_pdf(path):
        
            rsrcmgr = PDFResourceManager()
            retstr = StringIO()
            codec = 'utf-8'
            laparams = LAParams()
            device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
        
            fp = file(path, 'rb')
            process_pdf(rsrcmgr, device, fp)
            fp.close()
            device.close()
        
            str = retstr.getvalue()
            retstr.close()
            return str
        

        此解决方案在API changes in November 2013 之前有效。

        【讨论】:

        • 仅供参考,这不再适用于当前版本的 pdfminer - 我收到“ImportError: cannot import name process_pdf”
        • 这里是一个可行的解决方案:stackoverflow.com/questions/26494211/…(截至 2015 年 11 月中旬)
        • process_pdf 仅被 PDFPageInterpreter 取代
        • StringIO 也没有了,你可以改用“from io import StringIO”
        【解决方案9】:

        仅当有人仍然需要它时:如何使用 PDFMiner 从 PDF 打印 HTML:

        import sys
        import getopt
        from Core.Interfaces.IReader import IReader
        from pdfminer.pdfparser import PDFDocument, PDFParser
        from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
        from pdfminer.pdfdevice import PDFDevice, TagExtractor
        from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
        from pdfminer.cmapdb import CMapDB
        from pdfminer.layout import LAParams
        from cStringIO import StringIO
        
        class PdfReader(object):
        def __init__(self):
            pass
        
        def readText(self,path, outtype='text', opts={}):
            outfile = path[:-3] + outtype
            outdir = '/'.join(path.split('/')[:-1])
            # debug option
            debug = 0
            # input option
            password = ''
            pagenos = set()
            maxpages = 0
            # output option
            # ?outfile = None
            # ?outtype = None
            outdir = None
            #layoutmode = 'normal'
            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 == '-V': laparams.detect_vertical = True
                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 == '-F': laparams.boxes_flow = float(v)
                elif k == '-Y': layoutmode = v
                elif k == '-O': outdir = v
                elif k == '-t': outtype = v
                elif k == '-c': codec = v
                elif k == '-s': scale = float(v)
        
            print laparams
            #
            #PDFDocument.debug = debug
            #PDFParser.debug = debug
            CMapDB.debug = debug
            PDFResourceManager.debug = debug
            PDFPageInterpreter.debug = debug
            PDFDevice.debug = debug
            #
            rsrcmgr = PDFResourceManager()
        
            #outtype = 'text'
        
            outfp = StringIO()
        
            device = HTMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
        
        
            fp = file(path, 'rb')
            process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password,
                            check_extractable=True)
            fp.close()
            device.close()
            print outfp.getvalue()
            outfp.close()
        
            return
        
        
        
        reader = PdfReader()
        opt = map(None,['-W','-L','-t'],[0.5,0.4,'html'])
        reader.readText("/test_data/test.pdf","html",opt)
        

        【讨论】:

          【解决方案10】:

          以下代码适用于我最新版本的 PDFMiner,它采用 pdf 的路径并以 .txt 格式返回文本。

          P.S:这是对上述答案的修改。

          from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
          from pdfminer.converter import TextConverter
          from pdfminer.layout import LAParams
          from pdfminer.pdfpage import PDFPage
          from cStringIO import StringIO
          
          def convert_pdf_to_txt(path, outtype='txt'):
              outfile = path[:-3] + outtype
              rsrcmgr = PDFResourceManager()
              codec = 'utf-8'
              laparams = LAParams()
              if outfile:
                  outfp = file(outfile, 'w')
              else:
                  outfp = sys.stdout
              device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
              fp = file(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()
              outfp.close()
              return
          

          【讨论】:

            【解决方案11】:

            以下对 non-process_pdf 答案的修改直接从 URL 字符串名称中提取文本,并适用于版本 20140328 和 Python 2.7:

            from urllib2 import urlopen
            from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
            from pdfminer.converter import TextConverter
            from pdfminer.layout import LAParams
            from pdfminer.pdfpage import PDFPage
            from cStringIO import StringIO
            def convert_pdf_to_txt(url):
                rsrcmgr = PDFResourceManager()
                retstr = StringIO()
                codec = 'utf-8'
                laparams = LAParams()
                device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
            
                scrape = urlopen(url).read()
                fp = StringIO(scrape)
            
                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()
                textstr = retstr.getvalue()
                retstr.close()
                return textstr
            

            【讨论】:

              【解决方案12】:

              这是一个适用于最新版本的新解决方案:

              from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
              from pdfminer.converter import TextConverter
              from pdfminer.layout import LAParams
              from pdfminer.pdfpage import PDFPage
              from cStringIO 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 = file(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()
                  str = retstr.getvalue()
                  retstr.close()
                  return str
              

              【讨论】:

              • 太棒了!最后是一个不使用process_pdf 的正在运行的解决方案:) 我用official git repository 中的simple1.pdf 尝试了这一点
              • 这适用于版本pdfminer 20131113。谢谢。
              • @czw。您如何将其与内置选项一起使用?有没有办法指定要转换的页码?
              • 如果你想获得 html 输出,只需将 HTMLConverter 添加到导入和函数中,而不是 TextConverter 放入 HTMLConverter。就这么简单。
              • 只需稍作修改即可:不要使用 str 作为变量名。 str 是一个 python 函数。
              【解决方案13】:

              如果你正在通过 urllib2 处理抓取的数据,试试这个(开发和解释 here):

              def pdf_to_text(scraped_pdf_data): 
                  from pdfminer.pdfinterp import PDFResourceManager, process_pdf 
                  from pdfminer.pdfdevice import PDFDevice 
                  from pdfminer.converter import TextConverter 
                  from pdfminer.layout import LAParams 
              
                  import StringIO 
                  fp = StringIO.StringIO() 
                  fp.write(scraped_pdf_data) 
                  fp.seek(0) 
                  outfp = StringIO.StringIO() 
              
                  rsrcmgr = PDFResourceManager() 
                  device = TextConverter(rsrcmgr, outfp, laparams=LAParams()) 
                  process_pdf(rsrcmgr, device, fp) 
                  device.close() 
              
                  t = outfp.getvalue() 
                  outfp.close() 
                  fp.close() 
                  return t
              

              与其他答案一样,此处的代码适应了 PDFMiner 本身提供的 pdf2txt 实用程序。因此,您也可以转换为 html 或 xml —— 只需将HTMLConverterXMLConverter 转换为上面的TextConverter

              【讨论】:

                【解决方案14】:

                这是我最终制作的对我有用的清理版本。以下只是简单地返回 PDF 中的字符串,给定它的文件名。我希望这可以节省一些时间。

                from pdfminer.pdfinterp import PDFResourceManager, process_pdf
                from pdfminer.converter import TextConverter
                from pdfminer.layout import LAParams
                from cStringIO import StringIO
                
                def convert_pdf(path):
                
                    rsrcmgr = PDFResourceManager()
                    retstr = StringIO()
                    codec = 'utf-8'
                    laparams = LAParams()
                    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
                
                    fp = file(path, 'rb')
                    process_pdf(rsrcmgr, device, fp)
                    fp.close()
                    device.close()
                
                    str = retstr.getvalue()
                    retstr.close()
                    return str
                

                谁能告诉我:有没有特定的地方放置pdf文件??

                【讨论】:

                  【解决方案15】:

                  我知道回答你自己的问题很糟糕,但我想我可能已经想通了,我不希望其他人浪费时间寻找解决我问题的方法。

                  我遵循了我的问题中发布的链接之一中的建议,并重新利用了 pdfminer 中包含的当前 pdf2txt.py 脚本。这是功能,以防它对其他人有用。感谢用户 skyl 发布了这个答案,我所要做的就是进行一些更改以使其与当前版本的 pdfminer 一起工作。

                  这个函数获取一个pdf并在同一个目录中创建一个同名的.txt文件。

                  def convert_pdf(path, outtype='txt', opts={}):
                  import sys
                  from pdfminer.pdfparser import PDFDocument, PDFParser
                  from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
                  from pdfminer.pdfdevice import PDFDevice, TagExtractor
                  from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
                  from pdfminer.cmapdb import CMapDB
                  from pdfminer.layout import LAParams
                  import getopt
                  
                  outfile = path[:-3] + outtype
                  outdir = '/'.join(path.split('/')[:-1])
                  
                  # debug option
                  debug = 0
                  # input option
                  password = ''
                  pagenos = set()
                  maxpages = 0
                  # output option
                  # ?outfile = None
                  # ?outtype = None
                  outdir = None
                  #layoutmode = 'normal'
                  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 == '-V': laparams.detect_vertical = True
                      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 == '-F': laparams.boxes_flow = float(v)
                      elif k == '-Y': layoutmode = v
                      elif k == '-O': outdir = v
                      elif k == '-t': outtype = v
                      elif k == '-c': codec = v
                      elif k == '-s': scale = float(v)
                  #
                  #PDFDocument.debug = debug
                  #PDFParser.debug = debug
                  CMapDB.debug = debug
                  PDFResourceManager.debug = debug
                  PDFPageInterpreter.debug = debug
                  PDFDevice.debug = debug
                  #
                  rsrcmgr = PDFResourceManager()
                  
                  outtype = 'text'
                  
                  if outfile:
                      outfp = file(outfile, 'w')
                  else:
                      outfp = sys.stdout
                  device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
                  
                  
                  fp = file(path, 'rb')
                  process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password,
                                  check_extractable=True)
                  fp.close()
                  device.close()
                  outfp.close()
                  return
                  

                  【讨论】:

                  • 自己的问题可以自己回答,不用担心。
                  • 我还重新调整了该代码的用途。它可能会更苗条
                  • 由于您提到的原因,回答您自己的问题非常可取
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-11-14
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-11-22
                  • 2020-01-29
                  • 1970-01-01
                  相关资源
                  最近更新 更多