實(shí)現(xiàn)方法很多馒铃,不僅限于Python蟹腾,一般場(chǎng)景下通過(guò)VBA去做應(yīng)該會(huì)更方便痕惋。
主要是因?yàn)橥掠蓄愃频男枨螅枰拷獬罅縀xcel文檔的工作簿保護(hù)岭佳,統(tǒng)計(jì)其中的信息血巍,而他又使用了Python,我正好沒(méi)寫過(guò)珊随,頓時(shí)來(lái)了興致就寫了一下述寡。
Python操作Excel的庫(kù)如xlrd、openpyxl等都無(wú)法實(shí)現(xiàn)解除工作簿保護(hù)叶洞,因此只能通過(guò)COM組件的方式調(diào)用Excel來(lái)解除鲫凶。
我將其通過(guò)COM組件調(diào)用Excel解除工作簿保護(hù)的部分單獨(dú)提取了出來(lái),因?yàn)槠渌胤揭部赡軙?huì)用到衩辟。
用法上涉及到了configparser(解析配置文件)螟炫、logging(日志記錄)以及win32com.client的Dispatch(COM組件調(diào)用)等模塊。
注釋我已經(jīng)盡可能詳細(xì)艺晴,初學(xué)者或感興趣的可以嘗試折騰昼钻。
你可能需要通過(guò)以下命令安裝configparser
pip install configparser
其主要代碼如下:
# Excel 工具
#!/usr/bin/env python3
"""
Excel 工具
"""
import configparser
import logging
import os
import win32com.client
from win32com.client import Dispatch
class ExcelTools:
def __init__(self):
# 創(chuàng)建 logger 實(shí)例
# 日志記錄器不會(huì)直接實(shí)例化,而是始終通過(guò)模塊級(jí)方法logging.getLogger(name)進(jìn)行實(shí)例化
# 多次調(diào)用getLogger()具有相同的 name 將始終返回對(duì)同一個(gè)Logger對(duì)象的引用
# 通過(guò) __name__ 來(lái)命名 日志記錄器 可用來(lái)追蹤包/模塊 封寞,從logger名字直觀上找到事件發(fā)生處
# __name__ 是python模塊中的一個(gè)內(nèi)置屬性
# 一個(gè)模塊的 __name__ 的值取決于您如何應(yīng)用模塊然评。
# 如果 import 一個(gè)模塊,那么模塊__name__ 的值通常為模塊文件名狈究,
# 如果直接運(yùn)行模塊碗淌,在這 種情況下, __name__ 的值將為"__main__"。
logger = logging.getLogger(__name__)
# 設(shè)置該日志記錄器處理的閾值[也就是設(shè)置一個(gè)記錄的級(jí)別抖锥,低于這個(gè)級(jí)別的日志會(huì)被忽略]
logger.setLevel(logging.DEBUG)
# 創(chuàng)建日志記錄器記錄時(shí)的內(nèi)容格式
# 以下格式為:發(fā)生時(shí)間-調(diào)用模塊的名稱-調(diào)用方法的名稱-源文件的行號(hào)-記錄級(jí)別-事件描述消息
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(funcName)s - %(lineno)d - %(levelname)s - %(message)s')
# 創(chuàng)建日記處理程序亿眠,我們要輸出到控制臺(tái)則需要?jiǎng)?chuàng)建一個(gè)控制臺(tái)處理程序以便處理記錄的日志
# 創(chuàng)建 控制臺(tái)處理程器 并設(shè)置 級(jí)別 以進(jìn)行調(diào)試
console = logging.StreamHandler()
# 設(shè)置該控制臺(tái)處理器的日志記錄級(jí)別
console.setLevel(logging.DEBUG)
# 添加格式化程序到控制臺(tái)
console.setFormatter(formatter)
# 添加控制臺(tái)處理器添加到日志記錄器
# 可以將多個(gè)處理器添加到該日志記錄器中,如同時(shí)可以添加一個(gè)FileHandler文件處理器以便將日志同時(shí)記錄到文件中
logger.addHandler(console)
self.logger = logger
try:
self.excel = excel = win32com.client.Dispatch('Excel.Application')
logger.info("Excel COM庫(kù)版本:%s" % excel.Version)
except Exception as err:
logger.error('未檢測(cè)到Excel COM組件: %s' % err)
def decode(self, path, password):
'解除Excel的工作簿保護(hù)'
logger = self.logger
excel = self.excel
try:
# os.listdir() 方法用于返回指定的文件夾包含的文件或文件夾的名字的列表磅废。
for file in os.listdir(path):
# 獲取該文件的絕對(duì)路徑
absFilePath = os.path.abspath(os.path.join(path, file))
logger.info('文件路徑:%s' % absFilePath)
# 判斷是否是一個(gè)文件纳像,如果不是文件則跳過(guò)
if not os.path.isfile(absFilePath):
continue
# excel打開該文件
wb = excel.Workbooks.Open(absFilePath)
# excel隱藏界面,運(yùn)行在后臺(tái)拯勉,不顯示
excel.Visible = False
try:
logger.info('去除工作簿保護(hù):%s' % file)
# 解除保護(hù)
wb.Unprotect(password)
except Exception as err:
logger.error('解除 %s 的工作簿保護(hù)出錯(cuò):%s' % (file, err))
# 保存文件
wb.Save()
# 文件保存并關(guān)閉
wb.Close(SaveChanges=True)
finally:
# 確保在出錯(cuò)的時(shí)候也能正確的關(guān)閉Excel
# 未關(guān)閉在后臺(tái)運(yùn)行的Excel可能會(huì)導(dǎo)致很多奇怪的問(wèn)題
# 如果出現(xiàn)莫名其妙的錯(cuò)誤爹耗,請(qǐng)查看任務(wù)管理器關(guān)閉所有的Excel進(jìn)程
if hasattr(excel, 'Quit'):
logger.info('關(guān)閉Excel')
excel.Quit()
def main():
'主方法'
# 創(chuàng)建配置文件解析實(shí)例
conf = configparser.ConfigParser()
# 指定配置文件路徑和編碼
conf.read('conf.ini', 'utf-8') # 文件路徑
# 讀取配置信息
path = conf.get("Conf", "path")
password = conf.get("Conf", "password")
xls_tools = ExcelTools()
xls_tools.decode(path, password)
if __name__ == "__main__":
main()
conf.ini配置文件如下:
[Conf]
path=文件路徑
password=密碼