毕业设计网站开发选题依据,怎么往网站添加视频,做目录网站注意,合肥seo按天扣费Python#xff1a;自动化处理PDF文档集合#xff0c;提取文献标题、合并文献PDF并生成目录和页码 引言#xff1a;功能概述步骤一#xff1a;提取PDF标题步骤二#xff1a;生成目录和页码#xff0c;合并PDF技术亮点 代码步骤一#xff1a;提取PDF标题#xff08;Step_… Python自动化处理PDF文档集合提取文献标题、合并文献PDF并生成目录和页码 引言功能概述步骤一提取PDF标题步骤二生成目录和页码合并PDF技术亮点 代码步骤一提取PDF标题Step_two.ipynb步骤二生成目录和页码合并PDFStep_two.ipynb  引言 
在学术研究、文档管理等领域经常需要处理大量的PDF文档。手动整理这些文档既耗时又低效。本文介绍一个使用Python自动化这一过程的方法包括提取PDF文件的标题生成目录添加页码并最终合并为一个PDF文件。这不仅提高了工作效率也增加了文档的可用性和可读性。 
功能概述 
本项目通过两个主要步骤实现PDF文档的自动化处理 
提取PDF文档的标题从每个PDF文件中提取标题并保存到一个CSV文件中。这一步允许用户手动校对和修正自动提取的标题。生成目录和页码然后合并PDF文件根据校对后的标题自动生成目录页为每个PDF文件的每一页添加页码最后将所有文件合并成一个PDF。 
步骤一提取PDF标题 
首先将所有待处理的PDF文件放入指定的目录中。运行第一步脚本Step_one.ipynb该脚本自动遍历目录中的每个PDF文件提取其标题并将文件名及对应的标题保存到一个CSV文件中。 
这一步骤涉及PDF元数据的读取和文本提取技术。对于难以直接从元数据中获取标题的情况脚本尝试从PDF的内容中分析出可能的标题。处理完所有文件后用户可以检查CSV文件并手动修正错误的标题。 
步骤二生成目录和页码合并PDF 
在校对完CSV文件中的标题后运行第二步脚本Step_two.ipynb。该脚本首先根据CSV文件中的信息生成一个目录页然后为每个PDF页面添加页码并将所有PDF文件合并为一个。 
目录页的生成考虑了标题的长度对过长的标题进行适当的分行处理确保目录的整洁性。页码的添加在页面底部中央通过绘制白色矩形覆盖原有页码区域后添加新的页码信息以避免页码重叠。最终所有页面包括目录页和带有新页码的原始页面被合并成一个PDF文件。 
技术亮点 
文本提取与处理通过PyMuPDF和PyPDF2库提取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  合并后/老师的论文集.csvimport csv
import html
import os
import re  # 导入正则表达式模块import fitz  # PyMuPDF
from PyPDF2 import PdfReaderdef 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 Nonedef 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  untitledreturn paper_titledef get_pdf_title_2(pdf_path):# 检查文件名是否符合特定模式filename  os.path.basename(pdf_path)if filename  [SCI 】ions for nonlinear dynamical systems.pdf:return Estynamical systemsdoc  fitz.open(pdf_path)first_page  doc[0]  # 只查看第一页# 获取页面上所有文本块每个块包含文字、字体大小和位置blocks  first_page.get_text(dict)[blocks]# 只考虑页面上半部分的文本块mid_y  first_page.rect.height / 2top_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:  # 确保行包含spanfor 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 ifnot any(keyword in block[0] for keyword in excluded_keywords)]# 在过滤后的文本块中基于字体大小和垂直位置来识别可能的标题if filtered_blocks:max_font_size  max([size for _, size, _ in filtered_blocks], default0)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 untitledelse:title  untitleddoc.close()title  title.replace(fi, fi)title  title.replace(ff, ff)# 查找句子中的非文本字符find_non_text_chars(title)return titledef 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_titleelse:paper_title  get_pdf_title_2(pdf_path)return paper_titledef 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_pathelse:try:title  get_pdf_title(pdf_path)titles.append((file, title))except Exception as e:print(fError 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(fError processing {specific_file}: {e})return titlesspecific_file  lic health.pdf# 替换为你的PDF文件所在的目录路径
directory_path  pdf_dir
titles  get_titles_from_directory(directory_path, specific_file)with open(TitlesCSV, w, newline, encodingutf-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]) 
步骤二生成目录和页码合并PDFStep_two.ipynb 
### 第三步读取 Step_one.ipynb获取的标题的CSV文件
### 第四步根据文件名字 标题 合并PDF 并生成目录与页码# 读取路径下所有.pdf为后缀的文件
pdf_dir  老师的论文集/
# 合并后的PDF名字
output_pdf_path  合并后/老师的论文集.pdf
# 用于中间 存放文件名与标题的CSV文件
TitlesCSV  合并后/老师的论文集.csvimport csv
import io
import osfrom PyPDF2 import PdfReader, PdfWriter
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.pdfgen import canvasdef create_footer_page(footer_text):packet  io.BytesIO()c  canvas.Canvas(packet, pagesizeletter)width, height  letter  # letter页面的宽度和高度font_name  Helvetica  # 使用的字体font_size  12  # 字体大小cover_height  font_size  4  # 覆盖区域的高度稍大于字体大小以确保完全覆盖原有页码cover_y_position  28  # 覆盖区域的Y位置根据需要进行调整以确保覆盖原有页码# 计算文本宽度和起始X位置以居中文本text_width  c.stringWidth(footer_text, font_name, font_size)text_start_position  (width - text_width) / 2# 绘制一个足够大的白色矩形以覆盖原有页码c.setFillColorRGB(1, 1, 1)  # 设置填充颜色为白色c.rect(0, cover_y_position, width, cover_height, strokeFalse, fillTrue)# 在页脚区域居中添加文本高度可以根据需要调整c.setFont(font_name, font_size)  # 设置字体和大小c.setFillColorRGB(0, 0, 0)  # 设置文本颜色为黑色c.drawString(text_start_position, 32, footer_text)  # 绘制居中的页脚文本c.save()packet.seek(0)return PdfReader(packet)# 定义用于分割过长标题的函数以适应页面宽度
def split_title(title, available_width, font_nameHelvetica, font_size12):split_titles  []  # 存储分割后的标题部分# 循环直到标题宽度小于可用宽度while stringWidth(title, font_name, font_size)  available_width:split_point  len(title)  # 初始分割点设置为标题长度# 寻找适合分割的位置使分割后的宽度小于可用宽度while split_point  0 and stringWidth(title[:split_point]  -, font_name, font_size)  available_width:split_point - 1  # 逐字符减少分割点if split_point  0:  # 如果找不到分割点添加整个标题并结束循环split_titles.append(title)breaksplit_titles.append(title[:split_point]  -)  # 添加分割后的标题部分title  title[split_point:]  # 准备处理剩余的标题部分if title:  # 确保添加剩余的未分割部分split_titles.append(title)return split_titles# 添加目录页的函数包含书签的标题和页码
def add_catalog_page(bookmarks):packet  io.BytesIO()  # 创建内存流以存储PDF数据c  canvas.Canvas(packet, pagesizeletter)  # 创建PDF画布width, height  letter  # 获取页面尺寸top_margin  60  # 顶部边距bottom_margin  60  # 底部边距y_position  height - top_margin  # 初始Y坐标位置c.setFont(Helvetica-Bold, 16)  # 设置目录标题字体和大小c.drawString(280, y_position, Directory)  # 绘制目录标题y_position - 30  # 更新Y坐标为目录项c.setFont(Helvetica, 12)  # 设置目录项字体和大小left_margin  72  # 左边距right_margin  width - 72  # 右边距dot_space  5  # 点线间隔different_title_spacing  25  # 不同标题间隔same_title_line_spacing  15  # 同一标题行间隔title_number  1  # 标题编号初始值for title, page_number in bookmarks:split_titles  split_title(title, right_margin - left_margin - 25, Helvetica, 12)  # 分割长标题for index, part_title in enumerate(split_titles):if index  0:# 对新标题的第一部分添加编号formatted_number  str(title_number).zfill(2)full_title  f{formatted_number}. {part_title}title_number  1else:# 分割的部分不添加编号# 分割的行需要空出编号和第一行相同的空间full_title_blank    * len(str(title_number).zfill(2)  .   )full_title  f{full_title_blank}{part_title}c.drawString(left_margin, y_position, full_title)  # 绘制标题if index  len(split_titles) - 1:  # 在最后一部分标题处添加页码c.drawRightString(right_margin, y_position, str(page_number))  # 绘制页码# 绘制连接标题和页码的点线dot_line_start  left_margin  stringWidth(full_title, Helvetica, 12)  10dot_line_end  right_margin - stringWidth(str(page_number), Helvetica, 12) - 10current_position  dot_line_startwhile current_position  dot_line_end:c.drawString(current_position, y_position, .)current_position  dot_spacey_position - same_title_line_spacing  # 更新Y坐标为同一标题的下一行y_position - different_title_spacing - same_title_line_spacing  # 为下一个标题更新Y坐标减去已应用的间隔if y_position  bottom_margin:  # 如果超出页面底部创建新页面c.showPage()y_position  height - top_marginc.setFont(Helvetica, 12)  # 确保新页面使用相同的字体设置c.save()  # 保存PDF数据到内存流packet.seek(0)  # 将内存流指针重置到起始位置return PdfReader(packet)  # 创建PDF阅读器对象返回包含目录页数据的对象# 读取CSV文件
pdf_titles_info  []
with open(TitlesCSV, r, encodingutf-8) as csvfile:reader  csv.reader(csvfile)next(reader)  # 跳过标题行for row in reader:# 假设第一列是文件名第二列是标题pdf_titles_info.append(row)# 准备工作区
all_pages  []
bookmarks  []
total_pages  0# 更新根据pdf_titles_info直接处理文件
for filename, title in pdf_titles_info:pdf_path  os.path.join(pdf_dir, filename)bookmarks.append((title, total_pages  1))  # 使用提供的标题而不是重新获取reader  PdfReader(pdf_path)for page in reader.pages:all_pages.append(page)total_pages  1# 创建目录页
writer  PdfWriter()
catalog_pdf  add_catalog_page(bookmarks)  # 这里假设add_catalog_page可以处理bookmarks列表
for page in catalog_pdf.pages:writer.add_page(page)# 为每页添加页脚
current_page_number  1
for page in all_pages:footer_pdf  create_footer_page(fPage number:{current_page_number})page.merge_page(footer_pdf.pages[0])writer.add_page(page)current_page_number  1# 保存最终的PDF文件
output_pdf_path  output_pdf_path
with open(output_pdf_path, wb) as f_out:writer.write(f_out) 文章转载自: http://www.morning.yllym.cn.gov.cn.yllym.cn http://www.morning.ymhjb.cn.gov.cn.ymhjb.cn http://www.morning.dqpd.cn.gov.cn.dqpd.cn http://www.morning.qbjgw.cn.gov.cn.qbjgw.cn http://www.morning.hympq.cn.gov.cn.hympq.cn http://www.morning.zzhqs.cn.gov.cn.zzhqs.cn http://www.morning.smggx.cn.gov.cn.smggx.cn http://www.morning.zhnyj.cn.gov.cn.zhnyj.cn http://www.morning.kzhxy.cn.gov.cn.kzhxy.cn http://www.morning.pqktp.cn.gov.cn.pqktp.cn http://www.morning.rpkg.cn.gov.cn.rpkg.cn http://www.morning.hmqwn.cn.gov.cn.hmqwn.cn http://www.morning.kzpy.cn.gov.cn.kzpy.cn http://www.morning.dangaw.com.gov.cn.dangaw.com http://www.morning.mkkcr.cn.gov.cn.mkkcr.cn http://www.morning.nhgfz.cn.gov.cn.nhgfz.cn http://www.morning.c7510.cn.gov.cn.c7510.cn http://www.morning.cmzcp.cn.gov.cn.cmzcp.cn http://www.morning.jrwbl.cn.gov.cn.jrwbl.cn http://www.morning.mqzcn.cn.gov.cn.mqzcn.cn http://www.morning.thzgd.cn.gov.cn.thzgd.cn http://www.morning.rcjwl.cn.gov.cn.rcjwl.cn http://www.morning.hrpmt.cn.gov.cn.hrpmt.cn http://www.morning.yngtl.cn.gov.cn.yngtl.cn http://www.morning.lswgs.cn.gov.cn.lswgs.cn http://www.morning.pmlgr.cn.gov.cn.pmlgr.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.fnnkl.cn.gov.cn.fnnkl.cn http://www.morning.sjbpg.cn.gov.cn.sjbpg.cn http://www.morning.xplng.cn.gov.cn.xplng.cn http://www.morning.osshjj.cn.gov.cn.osshjj.cn http://www.morning.fhlfp.cn.gov.cn.fhlfp.cn http://www.morning.dmzmy.cn.gov.cn.dmzmy.cn http://www.morning.lwygd.cn.gov.cn.lwygd.cn http://www.morning.wkws.cn.gov.cn.wkws.cn http://www.morning.hmqwn.cn.gov.cn.hmqwn.cn http://www.morning.tqdqc.cn.gov.cn.tqdqc.cn http://www.morning.rkhhl.cn.gov.cn.rkhhl.cn http://www.morning.dmxzd.cn.gov.cn.dmxzd.cn http://www.morning.qzxb.cn.gov.cn.qzxb.cn http://www.morning.fqpyj.cn.gov.cn.fqpyj.cn http://www.morning.xbwqg.cn.gov.cn.xbwqg.cn http://www.morning.fqyqm.cn.gov.cn.fqyqm.cn http://www.morning.mlckd.cn.gov.cn.mlckd.cn http://www.morning.dnphd.cn.gov.cn.dnphd.cn http://www.morning.kpcxj.cn.gov.cn.kpcxj.cn http://www.morning.nclbk.cn.gov.cn.nclbk.cn http://www.morning.hmhdn.cn.gov.cn.hmhdn.cn http://www.morning.cndxl.cn.gov.cn.cndxl.cn http://www.morning.hrzky.cn.gov.cn.hrzky.cn http://www.morning.qjlnh.cn.gov.cn.qjlnh.cn http://www.morning.lkgqb.cn.gov.cn.lkgqb.cn http://www.morning.knzmb.cn.gov.cn.knzmb.cn http://www.morning.bpmtx.cn.gov.cn.bpmtx.cn http://www.morning.lwtld.cn.gov.cn.lwtld.cn http://www.morning.kfsfm.cn.gov.cn.kfsfm.cn http://www.morning.lmjtp.cn.gov.cn.lmjtp.cn http://www.morning.nwpnj.cn.gov.cn.nwpnj.cn http://www.morning.tdcql.cn.gov.cn.tdcql.cn http://www.morning.jypqx.cn.gov.cn.jypqx.cn http://www.morning.ghjln.cn.gov.cn.ghjln.cn http://www.morning.gbyng.cn.gov.cn.gbyng.cn http://www.morning.bnrnb.cn.gov.cn.bnrnb.cn http://www.morning.rkypb.cn.gov.cn.rkypb.cn http://www.morning.ydmml.cn.gov.cn.ydmml.cn http://www.morning.dtfgr.cn.gov.cn.dtfgr.cn http://www.morning.slwqt.cn.gov.cn.slwqt.cn http://www.morning.rqhdt.cn.gov.cn.rqhdt.cn http://www.morning.rhdln.cn.gov.cn.rhdln.cn http://www.morning.mbhdl.cn.gov.cn.mbhdl.cn http://www.morning.wslr.cn.gov.cn.wslr.cn http://www.morning.kflpf.cn.gov.cn.kflpf.cn http://www.morning.rxhn.cn.gov.cn.rxhn.cn http://www.morning.qrnbs.cn.gov.cn.qrnbs.cn http://www.morning.wmcng.cn.gov.cn.wmcng.cn http://www.morning.gklxm.cn.gov.cn.gklxm.cn http://www.morning.mlckd.cn.gov.cn.mlckd.cn http://www.morning.nzklw.cn.gov.cn.nzklw.cn http://www.morning.lnckq.cn.gov.cn.lnckq.cn http://www.morning.gfpyy.cn.gov.cn.gfpyy.cn