【Word】用 Python 輕松實現 Word 文檔對比并生成可視化 HTML 報告

在日常工作和學習中,我們經常需要對兩個版本的文檔進行比對,比如合同修改、論文修訂、報告更新等。手動逐字檢查不僅耗時費力,還容易遺漏細節。

今天,我將帶你使用 Python + python-docx + difflib 實現一個自動化 Word 文檔對比工具,不僅能精準識別段落增刪改,還能生成美觀的 HTML 可視化報告,并自動在瀏覽器中打開查看!


🚀 項目效果預覽

運行腳本后:

  • 自動讀取兩個 .docx 文件
  • 按段落逐一對比內容差異
  • 生成一份 高亮標注差異 的 HTML 報告
  • 支持瀏覽器自動打開,無需手動查找文件

? 完全自動化 | ? 差異高亮顯示 | ? 支持中文 | ? 界面美觀專業


🛠? 技術棧簡介

技術作用
python-docx讀取 .docx 文件內容
difflib計算文本差異(增刪改)
webbrowser自動打開瀏覽器預覽結果
os / datetime文件路徑處理與時間戳記錄
原生 HTML + CSS生成結構清晰、樣式現代化的報告頁面

📂 核心功能解析

1?? 讀取 .docx 文件內容

from docx import Documentdef read_docx(file_path):"""讀取 .docx 文件,返回段落列表"""try:doc = Document(file_path)paragraphs = [para.text.strip() for para in doc.paragraphs if para.text.strip()]return paragraphsexcept Exception as e:print(f"? 讀取文件 {file_path} 時出錯: {e}")return []

📌 說明:

  • 使用 Document 加載 Word 文件
  • 提取所有非空段落,并去除首尾空格
  • 異常捕獲確保程序健壯性

2?? 利用 difflib 實現文本差異分析

matcher = difflib.SequenceMatcher(None, p1, p2)
opcodes = matcher.get_opcodes()

difflib.SequenceMatcher 是 Python 內置的強大工具,可以分析兩個字符串之間的差異操作(equal, insert, delete, replace),我們據此為每個字符添加 HTML 標簽高亮。

例如:

<span class='diff-delete'>[刪除: 這句話被刪了]</span>
<span class='diff-add'>[新增: 這是新內容]</span>

3?? 生成精美 HTML 報告

我們構建了一個完整的 HTML 頁面,包含:

? 響應式設計 + 現代化 UI 風格
  • 漸變標題欄
  • 圓角卡片式表格
  • 懸停交互效果
  • 適配中文字體
? 對比概覽區

顯示文件名、段落數量、生成時間等元信息。

? 詳細對比表格
段落文檔1內容文檔2內容差異狀態
第1段? 相同? 相同? 完全相同
第2段? 被刪除? 新增內容?? 內容有差異

每一段都用顏色區分:

  • 🟢 綠色:相同內容
  • 🔴 紅色:刪除或缺失
  • 🔵 藍色:新增內容
  • 🟡 黃色背景:整段新增/刪除

4?? 自動生成并打開報告

abs_path = os.path.abspath(report_path)
url = f"file://{abs_path}"
webbrowser.open(url)

一鍵生成報告后,自動調用系統默認瀏覽器打開,用戶體驗極佳!


💡 使用方法(超簡單)

步驟 1:安裝依賴

pip install python-docx

?? 注意:difflib 是標準庫,無需安裝。

步驟 2:修改主函數中的文件路徑

file1_path = r'C:\Users\Administrator\Desktop\11.docx'
file2_path = r'C:\Users\Administrator\Desktop\22docx.docx'file1_name = "11.docx (原文版)"
file2_name = "22docx.docx (對比版)"
output_html_file = "荷塘月色_對比報告.html"

📌 支持任意 .docx 文件,建議使用絕對路徑避免出錯。

步驟 3:運行腳本

python docx_compare.py

輸出示例:

🚀 正在啟動文檔對比程序...
============================================================
? 成功讀取文檔!? 11.docx (原文版) 共 15 段? 22docx.docx (對比版) 共 17 段
? HTML 報告已成功生成: '荷塘月色_對比報告.html'
🌐 報告已自動在默認瀏覽器中打開。

🖼? 報告截圖展示

在這里插入圖片描述
在這里插入圖片描述

  • 頂部標題:帶有時間戳和漸變背景
  • 對比表格:左右并列展示,差異高亮
  • 狀態標識:圖標+顏色提示,一目了然

📎 完整代碼下載

你可以將本文提供的完整代碼保存為 docx_compare.py,稍作配置即可使用。

import difflib
from docx import Document
import webbrowser
import os
from datetime import datetimedef read_docx(file_path):"""讀取 .docx 文件,返回段落列表"""try:doc = Document(file_path)paragraphs = [para.text.strip() for para in doc.paragraphs if para.text.strip()]return paragraphsexcept Exception as e:print(f"? 讀取文件 {file_path} 時出錯: {e}")return []def generate_html_report(paras1, paras2, file1_name, file2_name, output_html="對比報告.html"):"""根據對比結果生成 HTML 報告。"""# 構建 HTML 內容html_content = f"""<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>文檔對比報告</title><style>body {{font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;line-height: 1.8;color: #333;max-width: 1200px;margin: 0 auto;padding: 20px;background-color: #f9f9f9;}}.header {{text-align: center;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;padding: 30px 20px;border-radius: 10px;margin-bottom: 30px;box-shadow: 0 4px 6px rgba(0,0,0,0.1);}}.header h1 {{margin: 0;font-size: 2.5em;}}.header p {{margin: 10px 0 0;opacity: 0.9;}}.comparison-table {{width: 100%;border-collapse: collapse;margin: 20px 0;box-shadow: 0 2px 10px rgba(0,0,0,0.1);background-color: white;border-radius: 8px;overflow: hidden;}}.comparison-table th {{background-color: #4a5568;color: white;text-align: left;padding: 15px;font-weight: 600;}}.comparison-table td {{padding: 15px;border-bottom: 1px solid #e2e8f0;vertical-align: top;}}.comparison-table tr:nth-child(even) {{background-color: #f7fafc;}}.comparison-table tr:hover {{background-color: #ebf8ff;}}.diff-equal {{color: #22c55e;font-weight: 600;}}.diff-delete {{color: #e53e3e;font-weight: 600;}}.diff-add {{color: #3182ce;font-weight: 600;}}.context {{font-family: 'Courier New', monospace;background-color: #f1f5f9;padding: 10px;border-radius: 5px;white-space: pre-wrap;word-wrap: break-word;font-size: 0.95em;}}.footer {{text-align: center;margin-top: 40px;color: #718096;font-size: 0.9em;}}.highlight {{background-color: #fff3cd;padding: 2px 4px;border-radius: 3px;}}</style></head><body><div class="header"><h1>📄 文檔對比報告</h1><p>生成時間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p></div><h2>📊 對比概覽</h2><p><strong>文檔 1:</strong> {file1_name}</p><p><strong>文檔 2:</strong> {file2_name}</p><p><strong>段落數量:</strong> 文檔1: {len(paras1)} 段, 文檔2: {len(paras2)} 段</p><h2>🔍 詳細對比結果</h2><table class="comparison-table"><thead><tr><th>段落</th><th>{file1_name}</th><th>{file2_name}</th><th>差異狀態</th></tr></thead><tbody>"""max_len = max(len(paras1), len(paras2))for i in range(max_len):p1 = paras1[i] if i < len(paras1) else Nonep2 = paras2[i] if i < len(paras2) else None# 生成差異標記文本if p1 is not None and p2 is not None:matcher = difflib.SequenceMatcher(None, p1, p2)opcodes = matcher.get_opcodes()result1 = []result2 = []for tag, i1, i2, j1, j2 in opcodes:if tag == 'equal':result1.append(p1[i1:i2])result2.append(p2[j1:j2])elif tag == 'delete':result1.append(f"<span class='diff-delete'>[刪除: {p1[i1:i2]}]</span>")result2.append(f"<span class='diff-add'>[缺失]</span>")elif tag == 'insert':result1.append(f"<span class='diff-add'>[缺失]</span>")result2.append(f"<span class='diff-delete'>[新增: {p2[j1:j2]}]</span>")elif tag == 'replace':result1.append(f"<span class='diff-delete'>[刪除: {p1[i1:i2]}]</span>")result2.append(f"<span class='diff-add'>[新增: {p2[j1:j2]}]</span>")marked_p1 = ''.join(result1)marked_p2 = ''.join(result2)else:marked_p1 = p1 or "<span class='diff-add'>[該段落不存在]</span>"marked_p2 = p2 or "<span class='diff-add'>[該段落不存在]</span>"# 確定差異狀態if p1 is None:status = f"<span class='diff-add'>? 新增段落</span>"elif p2 is None:status = f"<span class='diff-delete'>? 刪除段落</span>"elif p1 == p2:status = f"<span class='diff-equal'>? 完全相同</span>"else:status = f"<span class='diff-delete'>?? 內容有差異</span>"# 添加到HTML表格中paragraph_num = f"第 {i+1} 段"html_content += f"""<tr><td><strong>{paragraph_num}</strong></td><td class="context">{marked_p1}</td><td class="context">{marked_p2}</td><td>{status}</td></tr>"""# 閉合HTML標簽html_content += f"""</tbody></table><div class="footer"><p>此報告由 Python 文檔對比工具自動生成</p></div></body></html>"""# 寫入文件try:with open(output_html, 'w', encoding='utf-8') as f:f.write(html_content)print(f"? HTML 報告已成功生成: '{output_html}'")return output_htmlexcept Exception as e:print(f"? 生成 HTML 文件時出錯: {e}")return Nonedef main():# 🔧 請修改為您的實際文件路徑file1_path = r'C:\Users\Administrator\Desktop\11.docx'file2_path = r'C:\Users\Administrator\Desktop\22docx.docx'# 自定義顯示名稱file1_name = "11.docx (原文版)"file2_name = "22docx.docx (對比版)"output_html_file = "荷塘月色_對比報告.html"print("🚀 正在啟動文檔對比程序...")print("=" * 60)# 讀取文檔paras1 = read_docx(file1_path)paras2 = read_docx(file2_path)if not paras1 or not paras2:print("? 文檔讀取失敗,請檢查文件。")returnprint(f"? 成功讀取文檔!")print(f"   ? {file1_name} 共 {len(paras1)} 段")print(f"   ? {file2_name} 共 {len(paras2)} 段")# 生成 HTML 報告report_path = generate_html_report(paras1, paras2, file1_name, file2_name, output_html_file)if report_path:# 獲取文件的絕對路徑abs_path = os.path.abspath(report_path)# 構造 file:// URLurl = f"file://{abs_path}"# 自動打開瀏覽器try:webbrowser.open(url)print(f"🌐 報告已自動在默認瀏覽器中打開。")except Exception as e:print(f"??  自動打開瀏覽器失敗,您可以手動打開文件:\n   {abs_path}")else:print("? 報告生成失敗。")if __name__ == "__main__":main()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94605.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94605.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94605.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從0開始搭建一個前端項目(vue + vite + typescript)

