最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python輕松實(shí)現(xiàn)Word文檔對(duì)比并生成可視化HTML報(bào)告

 更新時(shí)間:2025年08月29日 08:22:18   作者:幸福清風(fēng)  
在日常工作和學(xué)習(xí)中,我們經(jīng)常需要對(duì)兩個(gè)版本的文檔進(jìn)行比對(duì),本文將使用 Python + python-docx + difflib 實(shí)現(xiàn)一個(gè)自動(dòng)化 Word 文檔對(duì)比工具,感興趣的可以了解下

在日常工作和學(xué)習(xí)中,我們經(jīng)常需要對(duì)兩個(gè)版本的文檔進(jìn)行比對(duì),比如合同修改、論文修訂、報(bào)告更新等。手動(dòng)逐字檢查不僅耗時(shí)費(fèi)力,還容易遺漏細(xì)節(jié)。

今天,我將帶你使用 Python + python-docx + difflib 實(shí)現(xiàn)一個(gè)自動(dòng)化 Word 文檔對(duì)比工具,不僅能精準(zhǔn)識(shí)別段落增刪改,還能生成美觀的 HTML 可視化報(bào)告,并自動(dòng)在瀏覽器中打開查看!

項(xiàng)目效果預(yù)覽

運(yùn)行腳本后:

  • 自動(dòng)讀取兩個(gè) .docx 文件
  • 按段落逐一對(duì)比內(nèi)容差異
  • 生成一份 高亮標(biāo)注差異 的 HTML 報(bào)告
  • 支持瀏覽器自動(dòng)打開,無需手動(dòng)查找文件

完全自動(dòng)化 | 差異高亮顯示 |  支持中文 | 界面美觀專業(yè)

技術(shù)棧簡介

技術(shù)作用
python-docx讀取 .docx 文件內(nèi)容
difflib計(jì)算文本差異(增刪改)
webbrowser自動(dòng)打開瀏覽器預(yù)覽結(jié)果
os / datetime文件路徑處理與時(shí)間戳記錄
原生 HTML + CSS生成結(jié)構(gòu)清晰、樣式現(xiàn)代化的報(bào)告頁面

核心功能解析

讀取.docx文件內(nèi)容

from docx import Document

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

說明:

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

利用difflib實(shí)現(xiàn)文本差異分析

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

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

例如:

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

生成精美 HTML 報(bào)告

我們構(gòu)建了一個(gè)完整的 HTML 頁面,包含:

響應(yīng)式設(shè)計(jì) + 現(xiàn)代化 UI 風(fēng)格

  • 漸變標(biāo)題欄
  • 圓角卡片式表格
  • 懸停交互效果
  • 適配中文字體

對(duì)比概覽區(qū)

顯示文件名、段落數(shù)量、生成時(shí)間等元信息。

詳細(xì)對(duì)比表格

段落文檔1內(nèi)容文檔2內(nèi)容差異狀態(tài)
第1段相同相同完全相同
第2段被刪除新增內(nèi)容內(nèi)容有差異

每一段都用顏色區(qū)分:

  • 綠色:相同內(nèi)容
  • 紅色:刪除或缺失
  • 藍(lán)色:新增內(nèi)容
  • 黃色背景:整段新增/刪除

自動(dòng)生成并打開報(bào)告

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

一鍵生成報(bào)告后,自動(dòng)調(diào)用系統(tǒng)默認(rèn)瀏覽器打開,用戶體驗(yàn)極佳!

使用方法(超簡單)

步驟 1:安裝依賴

pip install python-docx

注意:difflib 是標(biāo)準(zhǔn)庫,無需安裝。

步驟 2:修改主函數(shù)中的文件路徑

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 (對(duì)比版)"
output_html_file = "荷塘月色_對(duì)比報(bào)告.html"

支持任意 .docx 文件,建議使用絕對(duì)路徑避免出錯(cuò)。

步驟 3:運(yùn)行腳本

python docx_compare.py

輸出示例:

?? 正在啟動(dòng)文檔對(duì)比程序...
============================================================
? 成功讀取文檔!
   • 11.docx (原文版) 共 15 段
   • 22docx.docx (對(duì)比版) 共 17 段
