用Python 寫Excel 巨集 - 六小編Editor Leon

文章推薦指數: 80 %
投票人數:10人

說到Excel 巨集,最直覺聯想到的應該會是VBA,但其實微軟不只提供一種巨集語言,例如在網頁版的Excel 並不支援VBA,微軟給用戶的巨集語言是Office ... 說到Excel巨集,最直覺聯想到的應該會是VBA,但其實微軟不只提供一種巨集語言,例如在網頁版的Excel並不支援VBA,微軟給用戶的巨集語言是OfficeScripts,OfficeScripts是TypeScript的語法加上Excel物件模型的綜合體;又或者是增益集,微軟大大推的也是JavaScript/TypeScript的開發方案,而本文要介紹的是以Python為基礎的Excel開發模式。

什麼是「Python寫Excel巨集」?簡單的說,就是在Python程式內呼叫WindowsAPI操控Excel,具體的說是使用xlwings提供的封裝過的的ExcelCOMAPI以及透過pywin32提供的WindowsAPI橋接能力來實現在Python程式操控Excel的目的,這樣的組合用起來和VBA寫巨集有八成像,所以才說「用Python寫Excel巨集」。

這種模式其實和在C#調用ExcelCOMAPI是一樣的,差別在於Python在數據處理領域擁有C#無法比擬的成熟生態系。

和一般用Python套件讀寫Excel檔案不同的是,Python+xlwings的做法是去操控Excel,所以不會有讀寫後格式跑掉的問題,就算有也是Excel自己造成的,而用戶對Excel自己造成的跑版問題有著異常高的寬容度。

(反之,LibreOffice開Office文件有點小跑版,用戶就會勃然大怒。

)為什麼是Python,VBA不香嗎?或JS不香嗎?改用Python最顯著的好處當然是可以享用Python生態系的一切工具,特別是在數據處理這塊,這些好處列舉如下:可以用pandas等著名的數據套件處理Excel資料。

可以在JupyterNotebook環境或任何你喜愛的編輯器寫Python腳本,再也不用碰那陳年的VBA編輯器。

你的巨集腳本可以被版控、被集中整理,而不會隨著Excel檔案散落四方,因而享有所有版控的特性,多人協作、功能分支等等。

你還可以在Python腳本內透過xlwings調用Excel公式。

這幾點在其他的語言能否找到與之相當的工具,就看各個語言的套件生態豐不豐富了,至少在npm裡面我沒找到相對應的工具鍊。

而VBA本身,雖然也曾經輝煌過,十幾年前AutoCAD和CorelDRAW也一度支援VBA巨集,後來AutoCAD回歸Lisp的懷抱、CorelDRAW也認清要平面設計師寫巨集是不切實際的奢望…,現在的VBA不論對微軟或對我們來說,都更像是個歷史遺產而不是資產,因此對沒有歷史包袱的巨集開發者來說,改用Python完全是個可以考慮的選項。

當然,改用Python必然要建立Python開發環境,這點額外的負擔可以參見〈建置Python3.9/3.10開發環境〉或〈在Windows建置以VisualStudio為基礎的Python/Node.js開發環境〉,讓你快速在二十分鐘內建出心愛的Python環境。

用Python操控Excel前面提過,用Python操控Excel是靠xlwings與pywin32兩個套件實現的,這與我們利用Playwright或Selenium做瀏覽器自動化的模式相當類似,所以用Python寫Excel巨集這件是我們也可以稱為用Python做Excel自動化。

先放一部xlwings的影片感受一下操作體驗:這裡我們直接用程式說明xlwings的用法。

初始化與讀檔、存檔importxlwingsasxw withxw.App(add_book=False,visible=True)asapp: wb:xw.Book=app.books.open('example.xlsx') sheet:xw.Sheet=wb.sheets[0] #handlethesheet wb.save() 在引入xlwings並命名為xw後,我們建立了一個App物件,因為有存取Excel及開關檔案的原因,App是被設計成支援contextmanager的,因此我們用with敘述讓Python自動幫我們處理掉區塊執行後自動關閉Excel的瑣事。

接著用一個book物件叫Excel開啟example.xlsx檔案,再把檔案內的第一個工作表指到sheet,最後我們用save()叫Excel幫我存檔。

中間的#handlethesheet部分,典型的操作是找到你要的儲存格,再做後續的讀取、運算、寫入等工作。

選擇儲存格儲存格的選定,不論是單格或一個範圍,都是用xlwings的range()函式。

range()可以接受多種的儲存格標示法:#Excel標示法-單格 sheet.range('A1') #Excel標示法-多格 sheet.range('A1:C3') #以1為首的tuple(row,column)標示法-單格 sheet.range((1,2))#B1 #以1為首的tuple(row,column)標示法-多格 sheet.range((1,2),(3,4))#B1:D3 建議不要用Excel標示法,因為欄數一超過26欄還要去處理AA、AB、AC這類兩碼欄號的邏輯問題。

儲存格的取值與賦值取值與賦值也相當直覺,下面改用PythonREPL模式說明較能直觀感受到指令的回應:>>>rng1=sheet.range((1,2))#B1 >>>rng1.value '每次Jira的卡頓都令人抓狂' >>>rng1.value='用戰術上的勤奮掩蓋戰略上的怠惰' >>>rng1.value '用戰術上的勤奮掩蓋戰略上的怠惰' >>>rng2=sheet.range((1,2),(1,4))#B1:D1 >>>rng2.value ['a','b','c'] >>>rng2.value=['d','e','f'] >>>rng2.value ['d','e','f'] >>>rng3=sheet.range((10,1),(11,3))#A10:C11 >>>rng3.value [['a','b','c'],[10.0,20.0,30.0]] 對於A10:C11這樣3*2的範圍,對應的值也會以3*2的巢狀二維陣列形式表示。

只要靠range()搭配程式本身的迴圈或迭代結構,就可以完成大部分的任務囉,是不是相當簡單直覺呢!小訣竅分享一點小訣竅:一個xlwings的App可以開啟多份Excel檔案,可以互相剪剪貼貼。

也可以開多個xlwings的app,此時他們會有各自的程序ID。

結語VB大哥已死,小弟弟SmallBasic又注定只能是玩具不能是工具,肩負著教育責任的SmallBasic首頁卻有著奇葩的烏龜人:在這樣的勢態下,微軟僅容你VBA苟活,至於那美好的未來,看來是OfficeScripts會與我們一同走過,但在OfficeScripts尚未支援桌面版Excel的當下,對於沒有歷史包袱的我們,改用Python可能是更好的選擇,而且身分還能從「寫巨集的😞」搖身一變成🕺「大數據工程師🤓」,一整個潮到出汁💦。

本文僅介紹xlwings最常用的幾個功能,但xlwings的能力遠不止於此,它還有個特異功能,用xlwings的CLI指令讀檔,它會以HTTP服務的方式供應那份Excel檔的API,各種花式用法請參閱xlwings文件。

Share作者:Leon有機無毒的小農小編。



請為這篇文章評分?