当前位置: 首页 > news >正文

本地运行的检索PDF文件中出现关键字的python程序

如果PDF不是OCR的,要在一大堆PDF中检索某个关键词,比较麻烦,
下面的程序可以实现,功能有:
1)本地运行
2)指定某个文件夹,检索出结果,并且可以本地打开。

import os
import sys
import pdfplumber
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import webbrowser
import threading
from queue import Queueclass PDFSearchApp:def __init__(self, root):self.root = rootself.root.title("PDF关键词搜索工具")self.root.geometry("900x650")# 设置主题样式self.style = ttk.Style()if sys.platform == "win32":self.style.theme_use('vista')elif sys.platform == "darwin":self.style.theme_use('aqua')else:self.style.theme_use('clam')self.setup_ui()# 用于线程间通信的队列self.result_queue = Queue()# 检查是否在搜索中self.searching = Falsedef setup_ui(self):"""设置用户界面"""# 主框架main_frame = ttk.Frame(self.root, padding="10")main_frame.pack(fill=tk.BOTH, expand=True)# 文件夹选择区域folder_frame = ttk.LabelFrame(main_frame, text="PDF文件夹选择", padding="10")folder_frame.pack(fill=tk.X, pady=(0, 10))self.folder_var = tk.StringVar()folder_entry = ttk.Entry(folder_frame, textvariable=self.folder_var, width=80)folder_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))browse_btn = ttk.Button(folder_frame, text="浏览...", command=self.browse_folder)browse_btn.pack(side=tk.RIGHT)# 关键词搜索区域search_frame = ttk.LabelFrame(main_frame, text="搜索设置", padding="10")search_frame.pack(fill=tk.X, pady=(0, 10))ttk.Label(search_frame, text="关键词:").pack(side=tk.LEFT)self.keyword_var = tk.StringVar()keyword_entry = ttk.Entry(search_frame, textvariable=self.keyword_var, width=40)keyword_entry.pack(side=tk.LEFT, padx=(5, 10))keyword_entry.bind("<Return>", lambda event: self.start_search())self.search_btn = ttk.Button(search_frame, text="开始搜索", command=self.start_search)self.search_btn.pack(side=tk.RIGHT)# 结果区域results_frame = ttk.LabelFrame(main_frame, text="搜索结果", padding="10")results_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))# 创建带滚动条的树形视图tree_frame = ttk.Frame(results_frame)tree_frame.pack(fill=tk.BOTH, expand=True)# 创建垂直滚动条tree_scroll = ttk.Scrollbar(tree_frame)tree_scroll.pack(side=tk.RIGHT, fill=tk.Y)# 创建水平滚动条h_scroll = ttk.Scrollbar(tree_frame, orient="horizontal")h_scroll.pack(side=tk.BOTTOM, fill=tk.X)# 创建树形视图self.tree = ttk.Treeview(tree_frame,yscrollcommand=tree_scroll.set,xscrollcommand=h_scroll.set,selectmode="browse")# 配置滚动条tree_scroll.config(command=self.tree.yview)h_scroll.config(command=self.tree.xview)# 定义列self.tree["columns"] = ("path", "count")self.tree.column("#0", width=0, stretch=tk.NO)  # 隐藏默认列self.tree.column("path", anchor=tk.W, width=600)self.tree.column("count", anchor=tk.CENTER, width=100)# 设置列标题self.tree.heading("path", text="文件路径", anchor=tk.W)self.tree.heading("count", text="出现次数", anchor=tk.CENTER)# 绑定双击事件打开文件self.tree.bind("<Double-1>", self.open_selected_file)self.tree.pack(fill=tk.BOTH, expand=True)# 状态栏self.status_var = tk.StringVar()self.status_var.set("就绪")status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)status_bar.pack(side=tk.BOTTOM, fill=tk.X)# 添加右键菜单self.context_menu = tk.Menu(self.tree, tearoff=0)self.context_menu.add_command(label="打开文件", command=self.open_selected_file)self.context_menu.add_command(label="复制文件路径", command=self.copy_file_path)self.tree.bind("<Button-3>", self.show_context_menu)def browse_folder(self):"""浏览并选择文件夹"""folder_path = filedialog.askdirectory(title="选择包含PDF文件的文件夹")if folder_path:self.folder_var.set(folder_path)def start_search(self):"""开始搜索"""folder_path = self.folder_var.get().strip()keyword = self.keyword_var.get().strip()# 验证输入if not folder_path or not os.path.isdir(folder_path):messagebox.showerror("错误", "请选择有效的PDF文件夹")returnif not keyword:messagebox.showerror("错误", "请输入搜索关键词")return# 清空之前的搜索结果for item in self.tree.get_children():self.tree.delete(item)# 更新状态self.status_var.set(f"正在搜索 '{keyword}' 在文件夹: {folder_path}...")self.search_btn.config(state=tk.DISABLED)self.searching = True# 在后台线程执行搜索threading.Thread(target=self.search_worker, args=(folder_path, keyword), daemon=True).start()# 开始检查结果队列self.root.after(100, self.check_results)def search_worker(self, folder_path, keyword):"""搜索工作线程"""try:results = self.search_pdfs_for_keyword(folder_path, keyword)self.result_queue.put(('results', results, keyword, folder_path))except Exception as e:self.result_queue.put(('error', str(e)))def check_results(self):"""检查结果队列"""while not self.result_queue.empty():msg_type, *data = self.result_queue.get()if msg_type == 'results':results, keyword, folder_path = dataself.display_results(results, keyword, folder_path)elif msg_type == 'error':error_msg = data[0]messagebox.showerror("搜索错误", f"搜索过程中发生错误:\n{error_msg}")self.status_var.set("搜索出错")self.searching = Falseself.search_btn.config(state=tk.NORMAL)if self.searching:self.root.after(100, self.check_results)def search_pdfs_for_keyword(self, folder_path, keyword):"""在指定文件夹中搜索包含关键字的PDF文件并统计出现次数参数:folder_path (str): 要搜索的文件夹路径keyword (str): 要搜索的关键字返回:list: 包含关键字的PDF文件信息列表,每个元素包含文件路径和出现次数"""results = []keyword_lower = keyword.lower()total_files = 0processed_files = 0# 首先统计PDF文件总数(用于进度显示)for _, _, files in os.walk(folder_path):total_files += sum(1 for f in files if f.lower().endswith('.pdf'))# 遍历文件夹中的所有文件for root, _, files in os.walk(folder_path):for file in files:if file.lower().endswith('.pdf'):file_path = os.path.join(root, file)processed_files += 1try:# 更新状态self.status_var.set(f"正在处理 ({processed_files}/{total_files}): {file}")# 使用pdfplumber打开PDF文件with pdfplumber.open(file_path) as pdf:text = ""# 提取所有页面的文本for page in pdf.pages:page_text = page.extract_text()if page_text:text += page_text + "\n"# 检查关键字并统计出现次数text_lower = text.lower()count = text_lower.count(keyword_lower)if count > 0:# 保留相对路径显示,更简洁rel_path = os.path.relpath(file_path, folder_path)results.append({'file_path': file_path,'display_path': rel_path,'count': count,'absolute_path': os.path.abspath(file_path)})except Exception as e:print(f"处理文件 {file_path} 时出错: {e}")# 按出现次数排序(降序)results.sort(key=lambda x: x['count'], reverse=True)return resultsdef display_results(self, results, keyword, folder_path):"""显示搜索结果"""if not results:self.status_var.set(f"未找到包含 '{keyword}' 的PDF文件")messagebox.showinfo("搜索完成", f"在文件夹 '{folder_path}' 中未找到包含 '{keyword}' 的PDF文件")return# 添加结果到树形视图for result in results:self.tree.insert("", tk.END, values=(result['display_path'], result['count']),tags=(result['absolute_path'],))self.status_var.set(f"找到 {len(results)} 个包含 '{keyword}' 的PDF文件")messagebox.showinfo("搜索完成", f"找到 {len(results)} 个包含 '{keyword}' 的PDF文件")def open_selected_file(self, event=None):"""打开选中的文件"""selected_items = self.tree.selection()if not selected_items:returnitem = selected_items[0]file_path = self.tree.item(item, "tags")[0]if not file_path or not os.path.isfile(file_path):messagebox.showerror("错误", "无法获取有效的文件路径")returntry:# 尝试使用系统默认程序打开if sys.platform == 'win32':os.startfile(file_path)elif sys.platform == 'darwin':subprocess.call(('open', file_path))else:subprocess.call(('xdg-open', file_path))self.status_var.set(f"已尝试打开: {file_path}")except Exception as e:messagebox.showerror("打开文件错误", f"无法打开文件:\n{str(e)}")def copy_file_path(self):"""复制选中文件的路径到剪贴板"""selected_items = self.tree.selection()if not selected_items:returnitem = selected_items[0]file_path = self.tree.item(item, "tags")[0]if file_path:self.root.clipboard_clear()self.root.clipboard_append(file_path)self.status_var.set(f"已复制文件路径到剪贴板: {file_path}")def show_context_menu(self, event):"""显示右键菜单"""item = self.tree.identify_row(event.y)if item:self.tree.selection_set(item)self.context_menu.post(event.x_root, event.y_root)if __name__ == "__main__":# 检查是否安装了必要的库try:import pdfplumberexcept ImportError:result = messagebox.askyesno("依赖缺失","未找到pdfplumber库。需要安装才能提取PDF文本。\n\n""是否现在安装? (需要网络连接)\n\n""点击'是'将运行: pip install pdfplumber\n""点击'否'将退出程序")if result:import subprocesstry:subprocess.check_call([sys.executable, "-m", "pip", "install", "pdfplumber"])messagebox.showinfo("安装完成", "pdfplumber库已成功安装!")except Exception as e:messagebox.showerror("安装失败", f"无法安装pdfplumber库:\n{str(e)}\n\n请手动安装后重新运行程序")sys.exit(1)else:sys.exit(0)# 创建并运行GUIroot = tk.Tk()app = PDFSearchApp(root)root.mainloop()

