安装

# pip install pdfminer
pip install pdfminer3k
pip install pdfminer.six 安装这个引入的内容不会报错

若安装不成功,可以试试下面方法

首先下载pdfminer3k:https://pypi.python.org/pypi/pdfminer3k;然后安装pdfminer,将下载好的pdfminer3k解压到D:或其他合适的盘符,通过win+r 打开运行窗口,输入cmd;输入D:切换到D盘,cd pdfminer3k(pdf解压的文件夹),输入setup.py install安装软件。

解析pdf文件用到的类

PDFParser:从一个文件中获取数据
PDFDocument:保存获取的数据,和PDFParser是相互关联的
PDFPageInterpreter处理页面内容
PDFDevice将其翻译成你需要的格式
PDFResourceManager用于存储共享资源,如字体或图像。

PDF转Word功能所需的依赖包如下:

  • PDFParser(文档分析器)
  • PDFDocument(文档对象)
  • PDFResourceManager(资源管理器)
  • PDFPageInterpreter(解释器)
  • PDFPageAggregator(聚合器)
  • LAParams(参数分析器)

整体思路

构造文档对象,解析文档对象,提取所需内容

Python 读取解析pdf python读取pdf文字_python

构造文档对象

Python 读取解析pdf python读取pdf文字_缓存_02

PDFMiner的类之间的关系图:

Python 读取解析pdf python读取pdf文字_python_03

Layout布局分析返回的PDF文档中的每个页面LTPage对象。这个对象和页内包含的子对象,形成一个树结构。如图所示:

Python 读取解析pdf python读取pdf文字_Python 读取解析pdf_04

  • LTPage :表示整个页。可能会含有LTTextBox,LTFigure,LTImage,LTRect,LTCurve和LTLine子对象。
  • LTTextBox:表示一组文本块可能包含在一个矩形区域。注意此box是由几何分析中创建,并且不一定表示该文本的一个逻辑边界。它包含LTTextLine对象的列表。使用 get_text()方法返回文本内容。
  • LTTextLine :包含表示单个文本行LTChar对象的列表。字符对齐要么水平或垂直,取决于文本的写入模式。使用get_text()方法返回文本内容。
  • LTAnno:在文本中字母实际上被表示为Unicode字符串。需要注意的是,虽然一个LTChar对象具有实际边界,LTAnno对象没有,因为这些是“虚拟”的字符,根据两个字符间的关系(例如,一个空格)由布局分析后插入。
  • LTImage:表示一个图像对象。嵌入式图像可以是JPEG或其它格式,但是目前PDFMiner没有放置太多精力在图形对象。
  • LTLine:代表一条直线。可用于分离文本或附图。
  • LTRect:表示矩形。可用于框架的另一图片或数字。
  • LTCurve:表示一个通用的Bezier曲线

代码实操

  • 方法1
# -*- coding:utf-8 -*-
import time,os.path,requests,re
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams,LTTextBoxHorizontal,LTImage,LTCurve,LTFigure
from pdfminer.pdfpage import PDFTextExtractionNotAllowed,PDFPage
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from docx import Document

document = Document()

'''
pip install pdfminer3k
pip install pdfminer.six 安装这个引入的内容不会报错
'''

class CPdf2TxtManager():

    def changePdfToText(self, filePath):
        # 以二进制读模式打开
        file = open(path, 'rb')
        #用文件对象来创建一个pdf文档分析器
        praser = PDFParser(file)
        # 创建一个PDF文档对象存储文档结构,提供密码初始化,没有就不用传该参数
        doc = PDFDocument(praser, password='')
        ##检查文件是否允许文本提取
        if not doc.is_extractable:
            raise PDFTextExtractionNotAllowed

        # 创建PDf 资源管理器 来管理共享资源,#caching = False不缓存
        rsrcmgr = PDFResourceManager(caching = False)
        # 创建一个PDF设备对象
        laparams = LAParams()
        # 创建一个PDF页面聚合对象
        device = PDFPageAggregator(rsrcmgr, laparams=laparams)
        # 创建一个PDF解析器对象
        interpreter = PDFPageInterpreter(rsrcmgr, device)
        # 获得文档的目录(纲要),文档没有纲要会报错
        #PDF文档没有目录时会报:raise PDFNoOutlines  pdfminer.pdfdocument.PDFNoOutlines
        # print(doc.get_outlines())

        # 获取page列表
        print(PDFPage.get_pages(doc))
        # 用来计数页面,图片,曲线,figure,水平文本框等对象的数量
        num_page, num_image, num_curve, num_figure, num_TextBoxHorizontal = 0, 0, 0, 0, 0
        # 循环遍历列表,每次处理一个page的内容
        for page in PDFPage.create_pages(doc):
            num_page += 1  # 页面增一
            # 利用解释器的process_page()方法解析读取单独页数
            interpreter.process_page(page)
            # 接受该页面的LTPage对象
            layout = device.get_result()
            fileNames = os.path.splitext(filePath)
            # 这里layout是一个LTPage对象 里面存放着 这个page解析出的各种对象
            # 一般包括LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等等
            for x in layout:
                if hasattr(x, "get_text") or isinstance(x, LTTextBoxHorizontal):
                    with open(fileNames[0] + '.txt','a+') as f:
                        # 将'\xa0'替换成u' '空格,这个\xa0就是&nbps空格
                        results = x.get_text().replace(u'\xa0', u' ')
                        f.write(results + '\n')
                    document.add_paragraph(
                        results, style='ListBullet'  # 添加段落,样式为unordered list类型
                    )
                document.save('./data/demo1.docx')  # 保存这个文档

                # 如果x是水平文本对象的话
                if isinstance(x, LTTextBoxHorizontal):
                    num_TextBoxHorizontal += 1  # 水平文本框对象增一
                if isinstance(x, LTImage):  # 图片对象
                    num_image += 1
                if isinstance(x, LTCurve):  # 曲线对象
                    num_curve += 1
                if isinstance(x, LTFigure):  # figure对象
                    num_figure += 1

        print('对象数量:%s,页面数:%s,图片数:%s,曲线数:%s,'
              '水平文本框:%s,'%(num_figure,num_page,num_image,num_curve,num_TextBoxHorizontal))


