清旧入梦 发表于 2025-3-29 10:18:51

[Python 原创] 多个Excel文件中搜索关键字的工具

工作需要,因为是重复工作就写了个工具


    一个用于在多个Excel文件中搜索关键字的工具。
    可以选择多个Excel文件,搜索包含特定关键字的行,
    并按文件名分组显示结果的execl行数据。


发现还挺多人看的 初入萌新很激动呐 感谢大家支持 虽然打包的挺大 但很多人有需求就给大家放个exe
本来是考虑把标题都展示的 不用回头看excel文件了,然后发现很多可能标题行在第二行,动态适应查找比较麻烦
所以目前就是显示的行 用于快速定位位置 具体内容还是在具体文件中看吧

蓝奏云:https://wwl.lanzoum.com/iAt2w2r0dgyd
密码:52pj


纯文本查看 复制代码


import os
import tkinter as tk
from tkinter import filedialog, ttk
import pandas as pd
from pathlib import Path

class ExcelSearchTool:
    """
    一个用于在多个Excel文件中搜索关键字的工具。
    可以选择多个Excel文件,搜索包含特定关键字的行,
    并按文件名分组显示结果。
    """
   
    def __init__(self, root):
      """
      初始化Excel搜索工具界面
         
      @Param {tk.Tk} root - tkinter根窗口对象
      """
      self.root = root
      self.root.title("Excel多文件搜索工具")
      self.root.geometry("1200x800")# 增加窗口大小
         
      # 设置全局样式
      style = ttk.Style()
      style.configure("Treeview", font=('微软雅黑', 10))# 设置树形视图字体
      style.configure("Treeview.Heading", font=('微软雅黑', 10, 'bold'))# 设置表头字体
      style.configure("TLabelframe.Label", font=('微软雅黑', 10, 'bold'))# 设置LabelFrame标题字体
      style.configure("TButton", font=('微软雅黑', 10))# 设置按钮字体
         
      self.selected_files = []
      self.create_widgets()
         
    def create_widgets(self):
      """
      创建并配置界面组件
      """
      # 主容器
      main_container = ttk.Frame(self.root, padding="10")
      main_container.pack(fill="both", expand=True)
         
      # 文件选择框架
      file_frame = ttk.LabelFrame(main_container, text="选择Excel文件", padding="10")
      file_frame.pack(fill="x", pady=(0, 10))
         
      self.file_label = ttk.Label(file_frame, text="尚未选择文件", font=('微软雅黑', 10))
      self.file_label.pack(side="left", padx=(5, 10), fill="x", expand=True)
         
      select_btn = ttk.Button(file_frame, text="选择文件", command=self.select_files, width=15)
      select_btn.pack(side="right", padx=5)
         
      # 搜索框架
      search_frame = ttk.LabelFrame(main_container, text="搜索内容", padding="10")
      search_frame.pack(fill="x", pady=(0, 10))
         
      ttk.Label(search_frame, text="关键字:", font=('微软雅黑', 10)).pack(side="left", padx=(5, 10))
         
      self.search_entry = ttk.Entry(search_frame, width=50, font=('微软雅黑', 10))
      self.search_entry.pack(side="left", padx=(0, 10), fill="x", expand=True)
         
      search_btn = ttk.Button(search_frame, text="搜索", command=self.search_keyword, width=15)
      search_btn.pack(side="left")
         
      # 结果显示框架
      result_frame = ttk.LabelFrame(main_container, text="搜索结果", padding="10")
      result_frame.pack(fill="both", expand=True)
         
      # 创建带滚动条的框架
      tree_frame = ttk.Frame(result_frame)
      tree_frame.pack(fill="both", expand=True)
         
      # 创建Treeview显示结果
      self.result_tree = ttk.Treeview(tree_frame, show="headings", selectmode="browse")
      self.result_tree["columns"] = ("file", "sheet", "row", "data")
         
      # 配置列
      self.result_tree.column("file", width=200, anchor="w")
      self.result_tree.column("sheet", width=100, anchor="w")
      self.result_tree.column("row", width=80, anchor="center")
      self.result_tree.column("data", width=800, anchor="w")
         
      # 配置表头
      self.result_tree.heading("file", text="文件名", anchor="w")
      self.result_tree.heading("sheet", text="工作表", anchor="w")
      self.result_tree.heading("row", text="行号", anchor="center")
      self.result_tree.heading("data", text="数据内容", anchor="w")
         
      # 添加垂直滚动条
      scrollbar_y = ttk.Scrollbar(tree_frame, orient="vertical", command=self.result_tree.yview)
      self.result_tree.configure(yscrollcommand=scrollbar_y.set)
         
      # 添加水平滚动条
      scrollbar_x = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.result_tree.xview)
      self.result_tree.configure(xscrollcommand=scrollbar_x.set)
         
      # 布局滚动条和树形视图
      self.result_tree.grid(row=0, column=0, sticky="nsew")
      scrollbar_y.grid(row=0, column=1, sticky="ns")
      scrollbar_x.grid(row=1, column=0, sticky="ew")
         
      # 配置grid权重
      tree_frame.grid_rowconfigure(0, weight=1)
      tree_frame.grid_columnconfigure(0, weight=1)
         
      # 添加进度框架
      self.progress_frame = ttk.LabelFrame(main_container, text="查询进度", padding="10")
      self.progress_frame.pack(fill="x", pady=(0, 10))
         
      self.progress_label = ttk.Label(self.progress_frame, text="", font=('微软雅黑', 10))
      self.progress_label.pack(fill="x", padx=5)
         
      self.progress_bar = ttk.Progressbar(self.progress_frame, mode='determinate')
      self.progress_bar.pack(fill="x", padx=5, pady=(5, 0))
         
      # 状态栏
      self.status_var = tk.StringVar()
      self.status_var.set("就绪")
      status_bar = ttk.Label(
            main_container,
            textvariable=self.status_var,
            relief="sunken",
            anchor="w",
            font=('微软雅黑', 9),
            padding=(5, 2)
      )
      status_bar.pack(fill="x", pady=(10, 0))
         
    def select_files(self):
      """
      打开文件选择对话框,允许用户选择多个Excel文件
      """
      filetypes = [("Excel 文件", "*.xlsx;*.xls")]
      files = filedialog.askopenfilenames(filetypes=filetypes)
         
      if files:
            self.selected_files = files
            if len(files) > 1:
                self.file_label.config(text=f"已选择 {len(files)} 个文件")
            else:
                self.file_label.config(text=f"已选择: {Path(files).name}")
            self.status_var.set(f"已选择 {len(files)} 个Excel文件")
         
    def search_keyword(self):
      """
      在选定的Excel文件中搜索关键字,并在Treeview中显示结果
      """
      # 清除现有的搜索结果
      for item in self.result_tree.get_children():
            self.result_tree.delete(item)
            
      keyword = self.search_entry.get().strip()
      if not keyword:
            self.status_var.set("错误: 请输入搜索关键字")
            return
            
      if not self.selected_files:
            self.status_var.set("错误: 请先选择Excel文件")
            return
            
      # 初始化进度条
      total_files = len(self.selected_files)
      self.progress_bar["maximum"] = total_files
      self.progress_bar["value"] = 0
         
      found_count = 0
      error_files = []
      empty_files = []
         
      try:
            for file_idx, file_path in enumerate(self.selected_files, 1):
                file_name = Path(file_path).name
                self.progress_label.config(text=f"正在搜索: {file_name} ({file_idx}/{total_files})")
                self.progress_bar["value"] = file_idx
                self.root.update()
               
                try:
                  excel = pd.ExcelFile(file_path)
                  file_found = False
                     
                  for sheet_name in excel.sheet_names:
                        try:
                            df = pd.read_excel(file_path, sheet_name=sheet_name)
                            sheet_found = False
                           
                            for row_idx, row in df.iterrows():
                              row_found = False
                              row_values = []
                                 
                              for col_name, value in row.items():
                                    if isinstance(value, (str, int, float)) and str(keyword).lower() in str(value).lower():
                                        row_found = True
                                        row_values =
                                        break
                                 
                              if row_found:
                                    tag = 'even' if found_count % 2 == 0 else 'odd'
                                    values = (
                                        file_name,
                                        sheet_name,
                                        f"第{row_idx+1}行",
                                        " | ".join(row_values)
                                    )
                                    self.result_tree.insert("", "end", values=values, tags=(tag,))
                                    found_count += 1
                                    file_found = True
                                    sheet_found = True
                        
                        except Exception as sheet_error:
                            error_files.append(f"{file_name} (工作表: {sheet_name})")
                     
                  if not file_found:
                        empty_files.append(file_name)
                     
                except Exception as file_error:
                  error_files.append(file_name)
               
                self.root.update()
         
            # 设置交替行的背景色
            self.result_tree.tag_configure('odd', background='#F5F5F5')
            self.result_tree.tag_configure('even', background='white')
            
            # 构建详细的状态信息
            status_messages = []
            if found_count > 0:
                status_messages.append(f"找到 {found_count} 个匹配项")
            if empty_files:
                status_messages.append(f"{len(empty_files)} 个文件未找到匹配内容")
            if error_files:
                status_messages.append(f"{len(error_files)} 个文件出现错误")
            
            status_text = " | ".join(status_messages)
            self.status_var.set(f"搜索完成 - {status_text}")
            
            # 更新进度标签显示详细结果
            result_details = []
            if empty_files:
                result_details.append(f"未找到匹配的文件:{', '.join(empty_files)}")
            if error_files:
                result_details.append(f"搜索出错的文件:{', '.join(error_files)}")
            
            self.progress_label.config(text="\n".join(result_details) if result_details else "搜索完成")
            
      except Exception as e:
            self.status_var.set(f"搜索过程出现错误: {str(e)}")
      finally:
            self.progress_bar["value"] = self.progress_bar["maximum"]

def main():
    """
    程序入口点
    """
    root = tk.Tk()
    app = ExcelSearchTool(root)
    root.mainloop()

if __name__ == "__main__":
    main()软件界面

山中八月 发表于 2025-3-29 10:20:36

打包试了下,Python打包体积还是挺大的,33.2MB,打开速度也不太快需要4-6秒。
另外试了下用UPX压缩后26.8MB,但打开速度太慢了需要10-15秒。就不上传了。
https://wwse.lanzoub.com/iqda72r06tej
密码:8yqq

试了下:
1、基本单元格搜索还是可以的(见图示2),但不支持搜索【注释】和【批注】内容,希望楼主能优化支持。
2、发现了个【搜索n字符bug】小问题,详见图示1。




页: [1]
查看完整版本: [Python 原创] 多个Excel文件中搜索关键字的工具