功能特点

1. 用户友好界面

  • 简洁直观的Tkinter界面
  • 支持Windows、macOS和Linux
  • 响应式布局,适应不同屏幕尺寸

2. 核心功能

  • 文件夹选择:通过系统原生对话框选择PDF文件夹
  • 关键词搜索:输入关键词后按回车或点击按钮开始搜索
  • 结果展示
    • 显示文件相对路径(简洁)
    • 显示关键词出现次数
    • 按出现次数降序排列
  • 文件操作
    • 双击文件或右键菜单可直接打开PDF
    • 右键菜单提供"复制文件路径"功能

3. 高级特性

  • 后台搜索:搜索在独立线程中进行,不会冻结UI
  • 进度显示:状态栏显示当前处理的文件和进度
  • 错误处理:友好的错误提示和异常处理
  • 自动依赖检查:如果没有安装pdfplumber,会提示安装

使用说明

1. 安装依赖

首次运行时,程序会自动检查并安装pdfplumber库(需要网络连接):

  • 如果没有安装,会弹出提示询问是否安装
  • 点击"是"将自动安装
  • 如果不想自动安装,可以手动运行:pip install pdfplumber
http://www.dtcms.com/a/357992.html

相关文章:

  • 2025年如何批量下载雪球帖子和文章导出pdf?
  • 2025 批量下载雪球和东方财富帖子和文章导出excel和pdf
  • kind集群应用
  • 《云原生架构从崩溃失控到稳定自愈的实践方案》
  • 「鸿蒙系统的编程基础」——探索鸿蒙开发
  • 第12章:推荐算法与实践
  • 科技感网页计时器.html
  • 设计模式:抽象工厂模式(Abstract Factory Pattern)
  • 在word以及latex中引用zotero中的参考文献
  • 单例模式的mock类注入单元测试与友元类解决方案
  • 云存储(参考自腾讯云计算工程师认证)
  • Twitter舆情裂变链:指纹云手机跨账号协同机制提升互动率200%
  • 使用电脑操作Android11手机,连接步骤
  • 【序列晋升】21 Spring Cloud Gateway 云原生网关演进之路
  • DVWA靶场通关笔记-CSRF(Impossible级别)
  • 【90页PPT】新能源汽车数字化转型SAP解决方案(附下载方式)
  • 汽车加气站操作工证考试的复习重点是什么?
  • 【自然语言处理与大模型】多机多卡分布式微调训练的有哪些方式
  • C++ constexpr:编译时计算的高效秘籍
  • 复现论文块体不锈钢上的光栅耦合表面等离子体共振
  • 10.2 工程学中的矩阵
  • hadoop安欣医院挂号看诊管理系统(代码+数据库+LW)
  • 使用 Ansible 和 Azure Pipelines 增强您的 DevOps
  • Midjourney绘画创作入门操作创作(广告创意与设计)
  • 腾讯云centos7.6的运维笔记——从yum的安装与更新源开始
  • C++ 之 【map和set的模拟实现】(只涉及map和set的插入、迭代器以及map的operator[]函数)
  • Altium Designer中电路板设计
  • 流式HTTP MCP服务器开发
  • Android中handler机制
  • 《RANKGUESS: Password Guessing Using Adversarial Ranking》——论文解读