PDF 文件处理

参加高阶培训的时候讲过 pdf 数据内容的获取,当时使用的是 pdfplumber 这个第三方库。

PDF 文件处理

不过在那之前我一直使用的是 pymupdf 这个库进行 pdf 文件的处理。官方文档看得很心烦,索性写了一些代码将其封装,现在分享给大家。

# -*- coding: utf-8 -*-
"""
@author: yanglei
对pdf进行操作
需要先安装pymupdf库
安装方法为pip insatll --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple PyMuPDF
"""
try:
    import fitz
except:
    print(__file__, "needs PyMuPDF (fitz).")
    raise SystemExit

def convert_obj_to_pdf(obj_path, pdf_path):
    '''
        功能:将文件(XPS, EPUB, CBZ,图片等)转为pdf
        参数:文件路径,pdf存放路径
    '''
    if not (list(map(int, fitz.VersionBind.split('.'))) >= [1, 13, 3]):
        raise SystemExit('insufficient PyMuPDF version')
    doc = fitz.open(obj_path)
    if doc.isPDF:
        raise SystemExit('document is PDF already')
    print('Converting {} to pdf'.format(obj_path))
    b = doc.convertToPDF()  # convert to pdf
    pdf = fitz.open("pdf", b)  # open as pdf
    toc = doc.getToC()  # 获取书签
    pdf.setToC(toc)  # 设置输出的书签
    meta = doc.metadata  # 获取详细信息
    # if not meta.get('producer'):
        # meta['producer'] = 'PyMuPDF v' + fitz.VersionBind
    # if not meta.get('creater'):
        # meta['creater'] = "PyMuPDF PDF converter"
    pdf.setMetadata(meta)
    # 设置超链接
    link_cnti = 0
    link_skip = 0
    for pinput in doc:
        links = pinput.getLinks()
        link_cnti += len(links)
        pout = pdf[pinput.number]
        for l in links:
            if l['kind'] == fitz.LINK_NAMED:
                link_skip += 1
                continue
            pout.insertLink(l)
    pdf.save(pdf_path + '.pdf', garbage=4, deflate=True)
    print("Skipped %i named links of a total of %i in input." % (link_skip, link_cnti))
    return True

class Pdf(object):
    
    def __init__(self, path):
        self.pdf_path = path
        
    def get_doc_pagecount(self):
        '''
            功能:获取pdf文档的页数
            返回值:pdf文档的页数
            返回值类型:int
        '''
        doc = fitz.open(self.pdf_path)
        return doc.pageCount
        
    def get_doc_metadata(self):
        '''
            功能:获取pdf文档的详细信息,包括创建日期、修改日期、创建者等等
            返回值:pdf文档的详细信息
            返回值类型:dict
        '''
        doc = fitz.open(self.pdf_path)
        return doc.metadata
    
    def get_doc_bookmarks(self):
        '''
            功能:获取pdf文档的书签信息
            返回值:pdf文档的书签信息
            返回值类型:list
        '''
        doc = fitz.open(self.pdf_path)
        if doc.getToC():
            return doc.getToC()
        else:
            return None
        
    def get_page_links(self, pagenum=0):
        '''
            功能:获取pdf文档某个页面的超链接
            参数:页码
            参数类型:int
            返回值:pdf文档某个页面的超链接信息
            返回值类型:list
        '''
        doc = fitz.open(self.pdf_path)
        if pagenum > self.get_doc_pagecount() - 1:
            return 'Invalid page number,please try again!'
        else:
            page = doc[pagenum]
            links = page.getLinks()
            if links:
                return links
            else:
                return None
    
    def page_to_img(self, pagenum=0, img_path='yanglei.png', zoom=3, rotate=0):  # zoom为放大倍数,rotate为旋转角度
        '''
            功能:将pdf文档某个页面转换为图片
            参数:页码,图片存储路径,放大倍数,旋转角度
            返回值:True代表图片已经生成
            返回值类型:bool
        '''
        doc = fitz.open(self.pdf_path)
        if pagenum > self.get_doc_pagecount() - 1:
            return 'Invalid page number,please try again!'
        else:
            page = doc[pagenum]
            zoom = zoom
            rotate = rotate
            trans = fitz.Matrix(zoom, zoom).preRotate(rotate)
            pix = page.getPixmap(matrix=trans, alpha=False)
            pix.writePNG(img_path)
            return True
        
    def get_page_text(self, pagenum=0, type='text'):
        '''
            功能:将pdf文档某个页面转换为文本
            参数:页码,获取数据的类型(可填写的类型有text/html/dict/rawdict/xhtml/xml)
            返回值:转换为文本之后的内容
            返回值类型:str
        '''
        doc = fitz.open(self.pdf_path)
        if pagenum > self.get_doc_pagecount() - 1:
            return 'Invalid page number,please try again!'
        else:
            page = doc[pagenum]
            text = page.getText(type)
            return text
            
    def search_page_for_text(self, pagenum=0, text='', hit_max=16):
        '''
            功能:搜索pdf文档某个页面中是否存在待搜索文本
            参数:页码,待搜索文本的内容,允许匹配的最多个数
            返回值:待搜索文本的位置信息
            返回值类型:list
        '''
        doc = fitz.open(self.pdf_path)
        if pagenum > self.get_doc_pagecount() - 1:
            return 'Invalid page number,please try again!'
        else:
            page = doc[pagenum]
            areas = page.searchFor(text, hit_max=hit_max)
            return areas
            
pdf = Pdf('I:/艺赛旗iS-RPA V7.0高阶培训.pdf')
pdf.page_to_img(50, r'C:\Users\yuryq\Desktop\1.png')

顺带一提,看代码的最后两行可以知道本文的图片就是用其中的代码生成的。
先挖个坑,代码还远不止这些,感兴趣的可以持续关注,之后有空还会更新。