Python:自动化处理PDF文档集合,提取文献标题

目录页的生成考虑了标题的长度,对过长的标题进行适当的分行处理,确保目录的整洁性。页码的添加在页面底部中央,通过绘制白色矩形覆盖原有页码区域后添加新的页码信息,以避免页码重叠。最终,所有页面(包括目录页和带有新页码的原始页面)被合并成一个PDF文件。

技术亮点

  • 文本提取与处理:通过PyMuPDFPyPDF2库提取PDF文件的文本和元数据,使用正则表达式和文本处理技术清洗和格式化标题。
  • 动态内容生成:使用reportlab库动态生成包含自定义文本(如页码和目录项)的PDF页面。
  • 文档合并与修改:利用PyPDF2库合并PDF页面,并在合并过程中添加自定义内容。

通过这个Python项目,我们可以自动化处理一系列复杂的PDF文档管理任务,包括提取标题、生成目录、添加页码和合并文件。这大大减轻了手动处理的负担,使得管理大量PDF文档变得既简单又高效。无论是学术研究者、图书管理员还是文档管理专业人士,都可以从这个项目中受益。

代码

步骤一:提取PDF标题(Step_two.ipynb)

### 第一步:读取pdf\_dir路径下所有.pdf为后缀的文件,打开CSV文件以写入文件名和标题
### 第二步:手动对CSV文件内错误标题进行修改


 # 读取路径下所有.pdf为后缀的文件
pdf_dir = '老师的论文集/'
 # 合并后的PDF名字
output_pdf_path = "合并后/老师的论文集.pdf"
 # 用于中间 存放文件名与标题的CSV文件
