开发者

使用Python开发Excel表格数据对比工具

开发者 https://www.devze.com 2025-04-08 10:32 出处:网络 作者: 探客白泽
目录1.概述2.功能使用2.1 界面介绍2.2 文件加载与工作表选择3.效果展示4. 相关源码5.总结在日常的数据处理与分析工作中,我们经常需要对比两个 Excel 文件中的数据。这种操作看似简单,但如果手动操作,不仅容易出错
目录
  • 1.概述
  • 2.功能使用
    • 2.1 界面介绍
    • 2.2 文件加载与工作表选择
  • 3.效果展示
    • 4. 相关源码
      • 5.总结

        在日常的数据处理与分析工作中,我们经常需要对比两个 Excel 文件中的数据。这种操作看似简单,但如果手动操作,不仅容易出错,而且非常耗时。今天,我们将深入探讨如何通过 python 和 PyQt5 结合 pandas 库,快速实现一个高效、自动化的 Excel 数据对比工具。本文将详细介绍该工具的功能和使用方法,并探讨其潜在的扩展性。

        1.概述

        数据对比是数据处理中的一项基础工作,特别是在审计、报告、数据验证等任务中,通常需要确保两个数据源的内容一致。在实际的业务操作中,Excel 文件由于其简便易用、兼容性强,成为了大量数据存储的首选。然而,手动对比 Excel 文件往往繁琐且容易出现差错,尤其是在数据量较大的情况下。为了提升工作效率,本文基于 Python 中的 PyQt5 和 pandas 库,开发了一个简洁易用的 Excel 数据对比工具,能够高效地比较两个 Excel 文件中的数据差异。

        技术栈

        PyQt5:用于构建桌面 GUI(图形用户界面),提供友好的用户交互界面。

        pandas:处理 Excel 文件,进行数据对比。

        openpyxl:用来处理 Excel 文件的写入和样式设置,导出比较结果。

        QSS:通过自定义样式表美化界面,提升用户体验。

        2.功能使用

        2.1 界面介绍

        该工具的界面简单直观,包含以下主要部分:

        文件选择:用户可以选择需要比较的两个 Excel 文件。

        Sheet 选择:加载 Excel 文件后,用户可以选择要比较的工作表。

        列选择:用户选择要进行对比的列,可以灵活选择不同列的数据进行比对。

        对比结果表格:展示对比结果,包括左侧数据、右侧数据、匹配状态和内容对比。若数据不匹配,相关行会高亮显示。

        操作按钮:用户可以点击按钮执行对比操作、导出结果、重置界面和退出程序。

        2.2 文件加载与工作表选择

        首先,用户通过点击“打开”按钮选择两个 Excel 文件。文件选择完成后,应用会自动读取并展示文件中的所有工作表名称,用户可以从下拉框中选择对应的工作表。

        file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)")
        

        列选择与数据对比

        用户可以选择要对比的列。点击“开始对比”按钮后,应用会依照选择的列名对比两个工作表中的数据。如果两列数据一致,表格中会显示“✔”标记;若不一致,则显示“✘”标记,并高亮不匹配的行,详细展示差异内容。

        left_value = str(df_left[left_col].iloc[i])
        right_value = str(df_right[right_col].iloc[i])
        match = "✔" if left_value == right_value else "✘"
        

        导出结果

        用户对比完成后,可以通过“导出结果”按钮将对比结果保存为新的 Excel 文件。保存时,程序会自动高亮不匹配的数据行,并将所有对比信息写入到新文件中,便于后续查看与分析。

        ws.append([left_data, right_data, match_status, compare_info])
        

        重置与退出功能

        程序提供了“重置界面”按钮,用于清空当前选项和对比结果,方便用户重新开始操作。同时,“退出程序”按钮可以关闭应用。

        代码实现

        上述功能的实现主要依赖于 PyQt5 和 pandas 库。以下是部分关键代码片段:

        文件加载与数据读取

        def load_file(self, side):
            file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)")
            if not file_path:
                return
        
            # 选择文件后更新界面
            if side == "left":
                self.left_file = file_path
            else:
                self.right_file = file_path
        
            # 加载工作表名称
            try:
                sheets = pd.ExcelFile(file_path).sheet_names
                if side == "left":
                    self.left_sheet.addItems(sheets)
                else:
                    self.right_sheet.addItems(sheets)
            except Exception as e:
                QMessageBox.warning(self, "错误", f"无法读取 Excel 文件: {e}")
        

        数据对比与结果展示

        def compare_data(self):
            left_col = self.left_column.currentText()
            right_col = self.right_column.currentText()
        
            # 读取数据
            df_left = pd.read_excel(self.left_file, sheet_name=self.left_sheet.currentText())
            df_right = pd.read_excel(self.right_file, sheet_name=self.right_sheet.currentText())
        
            # 对比并更新表格
            for i in range(min(len(df_left), len(df_right))):
                left_value = str(df_left[left_col].iloc[i])
                right_value = str(df_right[right_col].iloc[i])
                match = "✔" if left_value == right_value else "✘"
        
                row = self.table.rowCount()
                self.table.insertRow(row)
        
                # 填充表格
                self.table.setItem(row, 0, QTableWidgetItem(left_value))
                self.table.setItem(row, 1, QTableWidgetItem(right_value))
                self.table.setItem(row, 2, QTableWidgetItem(match))
        

        导出结果到 Excel

        def export_results(self):
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            file_path, _ = QFileDialog.getSaveFileName(self, "保存 Excel", f"对比结果_{timestamp}.xlsx", "Excel 文件 (*.xlsx)")
        
            if not file_path:
                return
        
            # 创建 Excel 文件并保存数据
            wb = openpyxl.Workbook()
            ws = wb.active
            ws.append(["左侧数据", "右侧数据", "匹配状态", "内容对比"])
        
            for row in range(self.table.rowCount()):
                left_data = self.table.item(row, 0).text()
                right_data = self.table.item(row, 1).text()
                match_status = self.table.item(row, 2).text()
                compare_info = self.table.item(row, 3).text()
        
                ws.append([left_data, right_data, match_status, compare_info])
                if match_status == "✘":
                    for col in range(1, 5):
                        ws.cell(row=row+2, column=col).fill = red_fill
        
            wb.save(file_path)
        

        3.效果展示

        使用Python开发Excel表格数据对比工具

        使用Python开发Excel表格数据对比工具

        4. 相关源码

        import sys
        import pandas ahWQdwKPs pd
        from PyQt5.QtWidgets import (
            QApplication, QWidget, QvboxLayout, QHBoxLayout, QPushButton,
            QFileDialog, QTableWidget, QTableWidgetItem, QLabel, QComboBox, QMessageBox
        )
        from PyQt5.QtGui import QBrush, QColor
        from datetime import datetime
        import openpyxl
        from openpyxl.styles import PaphptternFill
        
        class ExcelComparator(QWidget):
            def __init__(self):
                super().__init__()
                self.initUI()
        #
            def initUI(self):
                self.setWindowTitle("Excel 数据对比工具")
                self.setGeometry(100, 100, 900, 500)
                
                # 应用 QSS 美化界面
                self.setStyleSheet("""
                    QWidget { background-color: #f4f4f4; }
                    QPushButton { 
                        background-color: #0078D7; color: white; 
                        border-radius: 5px; padding: 8px; 
                        font-size: 14px;
                    }
                    QPushButton:hover { background-color: #005A9E; }
                    QTableWidget { background-color: white; gridline-color: #CCC; }
                    QLabel { font-size: 14px;  }
                "编程客栈"")
        
                layout = QVBoxLayout()
        
                # 文件选择区
                file_layout = QHBoxLayout()
                self.left_label = QLabel("左侧文件:")
                self.right_label = QLabel("右侧文件:")
                self.left_btn = QPushButton("打开")
                self.right_btn = QPushButton("打开")
                self.left_btn.clicked.connect(lambda: self.load_file("left"))
                self.right_btn.clicked.connect(lambda: self.load_file("right"))
                
                file_layout.addWidget(self.left_label)
                file_layout.addWidget(self.left_btn)
                file_layout.addWidget(self.right_label)
                file_layout.addWidget(self.right_btn)
                
                # Sheet 选择区
                sheet_layout = QHBoxLayout()
                self.left_sheet = QComboBox()
                self.right_sheet = QComboBox()
                self.left_sheet.currentIndexChanged.connect(lambda: self.load_sheet("left"))
                self.right_sheet.currentIndexChanged.connect(lambda: self.load_sheet("right"))
                
                sheet_layout.addWidget(QLabel("左侧 Sheet:"))
                sheet_layout.addWidget(self.left_sheet)
                sheet_layout.addWidget(QLabel("右侧 Sheet:"))
                sheet_layout.addWidget(self.right_sheet)
                
                # 对比列选择
                column_layout = QHBoxLayout()
                self.left_column = QComboBox()
                self.right_column = QComboBox()
                
                column_layout.addWidget(QLabel("左侧对比列:"))
                column_layout.addWidget(self.left_column)
                column_layout.addWidget(QLabel("右侧对比列:"))
                column_layout.addWidget(self.right_column)
        
                # 结果表格
                self.table = QTableWidget()
                self.table.setColumnCount(4)
                self.table.setHorizontalHeaderLabels(["左侧数据", "右侧数据", "匹配状态", "内容对比"])
        
                # 操作按钮
                button_layout = QHBoxLayout()
                self.compare_btn = QPushButton("开始对比")
                self.export_btn = QPushButton("导出结果")
                self.reset_btn = QPushButton("重置界面")
                self.exit_btn = QPushButton("退出程序")
                
                self.compare_btn.clicked.connect(self.compare_data)
                self.export_btn.clicked.connect(self.export_results)
                self.reset_btn.clicked.connect(self.reset_ui)
                self.exit_btn.clicked.connect(self.close)
                
                button_layout.addWidget(self.compare_btn)
                button_layout.addWidget(self.export_btn)
                button_layout.addWidget(self.reset_btn)
                button_layout.addWidget(self.exit_btn)
        
                # 布局组合
                layout.addLayout(file_layout)
                layout.addLayout(sheet_layout)
                layout.addLayout(column_layout)
                layout.addWidget(self.table)
                layout.addLayout(button_layout)
                self.setLayout(layout)
        
            def load_file(self, side):
                file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)")
                if not file_path:
                    return
        
                if side == "left":
                    self.left_label.setText(f"左侧文件: {file_path}")
                    self.left_file = file_path
                    self.left_sheet.clear()
                else:
                    self.right_label.setText(f"右侧文件: {file_path}")
                    self.right_file = file_path
                    self.right_sheet.clear()
        
                try:
                    sheets = pd.ExcelFile(file_path).sheet_names
                    if side == "left":
                        self.left_sheet.addItems(sheets)
                    else:
                        self.right_sheet.addItems(sheets)
                except Exception as e:
                    QMessageBox.warning(self, "错误", f"无法读取 Excel 文件: {e}")
        
            def load_sheet(self, side):
                if side == "left":
                    file, sheet_combo, column_combo = self.left_file, self.left_sheet, self.left_column
                else:
                    file, sheet_combo, column_combo = self.right_file, self.right_sheet, self.right_column
        
                if not file or sheet_combo.currentText() == "":
                    return
        
                try:
                    df = pd.read_excel(file, sheet_name=sheet_combo.currentText())
                    df.columns = df.columns.map(str)  # 确保列名是字符串
                    column_combo.clear()
                    column_combo.addItems(df.columns)
                except Exception as e:
                    QMessageBox.warning(self, "错误", f"无法加载 Sheet 数据: {e}")
        
            def compare_data(self):
                left_col = self.left_column.currentText()
                right_col = self.right_column.currentText()
        
                if not left_col or not right_col:
                    QMessageBox.warning(self, "错误", "请选择要对比的列!")
                    return
        
                df_left = pd.read_excel(self.left_file, sheet_name=self.left_sheet.currentText())
                df_right = pd.read_excel(self.right_file, sheet_name=self.right_sheet.currentText())
        
                df_left.columns = df_left.columns.map(str)
                df_right.columns = df_right.columns.map(str)
        
                self.table.setRowCount(0)
        
                for i in range(min(len(df_left), len(df_right))):
                    left_value = str(df_left[left_col].iloc[i])
                    right_value = str(df_right[right_编程客栈col].iloc[i])
                    match = "✔" if left_value == right_value else "✘"
        
                    row = self.table.rowCount()
                    self.table.insertRow(row)
                    
                    # 左侧数据列
                    if not self.table.item(row, 0):
                        self.table.setItem(row, 0, QTableWidgetItem(left_value))
                    else:
                        self.table.item(row, 0).setText(left_value)
                
                    # 右侧数据列
                    if not self.table.item(row, 1):
                        self.table.setItem(row, 1, QTableWidgetItem(right_value))
                    else:
                        self.table.item(row, 1).setText(right_value)
                
                    # 匹配状态列
                    item_match = QTableWidgetItem(match)
                    if not self.table.item(row, 2):
                        self.table.setItem(row, 2, item_match)
                    else:
                        self.table.item(row, 2).setText(match)
        
                    # 高亮不匹配的行
                    if match == "✘":
                        for col in range(4):  # 增加第四列的信息对比内容列表
                            if not self.table.item(row, col):
                                self.table.setItem(row, col, QTableWidgetItem())
                            self.table.item(row, col).setBackground(QBrush(QColor(255, 150, 150)))
        
                        # 对比内容显示
                        differences = f"左侧: {left_value} | 右侧: {right_value}"
                        if not self.table.item(row, 3):
                            self.table.setItem(row, 3, QTableWidgetItem(differences))
                        else:
                            self.table.item(row, 3).setText(differences)
        
            def export_results(self):
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                file_path, _ = QFileDialog.getSaveFileName(self, "保存 Excel", f"对比结果_{timestamp}.xlsx", "Excel 文件 (*.xlsx)")
                
                if not file_path:
                    return
                
                wb = openpyxl.Workbook()
                ws = wb.active
                ws.append(["左侧数据", "右侧数据", "匹配状态", "内容对比"])
                red_fphpill = PatternFill(start_color="FF9999", end_color="FF9999", fill_type="solid")
        
                for row in range(self.table.rowCount()):
                    left_data = self.table.item(row, 0).text()
                    right_data = self.table.item(row, 1).text()
                    match_status = self.table.item(row, 2).text()
                    compare_info = self.table.item(row, 3).text()
        
                    ws.append([left_data, right_data, match_status, compare_info])
                    if match_status == "✘":
                        for col in range(1, 5):
                            ws.cell(row=row+2, column=col).fill = red_fill
        
                wb.save(file_path)
        
            def reset_ui(self):
                self.left_sheet.clear()
                self.right_sheet.clear()
                self.left_column.clear()
                self.right_column.clear()
                self.table.setRowCount(0)
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            window = ExcelComparator()
            window.show()
            sys.exit(app.exec_())
        

        5.总结

        通过 PyQt5 和 pandas,我们快速实现了一个 Excel 数据对比工具,能够高效地处理两个 Excel 文件的内容对比,并自动高亮显示差异。此外,用户可以方便地导出对比结果,以便后续的查看和分析。对于需要频繁进行数据比对的工作人员而言,这款工具无疑能够大幅度提高工作效率,减少人工错误。

        在未来的版本中,可以考虑以下几点扩展:

        • 多列对比:支持用户选择多个列进行对比。
        • 性能优化:对于大数据量的 Excel 文件,可以优化读取和比较的速度。
        • 自动化脚本:将此工具的功能封装为命令行工具,便于批量处理。

        通过不断优化与扩展,我们能够将这款工具打造得更加完善,成为每位数据分析师和审计人员的得力助手。

        到此这篇关于使用Python开发Excel表格数据对比工具的文章就介绍到这了,更多相关Python Excel数据对比内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

        0

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        关注公众号