版本 node&#xff1a;v22.17.1 pnpm&#xff1a;v10.13.1 vue&#xff1a;^3.5.18 vite&#xff1a;^7.0.6 typescipt&#xff1a;~5.8.0腳手架初始化vue pnpm create vuelatest只選擇&#xff1a; TypeScript, JSX 3. 用vscode打開創建的項目&#xff0c;并刪除多余的代碼esl…

1.ImGui-環境安裝

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 本次游戲沒法給 內容參考于&#xff1a;微塵網絡安全 IMGUI是一個被廣泛應用到逆向里面的&#xff0c;它可以用來做外部的繪制&#xff0c;比如登錄界面&…

基于springboot的二手車交易系統

博主介紹&#xff1a;java高級開發&#xff0c;從事互聯網行業六年&#xff0c;熟悉各種主流語言&#xff0c;精通java、python、php、爬蟲、web開發&#xff0c;已經做了六年的畢業設計程序開發&#xff0c;開發過上千套畢業設計程序&#xff0c;沒有什么華麗的語言&#xff0…

修改win11任務欄時間字體和小圖標顏色

1 打開運行提示框 在桌面按快捷鍵winR&#xff0c;然后如下圖所示輸入regedit2 查找路徑 1、在路徑處粘貼路徑計算機\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize 2、如下圖所示&#xff0c;雙擊打開ColorPrevalence&#xff0c;將里面的…

