使用Python開發(fā)Excel表格數(shù)據(jù)對比工具
在日常的數(shù)據(jù)處理與分析工作中,我們經(jīng)常需要對比兩個 Excel 文件中的數(shù)據(jù)。這種操作看似簡單,但如果手動操作,不僅容易出錯,而且非常耗時。今天,我們將深入探討如何通過 Python 和 PyQt5 結(jié)合 pandas 庫,快速實現(xiàn)一個高效、自動化的 Excel 數(shù)據(jù)對比工具。本文將詳細介紹該工具的功能和使用方法,并探討其潛在的擴展性。
1.概述
數(shù)據(jù)對比是數(shù)據(jù)處理中的一項基礎工作,特別是在審計、報告、數(shù)據(jù)驗證等任務中,通常需要確保兩個數(shù)據(jù)源的內(nèi)容一致。在實際的業(yè)務操作中,Excel 文件由于其簡便易用、兼容性強,成為了大量數(shù)據(jù)存儲的首選。然而,手動對比 Excel 文件往往繁瑣且容易出現(xiàn)差錯,尤其是在數(shù)據(jù)量較大的情況下。為了提升工作效率,本文基于 Python 中的 PyQt5 和 pandas 庫,開發(fā)了一個簡潔易用的 Excel 數(shù)據(jù)對比工具,能夠高效地比較兩個 Excel 文件中的數(shù)據(jù)差異。
技術(shù)棧
PyQt5:用于構(gòu)建桌面 GUI(圖形用戶界面),提供友好的用戶交互界面。
pandas:處理 Excel 文件,進行數(shù)據(jù)對比。
openpyxl:用來處理 Excel 文件的寫入和樣式設置,導出比較結(jié)果。
QSS:通過自定義樣式表美化界面,提升用戶體驗。
2.功能使用
2.1 界面介紹
該工具的界面簡單直觀,包含以下主要部分:
文件選擇:用戶可以選擇需要比較的兩個 Excel 文件。
Sheet 選擇:加載 Excel 文件后,用戶可以選擇要比較的工作表。
列選擇:用戶選擇要進行對比的列,可以靈活選擇不同列的數(shù)據(jù)進行比對。
對比結(jié)果表格:展示對比結(jié)果,包括左側(cè)數(shù)據(jù)、右側(cè)數(shù)據(jù)、匹配狀態(tài)和內(nèi)容對比。若數(shù)據(jù)不匹配,相關行會高亮顯示。
操作按鈕:用戶可以點擊按鈕執(zhí)行對比操作、導出結(jié)果、重置界面和退出程序。
2.2 文件加載與工作表選擇
首先,用戶通過點擊“打開”按鈕選擇兩個 Excel 文件。文件選擇完成后,應用會自動讀取并展示文件中的所有工作表名稱,用戶可以從下拉框中選擇對應的工作表。
file_path, _ = QFileDialog.getOpenFileName(self, "選擇 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)")
列選擇與數(shù)據(jù)對比
用戶可以選擇要對比的列。點擊“開始對比”按鈕后,應用會依照選擇的列名對比兩個工作表中的數(shù)據(jù)。如果兩列數(shù)據(jù)一致,表格中會顯示“?”標記;若不一致,則顯示“?”標記,并高亮不匹配的行,詳細展示差異內(nèi)容。
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 "?"
導出結(jié)果
用戶對比完成后,可以通過“導出結(jié)果”按鈕將對比結(jié)果保存為新的 Excel 文件。保存時,程序會自動高亮不匹配的數(shù)據(jù)行,并將所有對比信息寫入到新文件中,便于后續(xù)查看與分析。
ws.append([left_data, right_data, match_status, compare_info])
重置與退出功能
程序提供了“重置界面”按鈕,用于清空當前選項和對比結(jié)果,方便用戶重新開始操作。同時,“退出程序”按鈕可以關閉應用。
代碼實現(xiàn)
上述功能的實現(xiàn)主要依賴于 PyQt5 和 pandas 庫。以下是部分關鍵代碼片段:
文件加載與數(shù)據(jù)讀取
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}")
數(shù)據(jù)對比與結(jié)果展示
def compare_data(self): left_col = self.left_column.currentText() right_col = self.right_column.currentText() # 讀取數(shù)據(jù) 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))
導出結(jié)果到 Excel
def export_results(self): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") file_path, _ = QFileDialog.getSaveFileName(self, "保存 Excel", f"對比結(jié)果_{timestamp}.xlsx", "Excel 文件 (*.xlsx)") if not file_path: return # 創(chuàng)建 Excel 文件并保存數(shù)據(jù) wb = openpyxl.Workbook() ws = wb.active ws.append(["左側(cè)數(shù)據(jù)", "右側(cè)數(shù)據(jù)", "匹配狀態(tài)", "內(nèi)容對比"]) 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.效果展示
4. 相關源碼
import sys import pandas as 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 PatternFill class ExcelComparator(QWidget): def __init__(self): super().__init__() self.initUI() # def initUI(self): self.setWindowTitle("Excel 數(shù)據(jù)對比工具") 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() # 文件選擇區(qū) file_layout = QHBoxLayout() self.left_label = QLabel("左側(cè)文件:") self.right_label = QLabel("右側(cè)文件:") 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 選擇區(qū) 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("左側(cè) Sheet:")) sheet_layout.addWidget(self.left_sheet) sheet_layout.addWidget(QLabel("右側(cè) Sheet:")) sheet_layout.addWidget(self.right_sheet) # 對比列選擇 column_layout = QHBoxLayout() self.left_column = QComboBox() self.right_column = QComboBox() column_layout.addWidget(QLabel("左側(cè)對比列:")) column_layout.addWidget(self.left_column) column_layout.addWidget(QLabel("右側(cè)對比列:")) column_layout.addWidget(self.right_column) # 結(jié)果表格 self.table = QTableWidget() self.table.setColumnCount(4) self.table.setHorizontalHeaderLabels(["左側(cè)數(shù)據(jù)", "右側(cè)數(shù)據(jù)", "匹配狀態(tài)", "內(nèi)容對比"]) # 操作按鈕 button_layout = QHBoxLayout() self.compare_btn = QPushButton("開始對比") self.export_btn = QPushButton("導出結(jié)果") 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"左側(cè)文件: {file_path}") self.left_file = file_path self.left_sheet.clear() else: self.right_label.setText(f"右側(cè)文件: {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 數(shù)據(jù): {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) # 左側(cè)數(shù)據(jù)列 if not self.table.item(row, 0): self.table.setItem(row, 0, QTableWidgetItem(left_value)) else: self.table.item(row, 0).setText(left_value) # 右側(cè)數(shù)據(jù)列 if not self.table.item(row, 1): self.table.setItem(row, 1, QTableWidgetItem(right_value)) else: self.table.item(row, 1).setText(right_value) # 匹配狀態(tài)列 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): # 增加第四列的信息對比內(nèi)容列表 if not self.table.item(row, col): self.table.setItem(row, col, QTableWidgetItem()) self.table.item(row, col).setBackground(QBrush(QColor(255, 150, 150))) # 對比內(nèi)容顯示 differences = f"左側(cè): {left_value} | 右側(cè): {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"對比結(jié)果_{timestamp}.xlsx", "Excel 文件 (*.xlsx)") if not file_path: return wb = openpyxl.Workbook() ws = wb.active ws.append(["左側(cè)數(shù)據(jù)", "右側(cè)數(shù)據(jù)", "匹配狀態(tài)", "內(nèi)容對比"]) red_fill = 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.總結(jié)
通過 PyQt5 和 pandas,我們快速實現(xiàn)了一個 Excel 數(shù)據(jù)對比工具,能夠高效地處理兩個 Excel 文件的內(nèi)容對比,并自動高亮顯示差異。此外,用戶可以方便地導出對比結(jié)果,以便后續(xù)的查看和分析。對于需要頻繁進行數(shù)據(jù)比對的工作人員而言,這款工具無疑能夠大幅度提高工作效率,減少人工錯誤。
在未來的版本中,可以考慮以下幾點擴展:
- 多列對比:支持用戶選擇多個列進行對比。
- 性能優(yōu)化:對于大數(shù)據(jù)量的 Excel 文件,可以優(yōu)化讀取和比較的速度。
- 自動化腳本:將此工具的功能封裝為命令行工具,便于批量處理。
通過不斷優(yōu)化與擴展,我們能夠?qū)⑦@款工具打造得更加完善,成為每位數(shù)據(jù)分析師和審計人員的得力助手。
到此這篇關于使用Python開發(fā)Excel表格數(shù)據(jù)對比工具的文章就介紹到這了,更多相關Python Excel數(shù)據(jù)對比內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python Matplotlib數(shù)據(jù)可視化模塊使用詳解
matplotlib是基建立在python之上,適用于創(chuàng)建靜態(tài),動畫和交互式可視化,通常與數(shù)據(jù)分析模塊pandas搭配使用,用于數(shù)據(jù)的分析和展示,適用于主流的操作系統(tǒng),如Linux、Win、Mac2022-11-11python爬蟲MeterSphere平臺執(zhí)行報告使用實戰(zhàn)
這篇文章主要為大家介紹了python爬蟲MeterSphere平臺執(zhí)行報告使用實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12pytest實戰(zhàn)技巧之參數(shù)化基本用法和多種方式
本文介紹了pytest參數(shù)化的基本用法和多種方式,幫助讀者更好地使用這個功能,同時,還介紹了一些高級技巧,如動態(tài)生成參數(shù)名稱、參數(shù)化的組合和動態(tài)生成參數(shù)化裝飾器,幫助讀者更靈活地使用參數(shù)化,感興趣的朋友參考下吧2023-12-12