TitlesCSV = '合并后/老师的论文集.csv'```

import csv
import html
import os
import re  # 导入正则表达式模块

import fitz  # PyMuPDF
from PyPDF2 import PdfReader


def find\_non\_text\_chars(sentence):
    # 用于检测提取的文本中是否出现非文本类型的,若有则通过类似title = title.replace("fi", "fi")替换
    import regex as re
    # 定义正则表达式,匹配非文本字符(除了字母、数字、空格和标点符号之外的字符)
    non_text_pattern = re.compile(r'[^a-zA-Z0-9\s\p{P}]', re.UNICODE)
    # 使用正则表达式搜索句子中的非文本字符
    non_text_chars = non_text_pattern.findall(sentence)
    # 打印出非文本字符及其类型
    for char in non_text_chars:
        print(title)
        print(f"非文本字符 '{char}' 的类型是 '{type(char)}\n\n'")
    return None


def get\_pdf\_title\_1(pdf_path):
    """读取PDF文件的标题,并进行处理。"""
    with open(pdf_path, 'rb') as pdf_file:
        pdf_reader = PdfReader(pdf_file)
        doc_info = pdf_reader.metadata
        # 尝试从文档信息中获取标题
        paper_title = doc_info.get('/Title', 'untitled') if doc_info else 'untitled'

        # 如果标题有效,则进行进一步处理
        if paper_title != 'untitled' and paper_title != 'Untitled' and not paper_title.endswith('.pdf'):
            # 解码HTML实体
            paper_title = html.unescape(paper_title)
            # 替换不适合作为文件名的字符
            paper_title = re.sub(r'[:/\\\*?"\'<>|]', ' ', paper_title)
        else:
            # 无效的标题,返回默认值
            paper_title = 'untitled'
        return paper_title


def get\_pdf\_title\_2(pdf_path):
    # 检查文件名是否符合特定模式
    filename = os.path.basename(pdf_path)
    if filename == "[SCI 】ions for nonlinear dynamical systems.pdf":
        return "Estynamical systems"

    doc = fitz.open(pdf_path)
    first_page = doc[0]  # 只查看第一页

    # 获取页面上所有文本块,每个块包含文字、字体大小和位置
    blocks = first_page.get_text("dict")["blocks"]
    # 只考虑页面上半部分的文本块
    mid_y = first_page.rect.height / 2
    top_blocks = [b for b in blocks if b['type'] == 0 and b['bbox'][3] < mid_y]

    # 提取每个文本块的字体大小和文本内容
    text_blocks_with_size = []
    for block in top_blocks:
        if 'lines' in block:  # 确保文本块包含行
            for line in block['lines']:
                if 'spans' in line:  # 确保行包含span
                    for span in line['spans']:
                        if 'size' in span and len(span['text'].strip()) >= 2:  # 检查span中是否有size信息且文本长度符合要求
                            text_blocks_with_size.append((span['text'], span['size'], span['bbox']))

    # 排除特定关键词
    excluded_keywords = ["Research Article", "Physica A", "Neurocomputing",
                         "Sustainable Energy Technologies and Assessments"]
    filtered_blocks = [block for block in text_blocks_with_size if
                       not any(keyword in block[0] for keyword in excluded_keywords)]

    # 在过滤后的文本块中基于字体大小和垂直位置来识别可能的标题
    if filtered_blocks:
        max_font_size = max([size for _, size, _ in filtered_blocks], default=0)
        possible_title_blocks = [block for block in filtered_blocks if block[1] == max_font_size]

        # 合并具有相同最大字体大小的连续文本块
        title_texts = [block[0] for block in possible_title_blocks]
        title = " ".join(title_texts) if title_texts else "untitled"
    else:
        title = "untitled"

    doc.close()
    title = title.replace("fi", "fi")
    title = title.replace("ff", "ff")
    # 查找句子中的非文本字符
    find_non_text_chars(title)
    return title


def get\_pdf\_title(pdf_path):
    # 先使用get\_pdf\_title\_1获取标题,若获取失败则使用get\_pdf\_title\_2获取
    paper_title = get_pdf_title_1(pdf_path)  # 假设这是从PDF提取标题的函数
    # 编写一个正则表达式来匹配以连续4个数字和.pdf为后缀的字符串
    # 匹配以连续三个数字和.pdf结尾的字符串,或者包含空格和点的字符串,以及不包含空格但包含点的字符串
    regex_pattern = r'\d{3}\.pdf$|^[A-Z]+-\w+\s\d+\.\.\d+$|\w+\.\d+\s\d+\.\.\d+$|^[a-zA-Z]+\_\d+\w\*$'

    # 判断条件:标题不是'untitled'且不匹配正则表达式(即不是以连续4个数字和.pdf结尾)
    if paper_title != 'untitled' and not re.search(regex_pattern, paper_title):
        return paper_title
    else:
        paper_title = get_pdf_title_2(pdf_path)
        return paper_title


def get\_titles\_from\_directory(directory_path, specific_file):
    titles = []
    specific_pdf_path = None  # 用于存储特定文件的路径
    for root, dirs, files in os.walk(directory_path):
        for file in files:
            if file.lower().endswith('.pdf'):
                pdf_path = os.path.join(root, file)
                if file == specific_file:  # 如果当前文件是特定文件
                    specific_pdf_path = pdf_path
                else:
                    try:
                        title = get_pdf_title(pdf_path)
                        titles.append((file, title))
                    except Exception as e:
                        print(f"Error processing {file}: {e}")

    # 处理特定文件
    if specific_pdf_path:
        try:
            title = get_pdf_title(specific_pdf_path)
            titles.insert(0, (specific_file, title))  # 将特定文件的标题插入到列表的最前面
        except Exception as e:
            print(f"Error processing {specific\_file}: {e}")

    return titles


specific_file = "lic health.pdf"

 # 替换为你的PDF文件所在的目录路径
directory_path = pdf_dir
titles = get_titles_from_directory(directory_path, specific_file)

with open(TitlesCSV, 'w', newline='', encoding='utf-8') as csv_file:
    csv_writer = csv.writer(csv_file, delimiter=',')
    csv_writer.writerow(['Files', 'Title'])  # 写入头部信息
    for file, title in titles:
        # 写入文件名和标题
        csv_writer.writerow([file, title])


步骤二:生成目录和页码,合并PDF(Step_two.ipynb)

### 第三步:读取 Step\_one.ipynb获取的标题的CSV文件
### 第四步:根据文件名字 标题 合并PDF 并生成目录与页码

# 读取路径下所有.pdf为后缀的文件
pdf_dir = '老师的论文集/'
# 合并后的PDF名字
output_pdf_path = "合并后/老师的论文集.pdf"
# 用于中间 存放文件名与标题的CSV文件
TitlesCSV = '合并后/老师的论文集.csv'

import csv
import io
import os

from PyPDF2 import PdfReader, PdfWriter
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.pdfgen import canvas


def create\_footer\_page(footer_text):
    packet = io.BytesIO()
    c = canvas.Canvas(packet, pagesize=letter)


**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/56f6353e85b788623127447c4ab479ce.png)
![img](https://img-blog.csdnimg.cn/img_convert/183d900448f7c7f8803a5a0b4534fe51.png)
![](https://img-blog.csdnimg.cn/img_convert/46506ae54be168b93cf63939786134ca.png)
![](https://img-blog.csdnimg.cn/img_convert/252731a671c1fb70aad5355a2c5eeff0.png)
![](https://img-blog.csdnimg.cn/img_convert/6c361282296f86381401c05e862fe4e9.png) 
![](https://img-blog.csdnimg.cn/img_convert/9f49b566129f47b8a67243c1008edf79.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)**
![img](https://img-blog.csdnimg.cn/img_convert/75627adc4403de5312252cbc032b3759.png)



[**一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)

**AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**

net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)

**AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算**

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提取PDF文档的信息,需要使用Python中的pdfminer库。以下是一个简单的程序设计,以提取PDF文档标题和作者为例: ```python import io import pdfminer from pdfminer.pdfparser import PDFParser from pdfminer.pdfdocument import PDFDocument from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.pdfpage import PDFPage from pdfminer.layout import LAParams, LTTextBoxHorizontal # 打开PDF文件 with open('example.pdf', 'rb') as file: # 创建一个PDF解析器对象 parser = PDFParser(file) # 创建一个PDF文档对象 document = PDFDocument(parser) # 如果PDF文件已加密,则尝试解密它 if document.is_encrypted: document.decrypt('') # 创建PDF资源管理器对象 resource_manager = PDFResourceManager() # 创建一个参数分析器对象 laparams = LAParams() # 创建一个PDF设备对象 device = PDFPageAggregator(resource_manager, laparams=laparams) # 创建一个PDF页面解释器对象 interpreter = PDFPageInterpreter(resource_manager, device) # 遍历PDF页面 for page in PDFPage.create_pages(document): interpreter.process_page(page) # 获取页面布局 layout = device.get_result() # 遍历页面布局 for element in layout: # 如果元素是一个水平文本框 if isinstance(element, LTTextBoxHorizontal): # 获取元素文本 text = element.get_text().strip() # 如果文本以'Author:'开头 if text.startswith('Author:'): # 提取作者信息 author = text.split(':')[1].strip() # 如果文本以'Title:'开头 elif text.startswith('Title:'): # 提取标题信息 title = text.split(':')[1].strip() # 输出标题和作者信息 print('Title:', title) print('Author:', author) ``` 这个程序会打开名为'example.pdf'的PDF文件,并提取其中的标题和作者信息。程序使用pdfminer库中的PDFParser、PDFDocument、PDFResourceManager、PDFPageInterpreter、PDFPage和LTTextBoxHorizontal等类来解析PDF文件和提取信息。程输出提取到的标题和作者信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值