PDF匹配文本精准标记红框算法(单个、多个、单行、多行)

复制代码
## pip install pdfminer.six
## pip install PyMuPDF

import fitz
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox, LTTextLine, LTChar


## pdf匹配文本标红框
def pdfMarkedBox(string, name, address="", mode=0, order=0, skew=0, line=0):
    """
    :param string:  匹配的字符串
    :param name:    标框的pdf文件命名或者放置地址
    :param address: 对应的pdf文件地址
    :param mode:    对应匹配模式 mode = 0 完全匹配 mode =1 包含匹配 mode = 2 PyMuPDF单行匹配
    :param order:   匹配到的文本取值位置,默认第一个
    :param skew:    偏移位置,用于飘忽不定的文本匹配不上,找到特定标识位置偏移匹配
    :param line:    读取多个用于一起标记
    :return:        无
    """
    ## 文本存储
    list_text = []
    ## 坐标存储
    list_box = []
    ## 页码存储
    list_number = []

    def parse_pdf(address):
        with open(address, 'rb') as fp:
            ## 准备工作
            parser = PDFParser(fp)
            doc = PDFDocument(parser)
            rsrcmgr = PDFResourceManager()
            laparams = LAParams()
            device = PDFPageAggregator(rsrcmgr, laparams=laparams)
            interpreter = PDFPageInterpreter(rsrcmgr, device)
            page_number = 0  # 初始化页码计数器
            ## 获取pdf页面数据
            for page in PDFPage.create_pages(doc):
                interpreter.process_page(page)
                layout = device.get_result()
                for element in layout:
                    if isinstance(element, LTTextBox) or isinstance(element, LTTextLine):
                        # print(f"Text: {element.get_text()}")
                        # print(f"Coordinates: {element.bbox}")
                        list_text.append(element.get_text())
                        list_box.append(element.bbox)
                        list_number.append(page_number)
                    # elif isinstance(element, LTChar):
                    #     # 单个字符遍历LTChar对象
                    #     print(f"Character: {element.get_text()}")
                    #     print(f"Coordinates: {element.bbox}")
                page_number += 1

    ## 匹配列表 进行匹配操作 获取index来定位
    list_index = []
    if mode == 0:
        parse_pdf(address)
        print(list_text)
        print(list_box)
        print(list_number)
        print("进行完全匹配")
        number_matches = 0
        for index, value in enumerate(list_text):
            if string == value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)
    elif mode == 1:
        parse_pdf(address)
        print(list_text)
        print(list_box)
        print(list_number)
        print("进行包含匹配")
        number_matches = 0
        for index, value in enumerate(list_text):
            if string in value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)
    elif mode == 2:
        ## PyMuPDF 单行匹配
        list_fitz_text = []
        doc = fitz.open(address)
        # 获取 PDF 文件中的总页数
        num_pages = doc.page_count
        # 逐页读取内容
        for page_num in range(num_pages):
            page = doc.load_page(page_num)  # 加载页面
            # 获取页面上的所有文本块
            blocks = page.get_text_blocks()
            print(f"Page {page_num + 1} Blocks:")
            for block in blocks:
                print(block)
                list_text.append(block[4])
                list_box.append((block[0], block[1], block[2], block[3]))
                list_number.append(page_num)
        number_matches = 0
        for index, value in enumerate(list_text):
            print(index, value)
            if string in value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)

    if list_index == []:
        print("没有匹配到对应的文本,请检查一下")
        return
    if line == 0:
        print("读取位置:", list_index[order] + skew)
        print("读取文本:", list_text[list_index[order] + skew])
        print("读取坐标:", list_box[list_index[order] + skew])
        print("读取页码:", list_number[list_index[order] + skew])
    else:
        print("读取位置:", list_index[order] + skew, list_index[order] + skew + line)
        print("读取文本:", list_text[list_index[order] + skew: list_index[order] + skew + line])
        print("读取坐标:", list_box[list_index[order] + skew: list_index[order] + skew + line])
        print("读取页码:", list_number[list_index[order] + skew: list_index[order] + skew + line])

    ## 绘制红色框框并保存
    def redBox(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    页码
        :param box:     坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = box  # (left, bottom, right, top)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list_rect[3] - list1[3] - n, list1[2] + n, list_rect[3] - list1[1] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list_rect[3] - list1[1] +1, list1[2] + 0.5, list_rect[3] - list1[1] +1.5)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 多个文本绘制红色框框并保存  需同一页
    def redBoxAll(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    单个页码
        :param box:     多个坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        ## 处理box多个坐标 取最大值
        left = []
        bottom = []
        right = []
        top = []

        for i in box:
            left.append(i[0])
            bottom.append(i[1])
            right.append(i[2])
            top.append(i[3])
        new_box = (min(left), min(bottom), max(right), max(top))
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = new_box  # (left, bottom, right, top)
        print(rect)
        list1 = []
        for i in rect:
            list1.append(i)

        n = 5
        new_rect = (list1[0] - n, list_rect[3] - list1[3] - n, list1[2] + n, list_rect[3] - list1[1] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list_rect[3] - list1[1] +1, list1[2] + 0.5, list_rect[3] - list1[1] +1.5)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 绘制红色框框并保存 PyMuPDF版本
    def redBoxMuPDF(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    页码
        :param box:     坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = box  # (left, bottom, right, top)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list1[1] - n, list1[2] + n, list1[3] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list1[3] +1.5, list1[2] + 0.5,list1[3] +2)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 多个文本绘制红色框框并保存  需同一页 PyMuPDF版本
    def redBoxAllMuPDF(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    单个页码
        :param box:     多个坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        ## 处理box多个坐标 取最大值
        left = []
        bottom = []
        right = []
        top = []

        for i in box:
            left.append(i[0])
            bottom.append(i[1])
            right.append(i[2])
            top.append(i[3])
        new_box = (min(left), min(bottom), max(right), max(top))
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = new_box  # (left, bottom, right, top)
        print(rect)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list1[1] - n, list1[2] + n, list1[3] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list1[3] +1.5, list1[2] + 0.5,list1[3] +2)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    if mode == 2 and line == 0:
        redBoxMuPDF(address, list_number[list_index[order] + skew], list_box[list_index[order] + skew], name)
        return
    elif mode == 2 and line != 0:
        redBoxAllMuPDF(address, list_number[list_index[order] + skew],
                       list_box[list_index[order] + skew: list_index[order] + skew + line], name)
        return

    if line == 0:
        redBox(address, list_number[list_index[order] + skew], list_box[list_index[order] + skew], name)
        return
    else:
        redBoxAll(address, list_number[list_index[order] + skew],
                  list_box[list_index[order] + skew: list_index[order] + skew + line], name)
        return
python 复制代码
## pip install pdfminer.six
## pip install PyMuPDF

import fitz
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox, LTTextLine, LTChar


## pdf匹配文本标红框
def pdfMarkedBox(string, name, address="", mode=0, order=0, skew=0, line=0):
    """
    :param string:  匹配的字符串
    :param name:    标框的pdf文件命名或者放置地址
    :param address: 对应的pdf文件地址
    :param mode:    对应匹配模式 mode = 0 完全匹配 mode =1 包含匹配 mode = 2 PyMuPDF单行匹配
    :param order:   匹配到的文本取值位置,默认第一个
    :param skew:    偏移位置,用于飘忽不定的文本匹配不上,找到特定标识位置偏移匹配
    :param line:    读取多个用于一起标记
    :return:        无
    """
    ## 文本存储
    list_text = []
    ## 坐标存储
    list_box = []
    ## 页码存储
    list_number = []

    def parse_pdf(address):
        with open(address, 'rb') as fp:
            ## 准备工作
            parser = PDFParser(fp)
            doc = PDFDocument(parser)
            rsrcmgr = PDFResourceManager()
            laparams = LAParams()
            device = PDFPageAggregator(rsrcmgr, laparams=laparams)
            interpreter = PDFPageInterpreter(rsrcmgr, device)
            page_number = 0  # 初始化页码计数器
            ## 获取pdf页面数据
            for page in PDFPage.create_pages(doc):
                interpreter.process_page(page)
                layout = device.get_result()
                for element in layout:
                    if isinstance(element, LTTextBox) or isinstance(element, LTTextLine):
                        # print(f"Text: {element.get_text()}")
                        # print(f"Coordinates: {element.bbox}")
                        list_text.append(element.get_text())
                        list_box.append(element.bbox)
                        list_number.append(page_number)
                    # elif isinstance(element, LTChar):
                    #     # 单个字符遍历LTChar对象
                    #     print(f"Character: {element.get_text()}")
                    #     print(f"Coordinates: {element.bbox}")
                page_number += 1

    ## 匹配列表 进行匹配操作 获取index来定位
    list_index = []
    if mode == 0:
        parse_pdf(address)
        print(list_text)
        print(list_box)
        print(list_number)
        print("进行完全匹配")
        number_matches = 0
        for index, value in enumerate(list_text):
            if string == value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)
    elif mode == 1:
        parse_pdf(address)
        print(list_text)
        print(list_box)
        print(list_number)
        print("进行包含匹配")
        number_matches = 0
        for index, value in enumerate(list_text):
            if string in value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)
    elif mode == 2:
        ## PyMuPDF 单行匹配
        list_fitz_text = []
        doc = fitz.open(address)
        # 获取 PDF 文件中的总页数
        num_pages = doc.page_count
        # 逐页读取内容
        for page_num in range(num_pages):
            page = doc.load_page(page_num)  # 加载页面
            # 获取页面上的所有文本块
            blocks = page.get_text_blocks()
            print(f"Page {page_num + 1} Blocks:")
            for block in blocks:
                print(block)
                list_text.append(block[4])
                list_box.append((block[0], block[1], block[2], block[3]))
                list_number.append(page_num)
        number_matches = 0
        for index, value in enumerate(list_text):
            print(index, value)
            if string in value.replace("\n", ""):
                list_index.append(index)
                number_matches += 1
        print("匹配数量为:", number_matches)

    if list_index == []:
        print("没有匹配到对应的文本,请检查一下")
        return
    if line == 0:
        print("读取位置:", list_index[order] + skew)
        print("读取文本:", list_text[list_index[order] + skew])
        print("读取坐标:", list_box[list_index[order] + skew])
        print("读取页码:", list_number[list_index[order] + skew])
    else:
        print("读取位置:", list_index[order] + skew, list_index[order] + skew + line)
        print("读取文本:", list_text[list_index[order] + skew: list_index[order] + skew + line])
        print("读取坐标:", list_box[list_index[order] + skew: list_index[order] + skew + line])
        print("读取页码:", list_number[list_index[order] + skew: list_index[order] + skew + line])

    ## 绘制红色框框并保存
    def redBox(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    页码
        :param box:     坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = box  # (left, bottom, right, top)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list_rect[3] - list1[3] - n, list1[2] + n, list_rect[3] - list1[1] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list_rect[3] - list1[1] +1, list1[2] + 0.5, list_rect[3] - list1[1] +1.5)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 多个文本绘制红色框框并保存  需同一页
    def redBoxAll(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    单个页码
        :param box:     多个坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        ## 处理box多个坐标 取最大值
        left = []
        bottom = []
        right = []
        top = []

        for i in box:
            left.append(i[0])
            bottom.append(i[1])
            right.append(i[2])
            top.append(i[3])
        new_box = (min(left), min(bottom), max(right), max(top))
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = new_box  # (left, bottom, right, top)
        print(rect)
        list1 = []
        for i in rect:
            list1.append(i)

        n = 5
        new_rect = (list1[0] - n, list_rect[3] - list1[3] - n, list1[2] + n, list_rect[3] - list1[1] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list_rect[3] - list1[1] +1, list1[2] + 0.5, list_rect[3] - list1[1] +1.5)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 绘制红色框框并保存 PyMuPDF版本
    def redBoxMuPDF(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    页码
        :param box:     坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = box  # (left, bottom, right, top)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list1[1] - n, list1[2] + n, list1[3] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list1[3] +1.5, list1[2] + 0.5,list1[3] +2)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    ## 多个文本绘制红色框框并保存  需同一页 PyMuPDF版本
    def redBoxAllMuPDF(address, page, box, name):
        """
        :param address:  pdf文件地址
        :param page:    单个页码
        :param box:     多个坐标的位置
        :param name:    标框的pdf文件命名或者放置地址
        :return:        无
        """
        ##PyMuPDF进行处理
        doc = fitz.open(address)
        # 选择要添加注释的页面
        page = doc.load_page(page)  # 0 表示第一页
        # 获取页面大小来做处理
        page_rect = page.rect
        list_rect = list(page_rect)
        ## 处理box多个坐标 取最大值
        left = []
        bottom = []
        right = []
        top = []

        for i in box:
            left.append(i[0])
            bottom.append(i[1])
            right.append(i[2])
            top.append(i[3])
        new_box = (min(left), min(bottom), max(right), max(top))
        # 定义矩形注释的位置和大小(左下角和右上角的坐标)
        rect = new_box  # (left, bottom, right, top)
        print(rect)
        list1 = []
        for i in rect:
            list1.append(i)
        n = 5
        new_rect = (list1[0] - n, list1[1] - n, list1[2] + n, list1[3] + n)

        ## 变化为下划线
        # new_rect = (list1[0] - 0.5, list1[3] +1.5, list1[2] + 0.5,list1[3] +2)

        # 添加矩形注释到页面
        annot = page.add_rect_annot(new_rect)
        # 保存 PDF 文件
        doc.save(name)
        # 关闭 PDF 文件
        doc.close()
        print("文件完成标红框:", name)

    if mode == 2 and line == 0:
        redBoxMuPDF(address, list_number[list_index[order] + skew], list_box[list_index[order] + skew], name)
        return
    elif mode == 2 and line != 0:
        redBoxAllMuPDF(address, list_number[list_index[order] + skew],
                       list_box[list_index[order] + skew: list_index[order] + skew + line], name)
        return

    if line == 0:
        redBox(address, list_number[list_index[order] + skew], list_box[list_index[order] + skew], name)
        return
    else:
        redBoxAll(address, list_number[list_index[order] + skew],
                  list_box[list_index[order] + skew: list_index[order] + skew + line], name)
        return
相关推荐
子夜江寒2 小时前
基于 OpenCV 的图像形态学与边缘检测
python·opencv·计算机视觉
SmartRadio8 小时前
CH585M+MK8000、DW1000 (UWB)+W25Q16的低功耗室内定位设计
c语言·开发语言·uwb
rfidunion8 小时前
QT5.7.0编译移植
开发语言·qt
少林码僧8 小时前
2.31 机器学习神器项目实战:如何在真实项目中应用XGBoost等算法
人工智能·python·算法·机器学习·ai·数据挖掘
rit84324998 小时前
MATLAB对组合巴克码抗干扰仿真的实现方案
开发语言·matlab
智航GIS8 小时前
10.4 Selenium:Web 自动化测试框架
前端·python·selenium·测试工具
jarreyer8 小时前
摄像头相关记录
python
宝贝儿好8 小时前
【强化学习】第六章:无模型控制:在轨MC控制、在轨时序差分学习(Sarsa)、离轨学习(Q-learning)
人工智能·python·深度学习·学习·机器学习·机器人
大、男人8 小时前
python之asynccontextmanager学习
开发语言·python·学习
hqwest8 小时前
码上通QT实战08--导航按钮切换界面
开发语言·qt·slot·信号与槽·connect·signals·emit