? HTML 報(bào)告已成功生成: '荷塘月色_對(duì)比報(bào)告.html'
?? 報(bào)告已自動(dòng)在默認(rèn)瀏覽器中打開。

報(bào)告截圖展示

  • 頂部標(biāo)題:帶有時(shí)間戳和漸變背景
  • 對(duì)比表格:左右并列展示,差異高亮
  • 狀態(tài)標(biāo)識(shí):圖標(biāo)+顏色提示,一目了然

完整代碼下載

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

import difflib
from docx import Document
import webbrowser
import os
from datetime import datetime

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

def generate_html_report(paras1, paras2, file1_name, file2_name, output_html="對(duì)比報(bào)告.html"):
    """
    根據(jù)對(duì)比結(jié)果生成 HTML 報(bào)告。
    """
    # 構(gòu)建 HTML 內(nèi)容
    html_content = f"""
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>文檔對(duì)比報(bào)告</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>?? 文檔對(duì)比報(bào)告</h1>
            <p>生成時(shí)間: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
        </div>

        <h2>?? 對(duì)比概覽</h2>
        <p><strong>文檔 1:</strong> {file1_name}</p>
        <p><strong>文檔 2:</strong> {file2_name}</p>
        <p><strong>段落數(shù)量:</strong> 文檔1: {len(paras1)} 段, 文檔2: {len(paras2)} 段</p>

        <h2>?? 詳細(xì)對(duì)比結(jié)果</h2>
        <table class="comparison-table">
            <thead>
                <tr>
                    <th>段落</th>
                    <th>{file1_name}</th>
                    <th>{file2_name}</th>
                    <th>差異狀態(tài)</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 None
        p2 = paras2[i] if i < len(paras2) else None

        # 生成差異標(biāo)記文本
        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>"

        # 確定差異狀態(tài)
        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'>?? 內(nèi)容有差異</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標(biāo)簽
    html_content += f"""
            </tbody>
        </table>

        <div class="footer">
            <p>此報(bào)告由 Python 文檔對(duì)比工具自動(dòng)生成</p>
        </div>
    </body>
    </html>
    """

    # 寫入文件
    try:
        with open(output_html, 'w', encoding='utf-8') as f:
            f.write(html_content)
        print(f"? HTML 報(bào)告已成功生成: '{output_html}'")
        return output_html
    except Exception as e:
        print(f"? 生成 HTML 文件時(shí)出錯(cuò): {e}")
        return None

def main():
    # ?? 請(qǐng)修改為您的實(shí)際文件路徑
    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 (對(duì)比版)"
    output_html_file = "荷塘月色_對(duì)比報(bào)告.html"

    print("?? 正在啟動(dòng)文檔對(duì)比程序...")
    print("=" * 60)

    # 讀取文檔
    paras1 = read_docx(file1_path)
    paras2 = read_docx(file2_path)

    if not paras1 or not paras2:
        print("? 文檔讀取失敗,請(qǐng)檢查文件。")
        return

    print(f"? 成功讀取文檔!")
    print(f"   ? {file1_name} 共 {len(paras1)} 段")
    print(f"   ? {file2_name} 共 {len(paras2)} 段")

    # 生成 HTML 報(bào)告
    report_path = generate_html_report(paras1, paras2, file1_name, file2_name, output_html_file)

    if report_path:
        # 獲取文件的絕對(duì)路徑
        abs_path = os.path.abspath(report_path)
        # 構(gòu)造 file:// URL
        url = f"file://{abs_path}"
        # 自動(dòng)打開瀏覽器
        try:
            webbrowser.open(url)
            print(f"?? 報(bào)告已自動(dòng)在默認(rèn)瀏覽器中打開。")
        except Exception as e:
            print(f"??  自動(dòng)打開瀏覽器失敗,您可以手動(dòng)打開文件:\n   {abs_path}")
    else:
        print("? 報(bào)告生成失敗。")

if __name__ == "__main__":
    main()

以上就是Python輕松實(shí)現(xiàn)Word文檔對(duì)比并生成可視化HTML報(bào)告的詳細(xì)內(nèi)容,更多關(guān)于Python對(duì)比Word文檔的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python Pandas describe()函數(shù)的使用詳解

    Python Pandas describe()函數(shù)的使用詳解

    pandas庫中的describe()函數(shù)為我們提供了這樣的功能,它可以快速生成數(shù)據(jù)集的描述性統(tǒng)計(jì)信息,這篇文章主要介紹了Python Pandas describe()函數(shù)的使用介紹,需要的朋友可以參考下
    2024-05-05
  • 快速解決pyqt5窗體關(guān)閉后子線程不同時(shí)退出的問題

    快速解決pyqt5窗體關(guān)閉后子線程不同時(shí)退出的問題

    今天小編就為大家分享一篇快速解決pyqt5窗體關(guān)閉后子線程不同時(shí)退出的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Pycharm中切換pytorch的環(huán)境和配置的教程詳解

    Pycharm中切換pytorch的環(huán)境和配置的教程詳解

    這篇文章主要介紹了Pycharm中切換pytorch的環(huán)境和配置,本文給大家介紹的非常詳細(xì),對(duì)大家的工作或?qū)W習(xí)具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Pandas中八個(gè)常用option設(shè)置的示例詳解

    Pandas中八個(gè)常用option設(shè)置的示例詳解

    通過pandas的使用,我們經(jīng)常要交互式地展示表格(dataframe)、分析表格。本文整理了8個(gè)常用的配置選項(xiàng),使用可以提高很多效率,需要的可以參考一下
    2022-06-06
  • python中的np.round()函數(shù)示例詳解

    python中的np.round()函數(shù)示例詳解

    np.round()是NumPy庫中的一個(gè)函數(shù),用于對(duì)數(shù)組或單個(gè)數(shù)值進(jìn)行四舍五入,該函數(shù)返回一個(gè)與輸入類型相同的數(shù)組或數(shù)值,并可以通過可選的參數(shù)來指定保留的小數(shù)位數(shù),這篇文章主要介紹了python中的np.round()函數(shù),需要的朋友可以參考下
    2024-06-06
  • python執(zhí)行數(shù)據(jù)庫的查詢操作實(shí)例講解

    python執(zhí)行數(shù)據(jù)庫的查詢操作實(shí)例講解

    在本篇文章里小編給大家整理了一篇關(guān)于python執(zhí)行數(shù)據(jù)庫的查詢操作實(shí)例講解內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2021-10-10
  • Python實(shí)現(xiàn)基于HTTP文件傳輸實(shí)例

    Python實(shí)現(xiàn)基于HTTP文件傳輸實(shí)例

    這篇文章主要介紹了Python實(shí)現(xiàn)基于HTTP文件傳輸?shù)姆椒?以實(shí)例形式詳細(xì)講述了server端與client端的實(shí)現(xiàn)代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-11-11
  • Python利用matplotlib模塊數(shù)據(jù)可視化繪制3D圖

    Python利用matplotlib模塊數(shù)據(jù)可視化繪制3D圖

    matplotlib是python最著名的繪圖庫,它提供了一整套和matlab相似的命令A(yù)PI,十分適合交互式地行制圖,下面這篇文章主要給大家介紹了關(guān)于Python利用matplotlib模塊數(shù)據(jù)可視化實(shí)現(xiàn)3D圖的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • python文件編寫好后如何實(shí)踐

    python文件編寫好后如何實(shí)踐

    在本篇文章里小編給大家分享了關(guān)于python文件編寫好后如何實(shí)踐的相關(guān)內(nèi)容,需要的朋友們可以參考下。
    2020-07-07
  • Python調(diào)用接口合并Excel表代碼實(shí)例

    Python調(diào)用接口合并Excel表代碼實(shí)例

    這篇文章主要介紹了Python調(diào)用接口合并Excel表代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論

崇明县| 漯河市| 观塘区| 叶城县| 巴林右旗| 合肥市| 开远市| 神木县| 蛟河市| 于都县| 福建省| 丰城市| 旌德县| 林甸县| 古浪县| 潜山县| 定州市| 天柱县| 项城市| 平乡县| 巴东县| 屏边| 汤原县| 裕民县| 利津县| 辽中县| 瑞丽市| 湘潭市| 文昌市| 左云县| 营山县| 琼结县| 华安县| 鲁甸县| 石楼县| 灌阳县| 隆安县| 台北县| 体育| 抚顺市| 南通市|