Python3使用win32com從Excel讀取數(shù)據(jù)生成Word格式報(bào)告批量發(fā)郵件的示例詳解
什么是 win32com
win32com是 Python 在 Windows 平臺(tái)上一種用于訪問 COM(Component Object Model) 對象的庫/模塊。它隸屬于第三方擴(kuò)展包 pywin32(也就是我們通常安裝的 “pywin32” 庫)的一部分。- 借助 win32com,Python 腳本可以與 Windows 系統(tǒng)的底層組件或支持 COM 接口的應(yīng)用程序通信,并操控它們 —— 比如常見的辦公軟件(如 Excel、Word、Outlook)、以及其他支持 COM 的軟件。這樣就能通過 Python 自動(dòng)化許多原本依賴鼠標(biāo)/鍵盤/手動(dòng)操作的流程。
簡言之,win32com 讓 Python “變身”為 Windows 的自動(dòng)化驅(qū)動(dòng) — 就像用 Python 寫 VBA,但更靈活、功能更強(qiáng)大。
如何安裝與導(dǎo)入
首先確保你的環(huán)境是 Windows + Python3。
使用 pip 安裝 pywin32:
pip install pywin32
安裝后,就包含了 win32com 模塊。
在腳本中導(dǎo)入需要的模塊/子模塊,例如:
import win32com.client
如果你嘗試 import win32com 后報(bào)錯(cuò) “No module named ‘win32com’”,通常是因?yàn)闆]有正確安裝 pywin32,或安裝在與當(dāng)前 Python 解釋器不一致的環(huán)境里。
安裝完成并正確導(dǎo)入后,你就可以使用 win32com 來創(chuàng)建/連接 COM 對象。
基本使用 — 操作 Excel、Word 等 Office 應(yīng)用
下面是一些最常見、最基礎(chǔ)的用法示例。假設(shè)你已經(jīng)安裝好 Microsoft Office(或兼容 Office 的軟件,如 WPS),并在 Windows 系統(tǒng)上運(yùn)行。
操作 Excel 示例
import win32com.client
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True # 可見 Excel 窗口(方便調(diào)試/查看效果)
workbook = excel.Workbooks.Add()
sheet = workbook.Worksheets(1)
sheet.Cells(1, 1).Value = "Hello"
sheet.Cells(1, 2).Value = "World"
sheet.Cells(2, 1).Value = "Python"
sheet.Cells(2, 2).Value = "win32com"
workbook.SaveAs(r"C:\path\to\your\file.xlsx")
workbook.Close(False)
excel.Quit()
這段代碼會(huì):
- 啟動(dòng) Excel(COM 自動(dòng)化方式)
- 新建一個(gè)工作簿
- 獲取第一個(gè)工作表
- 向若干個(gè)單元格寫入數(shù)據(jù)
- 保存為
.xlsx文件 - 關(guān)閉 workbook 和 Excel 應(yīng)用程序
通過這種方式,你可以讓 Python 完全代替人工在 Excel 中輸入、保存、關(guān)閉操作。
操作 Word 示例
import win32com.client
word = win32com.client.Dispatch("Word.Application")
word.Visible = True
doc = word.Documents.Add()
rng = doc.Range(0, 0)
rng.Text = "這是由 python + win32com 自動(dòng)生成的 Word 文檔內(nèi)容。\n"
doc.SaveAs(r"C:\path\to\your\file.docx")
doc.Close(False)
word.Quit()
這會(huì):
- 啟動(dòng) Word
- 新建一個(gè)文檔
- 在開頭插入一段文本
- 保存為
.docx文件 - 關(guān)閉文檔和 Word
相比于 Python 其他庫(如專門操作 docx 的第三方庫),使用 win32com 的優(yōu)勢在于可以直接操控完整的 Word 功能,包括對舊版 .doc、宏、樣式、復(fù)雜格式的支持(前提是目標(biāo) Word 版本支持這些功能)。
win32com 的能力遠(yuǎn)不止基本讀寫 — 更多高級應(yīng)用 & 注意事項(xiàng)
更強(qiáng)的自動(dòng)化/擴(kuò)展能力
除了讀寫 Excel、Word,還可以:
- 操控 PowerPoint、Outlook、甚至其他支持 COM 的軟件。理論上,只要目標(biāo)軟件注冊了 COM 接口,都可以通過
win32com.client.Dispatch("YourApp.ProgID")來連接。 - 對 Excel 文檔進(jìn)行宏(VBA)操作 —— 通過
win32com可以操控 VBA 模塊,讀寫/導(dǎo)入/導(dǎo)出/執(zhí)行宏腳本,這對于復(fù)雜自動(dòng)化任務(wù)非常有用。 - 利用 COM 的事件機(jī)制 —— 通過
DispatchWithEvents結(jié)合相應(yīng)的事件處理類,可以讓 Python 監(jiān)聽并處理某些應(yīng)用(如 Word/Excel)的事件(例如“新建文檔”“退出程序”等)。 - 用于其他 Windows 應(yīng)用或第三方工具(只要其提供 COM 接口):例如科學(xué)儀器、工程軟件、老舊系統(tǒng)等,與其內(nèi)部 COM 接口對接,實(shí)現(xiàn)腳本自動(dòng)化/數(shù)據(jù)導(dǎo)出/批處理等功能。
注意事項(xiàng)與局限
- 僅 Windows 有效。因?yàn)?COM 是 Windows 特有的組件模型,在 Linux / macOS 下 win32com 通常無法使用。
- 依賴目標(biāo)軟件是否支持 COM 自動(dòng)化 —— 如果目標(biāo)程序沒有對外提供 COM 接口,就無法通過 win32com 控制它。
- 多線程時(shí)要小心。如果在多線程環(huán)境中調(diào)用 COM 對象,需要為每個(gè)線程單獨(dú)初始化 COM 庫,否則可能報(bào)錯(cuò)例如 “尚未調(diào)用 CoInitialize”。
- COM 操作不當(dāng)可能導(dǎo)致程序掛起。比如啟動(dòng)了某個(gè)應(yīng)用后忘記
Quit(),可能會(huì)導(dǎo)致后臺(tái)進(jìn)程殘留。良好的資源管理和異常處理非常重要。
適合用 win32com 的場景 / 推薦理由
| 場景 / 需求 | 為什么推薦 win32com |
|---|---|
| Excel/Word 等 Office 自動(dòng)化(批量生成、報(bào)表、郵件合并等) | 可以通過腳本完全自動(dòng)化操作 Office,效率高、功能強(qiáng) |
| 老舊 Office 格式(.doc、.xls)或需要宏/VBA 支持 | 支持 COM/VBA,比很多現(xiàn)代庫兼容性更好 |
| Windows 專用軟件自動(dòng)化/批處理(比如批量生成報(bào)告、儀器控制、與其他軟件對接) | 只要軟件支持 COM,就能用 Python 控制,靈活性強(qiáng) |
| 不想手寫 VBA/不熟悉 VBA,但熟悉 Python | Python 更易讀寫、更便于與其他 Python 模塊整合 |
一個(gè)稍復(fù)雜的處理Excel的完整 Demo(Excel + VBA 宏 + 錯(cuò)誤處理 + 清理)
import win32com.client
import pythoncom
import os
import sys
def main():
try:
excel = win32com.client.DispatchEx("Excel.Application")
excel.Visible = False
excel.DisplayAlerts = False
wb = excel.Workbooks.Add()
sheet = wb.Worksheets(1)
sheet.Name = "Data"
# 寫一些示例數(shù)據(jù)
for i in range(1, 6):
sheet.Cells(i, 1).Value = f"Row {i}"
sheet.Cells(i, 2).Value = i * 10
# 假設(shè)你有一個(gè) VBA 宏模塊,想插入并運(yùn)行
# 例如,導(dǎo)出數(shù)據(jù)、生成圖表、格式化等
# wb.VBProject.VBComponents.Add(...) # 插入模塊
# wb.Application.Run("YourMacroName")
out_path = os.path.join(os.getcwd(), "output.xlsx")
wb.SaveAs(out_path)
print("Saved to", out_path)
except Exception as e:
print("Error:", e)
finally:
try:
wb.Close(False)
except Exception:
pass
try:
excel.Quit()
except Exception:
pass
if __name__ == "__main__":
# 在一些環(huán)境下,多線程或腳本打包需要初始化 COM
pythoncom.CoInitialize()
main()
pythoncom.CoUninitialize()
這個(gè)腳本展示了如何:
- 使用
DispatchEx啟動(dòng) Excel(相比Dispatch更獨(dú)立,不會(huì)復(fù)用已有 Excel 進(jìn)程) - 寫入數(shù)據(jù)
- (可選)插入/執(zhí)行 VBA 宏
- 捕獲異常,保證出錯(cuò)后也能關(guān)閉/清理資源
- 最終保存并退出
示例:從Excel讀取數(shù)據(jù)生成Word格式報(bào)告批量發(fā)郵件
結(jié)合 Microsoft Excel、Microsoft Word 和 Microsoft Outlook 來實(shí)現(xiàn):從 Excel 讀取數(shù)據(jù) → 生成 Word 報(bào)告 → 附件 + 發(fā)郵件。適合用于“自動(dòng)生成報(bào)告 + 郵件發(fā)送”的辦公自動(dòng)化流程。
準(zhǔn)備條件
Windows 系統(tǒng) + 本地安裝 Office(Excel, Word, Outlook)
已安裝 pywin32:
pip install pywin32
```:contentReference[oaicite:5]{index=5}
Excel 中有一個(gè)表格(比如 .xlsx),包含你希望寫入 Word 報(bào)告并作為附件發(fā)送給某人的數(shù)據(jù)
示例腳本:從 Excel 到 Word,再通過 Outlook 發(fā)郵件
import os
import win32com.client
import pythoncom # 如果在腳本 / 多線程 /定時(shí)任務(wù)中運(yùn)行,推薦初始化 COM
def make_word_report(data_rows, output_docx_path):
"""
data_rows: list of dict,每個(gè) dict 對應(yīng)一行,key 是列名
output_docx_path: Word 文檔保存路徑
"""
word = win32com.client.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Add()
# 寫入標(biāo)題
doc.Content.InsertAfter("自動(dòng)生成報(bào)告\n")
doc.Content.InsertAfter("====================\n\n")
# 寫入表格/數(shù)據(jù)(簡單示例)
for row in data_rows:
# 假設(shè) row 是 dict,按順序?qū)?
line = ", ".join(f"{k}: {v}" for k, v in row.items())
doc.Content.InsertAfter(line + "\n")
doc.SaveAs(output_docx_path)
doc.Close(False)
word.Quit()
def read_excel_data(excel_path, sheet_name=None):
"""
簡單讀取 Excel,通過 COM 控件,也可以用 pandas/openpyxl,再包裝成 dict list
這里假設(shè)你能用其他方式讀取 Excel,示例用 pandas 更方便
"""
import pandas as pd
df = pd.read_excel(excel_path, sheet_name=sheet_name)
df = df.fillna("") # 可選:替換空值
records = df.to_dict(orient="records")
return records
def send_email_with_attachment(to_email, subject, body, attachment_paths=None):
outlook = win32com.client.Dispatch("Outlook.Application")
mail = outlook.CreateItem(0) # 0 表示 olMailItem
mail.To = to_email
mail.Subject = subject
mail.Body = body
if attachment_paths:
for path in attachment_paths:
if os.path.exists(path):
mail.Attachments.Add(path)
else:
print(f"[Warning] 附件文件不存在: {path}")
mail.Send()
def main():
pythoncom.CoInitialize()
# --- 配置區(qū) ---
excel_path = r"C:\path\to\your\data.xlsx"
word_report_path = r"C:\path\to\your\report.docx"
recipient = "recipient@example.com"
email_subject = "自動(dòng)生成報(bào)告 - " + os.path.basename(word_report_path)
email_body = "你好,\n\n請查收自動(dòng)生成的報(bào)告。如有問題,請回復(fù)。\n\nRegards."
# 1. 讀取 Excel
data = read_excel_data(excel_path)
# 2. 生成 Word 報(bào)告
make_word_report(data, word_report_path)
# 3. 發(fā)送郵件(帶上 Word 報(bào)告作為附件)
send_email_with_attachment(
to_email=recipient,
subject=email_subject,
body=email_body,
attachment_paths=[word_report_path]
)
pythoncom.CoUninitialize()
if __name__ == "__main__":
main()
說明與注意事項(xiàng)
- 我用了
pythoncom.CoInitialize()/CoUninitialize()來確保 COM 正確初始化/釋放 — 這是在腳本、服務(wù)、線程、定時(shí)任務(wù)里比較推薦的寫法。 - Excel 數(shù)據(jù)讀取部分我用了
pandas+openpyxl,這樣比用 COM 操作 Excel 更簡單可靠。你也可以根據(jù)需要改成 COM 方式。 - Word 報(bào)告非?;A(chǔ):只是逐行插入文本。如果需要更復(fù)雜的格式、表格、樣式、圖片,你可以用 Word COM 對象模型進(jìn)一步擴(kuò)展。COM 操作 Word 的能力比較完整。
- 發(fā)郵件部分通過 Outlook COM 自動(dòng)創(chuàng)建郵件、添加附件并發(fā)送。這樣一來你就實(shí)現(xiàn)了“讀取數(shù)據(jù) → 生成報(bào)告 → 郵件發(fā)送”的一條完整自動(dòng)化鏈。
進(jìn)階示例:支持 Excel 多行/多收件人+Word 報(bào)告?zhèn)€性化+郵件 HTML 格式+日志/異常處理 的腳本
實(shí)現(xiàn)以下功能 —— 從 Excel 讀取多條記錄 → 為每條記錄生成特定附件 (Excel/Word) 或內(nèi)容 → 通過 Microsoft Outlook 群發(fā)帶附件/HTML 正文郵件 → 支持日志與異常處理。你可以直接拿來改造/運(yùn)行。
import os
import traceback
import pandas as pd
import win32com.client
import pythoncom
from pathlib import Path
# --- 配置區(qū) ---
EXCEL_DATA_FILE = r"C:\path\to\your\recipients_and_data.xlsx"
OUTPUT_DIR = r"C:\path\to\output" # 存放生成的附件、報(bào)告等
LOG_FILE = os.path.join(OUTPUT_DIR, "send_mail.log")
EMAIL_COLUMN = "email" # Excel 表格中收件人郵箱地址所在列名
CC_COLUMN = "cc" # 可選:抄送人列名(若無,可設(shè)為 None)
SUBJECT_COLUMN = "subject" # 郵件主題列名
BODY_COLUMN = "body_html" # 郵件 HTML 正文列名(可設(shè) body_text 替代純文本)
ATTACHMENT_COLUMN = "attachment_path"
# 如果每行有自己附件路徑,可放在這一列;也可以留空,然后你自己動(dòng)態(tài)生成
# --- 輔助函數(shù) ---
def log(msg):
with open(LOG_FILE, 'a', encoding='utf-8') as f:
f.write(msg + "\n")
print(msg)
def ensure_folder(path: str):
if not os.path.isdir(path):
os.makedirs(path, exist_ok=True)
def read_data():
df = pd.read_excel(EXCEL_DATA_FILE, dtype=str)
df = df.fillna("") # 將 NaN 轉(zhuǎn)為空字符串
return df.to_dict(orient="records")
def create_custom_attachment(row: dict) -> str:
"""
如果你希望根據(jù)每行數(shù)據(jù)生成自定義附件(Excel、Word、PDF...等),
在這里實(shí)現(xiàn)生成邏輯,并返回文件路徑;若已有附件路徑,可直接返回 row[ATTACHMENT_COLUMN]
"""
# 示例:假設(shè)已有附件路徑
path = row.get(ATTACHMENT_COLUMN, "").strip()
if path and os.path.isfile(path):
return path
# 否則 —— 舉例,生成一個(gè)簡單 txt 報(bào)告
fn = os.path.join(OUTPUT_DIR, f"report_for_{row.get('id', '')}.txt")
with open(fn, 'w', encoding='utf-8') as f:
f.write("Report for: " + row.get(EMAIL_COLUMN, "") + "\n")
# 根據(jù)實(shí)際字段寫內(nèi)容
for k, v in row.items():
f.write(f"{k} = {v}\n")
return fn
def send_mail_via_outlook(to_addr: str, subject: str, body_html: str,
cc_addr: str = None, attachments: list = None,
send_on_behalf: str = None):
outlook = win32com.client.Dispatch("Outlook.Application")
mail = outlook.CreateItem(0) # 0 = olMailItem
mail.To = to_addr
if cc_addr:
mail.CC = cc_addr
if send_on_behalf:
mail.SentOnBehalfOfName = send_on_behalf # 使用指定發(fā)件郵箱(如有權(quán)限)
mail.Subject = subject
# 設(shè)置 html 正文
mail.BodyFormat = 2 # 2 = HTML
mail.HTMLBody = body_html
# 添加附件
if attachments:
for fp in attachments:
if os.path.isfile(fp):
mail.Attachments.Add(fp)
else:
log(f"[WARN] 附件不存在: {fp}")
mail.Send()
def main():
pythoncom.CoInitialize()
ensure_folder(OUTPUT_DIR)
data_rows = read_data()
log("開始處理,共 {} 行".format(len(data_rows)))
success = 0
fail = 0
for idx, row in enumerate(data_rows, start=1):
try:
to_addr = row.get(EMAIL_COLUMN, "").strip()
if not to_addr:
log(f"[SKIP #{idx}] 收件人地址為空,跳過")
continue
subject = row.get(SUBJECT_COLUMN, "(無主題)")
body_html = row.get(BODY_COLUMN, "")
cc_addr = row.get(CC_COLUMN, "").strip() or None
# 準(zhǔn)備附件
att = create_custom_attachment(row)
attachments = [att] if att else None
send_mail_via_outlook(to_addr=to_addr,
subject=subject,
body_html=body_html,
cc_addr=cc_addr,
attachments=attachments)
log(f"[OK #{idx}] 發(fā)送郵件 到: {to_addr}, 附件: {attachments}")
success += 1
except Exception as e:
log(f"[ERROR #{idx}] 收件人: {row.get(EMAIL_COLUMN)} 異常: {e}\n" + traceback.format_exc())
fail += 1
log(f"完成。成功: {success}, 失敗: {fail}")
pythoncom.CoUninitialize()
if __name__ == "__main__":
main()
模板說明 & 你可以怎樣擴(kuò)展 / 改造
- Excel 表格中每一行代表一封郵件:包含收件人、抄送(可選)、主題、HTML 正文、附件路徑/附件生成所需字段等。這樣適合“批量群發(fā) + 個(gè)性化內(nèi)容”。
- 我把生成附件與郵件發(fā)送邏輯分離。
create_custom_attachment(...)用于生成或獲取附件 — 你可以改成生成 Word/Excel 報(bào)告、PDF、圖片、文本等。 - 郵件正文支持 HTML。如果你希望插入圖片、表格、樣式、公司 logo、個(gè)性化布局,都可以通過 HTML 實(shí)現(xiàn)。很多人通過該方式,將公司模板/ html 模板 + Excel 數(shù)據(jù)融合后發(fā)送。關(guān)于這一點(diǎn),用 pandas 讀取數(shù)據(jù) + HTML 模板 + win32com 發(fā)郵件,是常見方案。
- 腳本中包含 日志記錄 + 異常捕獲 + 附件存在性檢查。 如果你每天/定期運(yùn)行這個(gè)腳本(比如用 Windows 任務(wù)調(diào)度器),日志能幫你追蹤哪些郵件發(fā)失敗,哪些發(fā)成功。
- 如果你需要針對不同收件人生成不同附件(例如針對每個(gè)客戶生成單獨(dú)報(bào)表/合同/發(fā)票),只需要把
create_custom_attachment(...)改成你的生成邏輯 — 比如讀取數(shù)據(jù)行內(nèi)容,生成 Excel/Word 或 PDF,再返回其路徑。
注意事項(xiàng) / 限制 / 異常處理
- 腳本依賴本地 Outlook 客戶端配置。如果沒有正確登錄或權(quán)限,可能拋出 COM 錯(cuò)誤。很多文章指出,當(dāng) Outlook 配置為現(xiàn)代安全模式、或組織策略限制自動(dòng)發(fā)送時(shí),腳本可能失敗。
- 如果批量郵件數(shù)量較多,建議有適當(dāng)間隔、不要一次性發(fā)送過快 —— 避免被當(dāng)作垃圾郵件或觸發(fā) Outlook 安全提示。
- 附件路徑/生成附件邏輯要保證正確,避免因路徑問題導(dǎo)致發(fā)送失敗。
- HTML 正文如果包含圖片、內(nèi)嵌資源等,要注意附件與 HTML 的引用關(guān)系 —— 有時(shí)候直接附件 + HTML 不一定能保證收件人看到正確格式/嵌入圖片 (取決于 Outlook 客戶端設(shè)置)。
總結(jié)
這個(gè)模板基本可以構(gòu)成一個(gè)“通用的批量發(fā)郵件 + 附件 + 個(gè)性化內(nèi)容 + 日志 + 錯(cuò)誤處理”工具。你可以根據(jù)具體業(yè)務(wù)(比如日報(bào)、自動(dòng)報(bào)表、客戶通知、合同發(fā)送等)——把 Excel 作為“驅(qū)動(dòng)表格”(包含收件人、內(nèi)容、參數(shù)、附件路徑/數(shù)據(jù)等),然后運(yùn)行腳本自動(dòng)完成所有工作。
以上就是Python3使用win32com從Excel讀取數(shù)據(jù)生成Word格式報(bào)告批量發(fā)郵件的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Python3 win32com Excel讀取數(shù)據(jù)生成Word的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
numpy如何刪除矩陣中的部分?jǐn)?shù)據(jù)numpy.delete
這篇文章主要介紹了numpy如何刪除矩陣中的部分?jǐn)?shù)據(jù)numpy.delete問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
Python 創(chuàng)建守護(hù)進(jìn)程的示例
這篇文章主要介紹了Python 創(chuàng)建守護(hù)進(jìn)程的示例,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-09-09
Python爬蟲中urllib庫的進(jìn)階學(xué)習(xí)
本篇文章主要介紹了Python爬蟲中urllib庫的進(jìn)階學(xué)習(xí)內(nèi)容,對此有興趣的朋友趕緊學(xué)習(xí)分享下。2018-01-01
python統(tǒng)計(jì)列表中元素出現(xiàn)次數(shù)的三種方法
這篇文章主要介紹了python統(tǒng)計(jì)列表中元素出現(xiàn)次數(shù)的三種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08
如何在python開發(fā)工具PyCharm中搭建QtPy環(huán)境(教程詳解)
這篇文章主要介紹了在python開發(fā)工具PyCharm中搭建QtPy環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
Python控制鍵盤鼠標(biāo)pynput的詳細(xì)用法
這篇文章主要介紹了Python控制鍵盤鼠標(biāo)pynput的詳細(xì)用法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
Pycharm pyuic5實(shí)現(xiàn)將ui文件轉(zhuǎn)為py文件,讓UI界面成功顯示
這篇文章主要介紹了Pycharm pyuic5實(shí)現(xiàn)將ui文件轉(zhuǎn)為py文件,讓UI界面成功顯示,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
Python中日期和時(shí)間的互相轉(zhuǎn)換操作方法
Python的datetime模塊提供了一套強(qiáng)大而靈活的工具,使我們能夠輕松地在不同的時(shí)間表示形式間相互轉(zhuǎn)換,并進(jìn)行復(fù)雜的時(shí)間計(jì)算,本文通過一個(gè)實(shí)用的例子向大家展示如何在Python中高效地進(jìn)行這些操作,感興趣的朋友一起看看吧2024-05-05