第13集 當您的USB設備不在已實測支持列表,如何讓TOS-WLink支持您的USB設備--答案Wireshark USB抓包

問&#xff1a;當您的USB設備不在已實測支持列表&#xff0c;如何讓TOS-WLink支持您的USB設備&#xff1f; 答案&#xff1a;使用Wireshark USB抓包&#xff0c;日志發給我 為什么要抓包&#xff1a; USB設備種類繁多&#xff1b;TOS-WLink是單片機&#xff0c;內存緊張&#…

[靈動微電子 MM32BIN560CN MM32SPIN0280]讀懂電機MCU之比較器

作為剛接觸微控制器的初學者&#xff0c;在看到MM32SPIN0280用戶手冊中“比較器”相關內容時&#xff0c;是不是會感到困惑&#xff1f;比如“5個通用比較器”“輪詢功能”“遲滯電壓”這些術語&#xff0c;好像都和電機控制有關&#xff0c;但又不知道具體怎么用。別擔心&…

? 貳 ? ? 安全架構:數字銀行安全體系規劃

&#x1f44d;點「贊」&#x1f4cc;收「藏」&#x1f440;關「注」&#x1f4ac;評「論」 &#x1f525;更多文章戳&#x1f449;Whoami&#xff01;-CSDN博客&#x1f680; 在金融科技深度融合的背景下&#xff0c;信息安全已從單純的技術攻防擴展至架構、合規、流程與創新的…

布隆過濾器完全指南:從原理到實戰

布隆過濾器完全指南:從原理到實戰 摘要:本文深入解析布隆過濾器的核心原理、實現細節和實際應用,提供完整的Java實現代碼,并探討性能優化策略。適合想要深入理解概率數據結構的開發者閱讀。 前言 在大數據時代,如何快速判斷一個元素是否存在于海量數據集合中?傳統的Hash…

?嵌入式Linux學習 - 網絡服務器實現與客戶端的通信

1.單循環服務器 2.并發服務器 1. 設置socket屬性 2. 進程 ?3. 線程 3.多路IO復用模型 - 提高并發程度 1. 區別 2. IO處理模型 1. 阻塞IO模型 2. 非阻塞IO模型 3. 信號驅動IO 4. IO多路復用 3. 特點 4. 函數接口 1. select 2. poll 3. epoll 半包 1.單循環服務…

Mybatis中緩存機制的理解以及優缺點

文章目錄一、MyBatis 緩存機制詳解1. 一級緩存&#xff08;Local Cache&#xff09;2. 二級緩存&#xff08;Global Cache&#xff09;3. 緩存執行順序二、MyBatis 緩存的優點三、MyBatis 緩存的缺點四、適用場景與最佳實踐總結MyBatis 提供了完善的緩存機制&#xff0c;用于減…

Rust 登堂 之 類型轉換(三)

