主要功能:根据关键词及指定列查询整个电子表格的多个Sheet,然后将数据写入新文件,保持原来的格式。

Python代码如下:

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pandas as pd
import os
from pathlib import Path
import time
import shutil
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
from copy import copy
import traceback
import sys
 
def resource_path(relative_path):
    """ 获取资源的绝对路径 """
    try:
        # PyInstaller创建临时文件夹,将路径存储在_MEIPASS中
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
     
    return os.path.join(base_path, relative_path)
 
class ExcelQueryApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Excel查询工具-志伟呀@_@qzw")
        self.root.geometry("1200x800")
         
        # 配置根窗口的网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
         
        # 数据相关变量
        self.df = None
        self.default_save_path = os.path.join(os.path.expanduser("~"), "Desktop")
         
        self.create_widgets()
         
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
         
        # 创建左右分栏
        left_frame = ttk.Frame(main_frame)
        left_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 10))
         
        right_frame = ttk.Frame(main_frame)
        right_frame.grid(row=0, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
         
        # 配置左侧框架的网格权重
        left_frame.columnconfigure(0, weight=1)
        left_frame.rowconfigure(1, weight=1)  # 让工作表设置区域可以扩展
         
        # 左侧内容 - 顶部文件选择
        file_frame = ttk.Frame(left_frame)
        file_frame.grid(row=0, column=0, sticky=(tk.W, tk.E), pady=(0, 5))
         
        ttk.Label(file_frame, text="选择Excel文件:").pack(side=tk.LEFT)
        self.file_path = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.file_path, width=50).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_frame, text="浏览", command=self.browse_file).pack(side=tk.LEFT)
         
        # Sheet信息显示和设置(使用滚动框架)
        sheet_container = ttk.LabelFrame(left_frame, text="工作表设置", padding="5")
        sheet_container.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
         
        # 配置sheet_container的网格权重
        sheet_container.columnconfigure(0, weight=1)
        sheet_container.rowconfigure(0, weight=1)
         
        # 创建Canvas和Scrollbar
        canvas = tk.Canvas(sheet_container)
        scrollbar = ttk.Scrollbar(sheet_container, orient="vertical", command=canvas.yview)
         
        # 创建可滚动的框架
        self.sheet_frame = ttk.Frame(canvas)
        self.sheet_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
         
        # 配置canvas的网格权重
        canvas.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
         
        # 在Canvas中创建窗口
        canvas.create_window((0, 0), window=self.sheet_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
         
        # 绑定鼠标滚轮事件
        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1*(event.delta/120)), "units")
        canvas.bind_all("<MouseWheel>", _on_mousewheel)
         
        # 统一设置选项
        self.unified_settings = tk.BooleanVar(value=True)
        ttk.Checkbutton(self.sheet_frame, text="统一设置所有工作表", 
                        variable=self.unified_settings,
                        command=self.toggle_settings).grid(row=0, column=0, columnspan=2, sticky=tk.W)
         
        # 统一设置框架
        self.unified_frame = ttk.Frame(self.sheet_frame)
        self.unified_frame.grid(row=1, column=0, columnspan=2, pady=5, sticky=(tk.W, tk.E))
         
        ttk.Label(self.unified_frame, text="表头行号:").grid(row=0, column=0, sticky=tk.W)
        self.unified_header_row = tk.StringVar(value="1")
        ttk.Entry(self.unified_frame, textvariable=self.unified_header_row, width=10).grid(row=0, column=1)
         
        ttk.Label(self.unified_frame, text="关键词列号:").grid(row=0, column=2, sticky=tk.W, padx=(20,0))
        self.unified_keyword_column = tk.StringVar(value="1")
        ttk.Entry(self.unified_frame, textvariable=self.unified_keyword_column, width=10).grid(row=0, column=3)
         
        # 独立设置框架(初始隐藏)
        self.individual_frame = ttk.Frame(self.sheet_frame)
        self.sheet_settings = {}
         
        # 左侧底部控件
        bottom_frame = ttk.Frame(left_frame)
        bottom_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=10)
         
        # 关键词输入
        keyword_frame = ttk.Frame(bottom_frame)
        keyword_frame.pack(fill=tk.X, pady=(0, 5))
        ttk.Label(keyword_frame, text="关键词(用逗号分隔):").pack(side=tk.LEFT)
        self.keywords = tk.StringVar()
        ttk.Entry(keyword_frame, textvariable=self.keywords, width=50).pack(side=tk.LEFT, fill=tk.X, expand=True)
         
        # 进度条
        self.progress = ttk.Progressbar(bottom_frame, length=300, mode='determinate')
        self.progress.pack(fill=tk.X, pady=5)
         
        # 操作按钮
        button_frame = ttk.Frame(bottom_frame)
        button_frame.pack(fill=tk.X)
        ttk.Button(button_frame, text="查询并保存", command=self.search_and_save).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="保存原始数据", command=self.save_original_data).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="设置默认保存路径", command=self.set_default_save_path).pack(side=tk.LEFT, padx=5)
         
        # 右侧内容 - 日志显示
        ttk.Label(right_frame, text="操作日志:").grid(row=0, column=0, sticky=tk.W)
        self.log_text = tk.Text(right_frame, width=50, height=40)
        self.log_text.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
         
        # 日志滚动条
        log_scrollbar = ttk.Scrollbar(right_frame, orient="vertical", command=self.log_text.yview)
        log_scrollbar.grid(row=1, column=1, sticky=(tk.N, tk.S))
        self.log_text.configure(yscrollcommand=log_scrollbar.set)
         
        # 配置网格权重,使得窗口可以正确调整大小
        main_frame.columnconfigure(0, weight=3)  # 左侧占比更大
        main_frame.columnconfigure(1, weight=2)  # 右侧占比较小
        right_frame.columnconfigure(0, weight=1)
        right_frame.rowconfigure(1, weight=1)
         
    def toggle_settings(self):
        """切换统一设置和独立设置"""
        if self.unified_settings.get():
            self.unified_frame.grid()
            self.individual_frame.grid_remove()
        else:
            self.unified_frame.grid_remove()
            self.individual_frame.grid()
         
    def browse_file(self):
        file_path = filedialog.askopenfilename(
            filetypes=[("Excel files", "*.xlsx *.xls")]
        )
        if file_path:
            self.file_path.set(file_path)
            self.update_sheet_info(file_path)
         
    def update_sheet_info(self, file_path):
        """更新工作表信息"""
        try:
            # 读取Excel文件中的sheet信息
            wb = load_workbook(file_path, read_only=True)
            sheet_names = wb.sheetnames
            wb.close()
             
            self.log_message(f"发现 {len(sheet_names)} 个工作表")
             
            # 清除现有的sheet设置
            for widget in self.individual_frame.winfo_children():
                widget.destroy()
            self.sheet_settings.clear()
             
            # 为每个sheet创建设置控件
            for idx, sheet_name in enumerate(sheet_names):
                frame = ttk.LabelFrame(self.individual_frame, text=f"工作表: {sheet_name}", padding="5")
                frame.grid(row=idx, column=0, sticky=(tk.W, tk.E), pady=2)
                 
                ttk.Label(frame, text="表头行号:").grid(row=0, column=0, sticky=tk.W)
                header_var = tk.StringVar(value="1")
                ttk.Entry(frame, textvariable=header_var, width=10).grid(row=0, column=1)
                 
                ttk.Label(frame, text="关键词列号:").grid(row=0, column=2, sticky=tk.W, padx=(20,0))
                keyword_var = tk.StringVar(value="1")
                ttk.Entry(frame, textvariable=keyword_var, width=10).grid(row=0, column=3)
                 
                self.sheet_settings[sheet_name] = {
                    'header_row': header_var,
                    'keyword_column': keyword_var
                }
             
            self.individual_frame.grid(row=2, column=0, columnspan=2, pady=5, sticky=(tk.W, tk.E))
            if self.unified_settings.get():
                self.individual_frame.grid_remove()
             
        except Exception as e:
            self.log_message(f"读取工作表信息时发生错误:{str(e)}", "ERROR")
         
    def set_default_save_path(self):
        path = filedialog.askdirectory()
        if path:
            self.default_save_path = path
            messagebox.showinfo("成功", f"默认保存路径已设置为:{path}")
             
    def log_message(self, message, level="INFO"):
        """添加日志消息到日志窗口并立即更新显示"""
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
        formatted_message = f"[{timestamp}] [{level}] {message}\n"
        self.log_text.insert(tk.END, formatted_message)
        self.log_text.see(tk.END)  # 自动滚动到最新消息
        self.root.update()  # 使用update()而不是update_idletasks()来强制更新界面
         
    def search_and_save(self):
        try:
            # 清空之前的日志
            self.log_text.delete(1.0, tk.END)
             
            # 获取输入参数
            file_path = self.file_path.get()
            keywords = [str(k.strip()) for k in self.keywords.get().split(",") if k.strip()]
             
            if not all([file_path, keywords]):
                self.log_message("错误:请填写所有必要信息", "ERROR")
                messagebox.showerror("错误", "请填写所有必要信息")
                return
             
            # 获取工作表设置
            sheet_configs = {}
            if self.unified_settings.get():
                # 使用统一设置
                header_row = int(self.unified_header_row.get()) - 1
                keyword_col = int(self.unified_keyword_column.get()) - 1
                wb = load_workbook(file_path, read_only=True)
                for sheet_name in wb.sheetnames:
                    sheet_configs[sheet_name] = {
                        'header_row': header_row,
                        'keyword_col': keyword_col
                    }
                wb.close()
            else:
                # 使用独立设置
                for sheet_name, settings in self.sheet_settings.items():
                    sheet_configs[sheet_name] = {
                        'header_row': int(settings['header_row'].get()) - 1,
                        'keyword_col': int(settings['keyword_column'].get()) - 1
                    }
             
            self.log_message(f"开始处理文件: {file_path}")
            self.log_message(f"搜索关键词: {keywords}")
             
            total_steps = len(keywords) * 2
            current_step = 0
             
            # 为每个关键词处理
            for keyword in keywords:
                self.log_message(f"\n开始处理关键词: {keyword}")
                 
                # 创建安全的文件名
                safe_keyword = "".join(c for c in keyword if c.isalnum() or c in (' ', '-', '_'))
                save_path = os.path.join(self.default_save_path, f"查询结果_{safe_keyword}.xlsx")
                 
                # 复制整个文件
                self.log_message(f"正在复制文件...")
                shutil.copy2(file_path, save_path)
                self.log_message(f"已创建文件副本: {save_path}")
                 
                current_step += 1
                self.progress['value'] = (current_step / total_steps) * 100
                 
                # 打开复制的文件
                wb = load_workbook(save_path)
                total_sheets = len(wb.sheetnames)
                 
                # 处理每个sheet
                for sheet_idx, sheet_name in enumerate(wb.sheetnames, 1):
                    config = sheet_configs[sheet_name]
                    self.log_message(f"\n正在处理工作表 ({sheet_idx}/{total_sheets}): {sheet_name}")
                    self.log_message(f"使用设置 - 表头行号: {config['header_row'] + 1}, 关键词列号: {config['keyword_col'] + 1}")
                     
                    # 读取原始数据用于查询
                    df = pd.read_excel(file_path, sheet_name=sheet_name, header=config['header_row'])
                     
                    # 过滤数据
                    filtered_df = df[df.iloc[:, config['keyword_col']].astype(str) == keyword]
                     
                    # 获当前sheet
                    sheet = wb[sheet_name]
                     
                    # 保留表头行,删除其他所有行
                    if sheet.max_row > config['header_row'] + 1:
                        sheet.delete_rows(config['header_row'] + 2, 
                                        sheet.max_row - (config['header_row'] + 1))
                     
                    if not filtered_df.empty:
                        self.log_message(f"找到 {len(filtered_df)} 行匹配数据")
                         
                        # 添加过滤后的数据
                        for row_idx, (_, row) in enumerate(filtered_df.iterrows(), 1):
                            if row_idx % 100 == 0:
                                self.log_message(f"已写入 {row_idx}/{len(filtered_df)} 行...")
                            sheet.append(list(row))
                    else:
                        self.log_message(f"未找到匹配数据", "WARNING")
                     
                    # 更新进度条
                    sheet_progress = (sheet_idx / total_sheets) * (100 / total_steps)
                    self.progress['value'] = ((current_step - 1) / total_steps * 100) + sheet_progress
                    self.root.update()
                 
                # 保存文件
                wb.save(save_path)
                self.log_message(f"关键词 '{keyword}' 的结果文件处理完成!", "SUCCESS")
                 
                current_step += 1
                self.progress['value'] = (current_step / total_steps) * 100
             
            self.log_message("\n所有处理完成!", "SUCCESS")
            messagebox.showinfo("成功", "所有关键词的查询结果已保存完成!")
             
        except Exception as e:
            error_msg = f"发生错误:{str(e)}"
            self.log_message(error_msg, "ERROR")
            self.log_message(traceback.format_exc(), "ERROR")
            messagebox.showerror("错误", error_msg)
        finally:
            self.progress['value'] = 0
             
    def save_original_data(self):
        try:
            file_path = self.file_path.get()
            if not file_path:
                self.log_message("错误:请先选择Excel文件", "ERROR")
                messagebox.showerror("错误", "请先选择Excel文件")
                return
                 
            save_path = os.path.join(self.default_save_path, "原始数据备份.xlsx")
            self.log_message(f"正在保存原始数据到: {save_path}")
             
            import xlwings as xw
            wb = xw.Book(file_path)
            wb.save(save_path)
            wb.close()
             
            self.log_message("原始数据保存完成!", "SUCCESS")
            messagebox.showinfo("成功", f"原始数据已保存至:{save_path}")
             
        except Exception as e:
            error_msg = f"保存原始数据时发生错误:{str(e)}"
            self.log_message(error_msg, "ERROR")
            self.log_message(traceback.format_exc(), "ERROR")
            messagebox.showerror("错误", error_msg)
 
if __name__ == "__main__":
    root = tk.Tk()
    app = ExcelQueryApp(root)
    root.mainloop()

 

下载地址
蓝奏云
密码:无
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。