if __name__ == '__main__':
    path = './data/13.pdf'
    pdf2TxtManager = CPdf2TxtManager()
    pdf2TxtManager.changePdfToText(path)
    print('ok,解析pdf结束!')
  • 方法2
# -*- coding: utf-8 -*-
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
import requests,os,re
try:#python3
    from io import StringIO
    from urllib.request import urlopen
except:#python2
    from urllib import urlopen
    from cStringIO import StringIO

'''
pip install pdfminer3k
pip install pdfminer.six 安装这个引入的内容不会报错
'''

def convert_pdf_to_txt(path,save_name):
    if debug:
        # 加载内存的方式
        retstr = StringIO()
        fp = StringIO(path)
    else:
        #读取文件的方式
        retstr = open(path, 'rb')
        fp = open(path, 'rb')
    # 创建一个PDF资源管理器对象来存储共享资源,caching = False不缓存
    rsrcmgr = PDFResourceManager(caching=False)
    # 创建一个PDF设备对象
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec='utf-8', laparams=laparams)
    # 创建一个PDF解析器对象
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.get_pages(fp, pagenos=set(), maxpages=0, password='',caching=True, check_extractable=True):
        interpreter.process_page(page)
    fp.close()#关闭输入流
    device.close()#关闭输出流
    str = retstr.getvalue()
    retstr.close()
    with open("%s"%save_name,"w") as f:
        for i in str:
            f.write(i)
    print("%s Writing Succeed!"%save_name)


if __name__ == '__main__':
    try:
        debug=False # True
        if debug:
            #这种方式暂时还有问题
            url="http://pythonscraping.com/pages/warandpeace/chapter1.pdf"
            pdf_file = urlopen(url).read()  # 也可以换成本地pdf文件,用open rb模式打开
            # pdf_file = requests.get(url).content
            # 加载内存的方式
            convert_pdf_to_txt(pdf_file, "./data/12.txt")
        else:
            #读取文件的方式
            convert_pdf_to_txt('./data/12.pdf',"./data/12.txt")
    except Exception as e:
        import traceback
        ex_msg = '{exception}'.format(exception=traceback.format_exc())
        print(ex_msg)
  • 批量提取
# -*- coding:utf-8 -*-
import os,re
from pdfminer.pdfinterp import PDFResourceManager,PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

'''
pip install pdfminer3k
pip install pdfminer.six 安装这个引入的内容不会报错
'''

#将一个pdf转换成txt
def pdfTotxt(filepath,outpath):
    try:
        fp = open(filepath, 'rb')
        outfp=open(outpath,'w')
        #创建一个PDF资源管理器对象来存储共享资源,caching = False不缓存
        rsrcmgr = PDFResourceManager(caching = False)
        # 创建一个PDF设备对象
        laparams = LAParams()
        device = TextConverter(rsrcmgr, outfp, codec='utf-8', laparams=laparams,imagewriter=None)
        #创建一个PDF解析器对象
        interpreter = PDFPageInterpreter(rsrcmgr, device)
        for page in PDFPage.get_pages(fp, pagenos = set(),maxpages=0,
                                      password='',caching=False, check_extractable=True):
            page.rotate = page.rotate % 360
            interpreter.process_page(page)
        #关闭输入流
        fp.close()
        #关闭输出流
        device.close()
        outfp.flush()
        outfp.close()
    except Exception as e:
         print("Exception:%s",e)

#一个文件夹下的所有pdf文档转换成txt
def fileTotxt(fileDir):
    files=os.listdir(fileDir)
    tarDir=fileDir+'txt'
    if not os.path.exists(tarDir):
        os.mkdir(tarDir)
    replace=re.compile(r'\.pdf',re.I)
    for file in files:
        filePath=fileDir+'\\'+file
        outPath=tarDir+'\\'+re.sub(replace,'',file)+'.txt'
        pdfTotxt(filePath,outPath)
        print("Saved "+outPath)


if __name__ == '__main__':
    pdfTotxt('000.pdf', 'test.txt')
    fileTotxt('这里是目录的路径')

使用pdfminer3K出现WARNING:root:UniGB-UCS2-H问题

问题原因:缺少字体库

解决:

从github下载对应字体库放入,python 库文件 \Lib\site-packages\pdfminer\cmap中。
下载地址:https://github.com/euske/pdfminer/tree/2103e5875ef04cfaf424b25d2fd0dc9535a90714/pdfminer/cmap

Python 读取解析pdf python读取pdf文字_Python 读取解析pdf_05

再次运行,可能会仍然报错

Python 读取解析pdf python读取pdf文字_Python 读取解析pdf_06

从相同下载地址 下载对应的解码文件,放到相同位置,再运行就ok了。