Rust 是類型安全的語言&#xff0c;因此在Rust 中做類型轉換不是一件簡單的事&#xff0c;這一章節&#xff0c;我們將對Rust 中的類型轉換進行詳盡講解。 高能預警&#xff0c;本章節有些難&#xff0c;可以考慮學了進階后回頭再看 as 轉換 先來看一段代碼 fn main() {let a…

【MySQL 為什么默認會給 id 建索引? MySQL 主鍵索引 = 聚簇索引?】

MySQL 索引 MySQL 為什么默認會給 id 建索引&#xff1f; & MySQL 主鍵索引 聚簇索引&#xff1f; 結論&#xff1a;在 MySQL (InnoDB) 中&#xff0c;主鍵索引是自動創建的聚簇索引&#xff0c;不需要刪除&#xff0c;其他索引是補充優化。 1. MySQL 的id 索引是怎么來的…

[光學原理與應用-321]:皮秒深紫外激光器產品不同階段使用的工具軟件、對應的輸出文件

在皮秒深紫外激光器的開發過程中&#xff0c;不同階段使用的工具軟件及其對應的輸出文件如下&#xff1a;一、設計階段工具軟件&#xff1a;Zemax OpticStudio&#xff1a;用于光學系統的初步設計和仿真&#xff0c;包括光線追跡、像差分析、優化設計等。MATLAB&#xff1a;用于…

openEuler常用操作指令

openEuler常用操作指令 一、前言 1.簡介 openEuler是由開放原子開源基金會孵化的全場景開源操作系統項目&#xff0c;面向數字基礎設施四大核心場景&#xff08;服務器、云計算、邊緣計算、嵌入式&#xff09;&#xff0c;全面支持ARM、x86、RISC-V、loongArch、PowerPC、SW…

Python爬蟲實戰:構建網易云音樂個性化音樂播放列表同步系統

1. 引言 1.1 研究背景 在數字音樂生態中,各大音樂平臺憑借獨家版權、個性化推薦等優勢占據不同市場份額。根據國際唱片業協會(IFPI)2024 年報告,全球流媒體音樂用戶已突破 50 億,其中超過 60% 的用戶同時使用 2 個及以上音樂平臺。用戶在不同平臺積累的播放列表包含大量…

vscode 配置 + androidStudio配置

插件代碼片段 餓了么 icon{"Print to console": {"prefix": "ii-ep-","body": ["i-ep-"],"description": "elementPlus Icon"} }Ts 初始化模版{"Print to console": {"prefix": &q…

DQN(深度Q網絡):深度強化學習的里程碑式突破

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; ? 1. DQN概述&#xff1a;當深度學習遇見強化學習 DQN&#xff08;D…

個人博客運行3個月記錄

個人博客 自推一波&#xff0c;目前我的Hexo個人博客已經優化的足夠好了&#xff0c; 已經足夠穩定的和簡單進行發布和管理&#xff0c;但還是有不少問題&#xff0c;總之先記下來再說 先總結下 關于評論系統方面&#xff0c;我從Waline (快速上手 | Waline) 更換成了&#x…

C89標準關鍵字以及運算符分類匯總

開發單片機項目學好C語言尤其重要&#xff0c;我感覺學習C語言需要先學好關鍵字和運算符&#xff0c;我對C語言的關鍵字和運算符做一下匯總。一、關鍵字&#xff1a;&#xff08;C89標準一共有32個關鍵字&#xff09;(1) 數據類型關鍵字&#xff08;一共12個&#xff0c;分為基…

吱吱企業通訊軟件打破跨部門溝通壁壘,為企業搭建安全的通訊環境

在數字化轉型浪潮中&#xff0c;企業通訊軟件不再僅僅作為企業跨部門溝通橋梁&#xff0c;更是承載著保護通訊數據安全的使命。吱吱企業通訊憑借其“私有化部署全鏈路加密”雙重機制&#xff0c;為企業構建了一套“溝通便捷、通訊安全”的數字化通訊解決方案。 一、打破溝通壁壘…