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
相关推荐
智能体与具身智能5 小时前
TVA具身智能的概念、架构与应用(19)
人工智能·python·具身智能
小灰灰搞电子5 小时前
Rust+Slint 实现动态消息提示框源码分享
开发语言·后端·rust
2601_962294616 小时前
python中range函数怎么用
python·for循环·可迭代对象·range函数·整数列表
weixin_469273816 小时前
如何在线把文字转为 pdf 文档
pdf
传奇开心果编程7 小时前
【Rust入门知识点学与练】第21课:Trait 进阶 Advanced Traits
开发语言·学习·rust
2601_963906787 小时前
离线截图 OCR 识别:支持表格与 PDF 解析
pdf·ocr·软件需求
青 春 记 忆7 小时前
零基础入门python70:Docker Compose 编排完整后端
python·后端开发
新时代牛马7 小时前
字符设备驱动完整篇:从 cdev_add、file_operations 到chrdev_open 与排障
开发语言·python
swordbob7 小时前
ReentrantLock 与 AQS 完整学习手册
java·开发语言
白山编程大哥8 小时前
Java OutputStreamWriter 详解:从字符到字节的桥梁
java·开发语言·python