背景
工作期间, 有一个报表生成并保存为图片发送的日常任务, 虽然数据处理可以利用pandas
库来便捷地完成, 但调整格式和保存特定单元格区域为图片, 就得用其他的库或手动来操作了(然而我很懒, 不想调用太多的python库), 另外, 我也不想再搞一个带宏的Excel文件, 想一并在python中完成操作.
之前一直对pywin32
库有所耳闻, 但当时没找到全面透彻的教程(当然现在也没找到), 这几天摸索了一下, 尤其是逛了逛StackOverflow
, 基于找到的零零散散的知识点做了些整理, 记录如下.
准备工作
import win32com.client as wc # wc这个别名好像不太好, 嘿嘿
from win32com.client import constants
如何查看任意COM对象的所有方法和属性?
首先, 最好是使用wc.gencache.EnsureDispatch(<进程名>)
, 因为这种方法能自动生成python接口文件
, 对应的文件夹位置一般为C:\Users\<Administrator>\AppData\Local\Temp\gen_py\3.X\
. 以Excel为例, 执行代码xl_app = wc.gencache.EnsureDispatch('Excel.Application')
后, 就会在上述文件夹下生成一个名为00020813-0000-0000-C000-000000000046
的文件夹, 这个名称其实对应着'Microsoft Excel 16.0 Object Library'
, 该文件夹下是各种COM对象的python接口文件
, 以_Worksheet
对象为例, 其方法都定义在class _Worksheet(DispatchBaseClass): ...
之下, 只读属性
都包含在_prop_map_get_
这个用作映射的字典里, 同时可读可写属性
都包含在_prop_map_put_
字典里. (其实并不是所有方法和属性都包含在这个接口文件中, 但大部分都在, 不影响调用), 接口文件代码抄录如下:
class _Worksheet(DispatchBaseClass):
CLSID = IID('{000208D8-0000-0000-C000-000000000046}')
coclass_clsid = IID('{00020820-0000-0000-C000-000000000046}')
def Activate(self):
return self._oleobj_.InvokeTypes(304, LCID, 1, (24, 0), (),)
def Arcs(self, Index=defaultNamedOptArg):
ret = self._oleobj_.InvokeTypes(760, LCID, 1, (9, 0), ((12, 17),),Index)
if ret is not None:
ret = Dispatch(ret, 'Arcs', None)
return ret
...
_prop_map_get_ = {
# Method 'Application' returns object of type 'Application'
"Application": (148, 2, (13, 0), (), "Application", '{00024500-0000-0000-C000-000000000046}'),
# Method 'AutoFilter' returns object of type 'AutoFilter'
"AutoFilter": (3289, 2, (9, 0), (), "AutoFilter", '{00024432-0000-0000-C000-000000000046}'),
...
}
_prop_map_put_ = {
"AutoFilterMode": ((792, LCID, 4, 0),()),
"DisplayAutomaticPageBreaks": ((643, LCID, 4, 0),()),
...
}
那么就可以写函数来查看任意COM对象的所有(大部分…)方法和属性了, 代码如下:
def print_multi_col(list, n_col=3, each_width=25):
for k, v in enumerate(list):
v = str(v)
if len(v) >= each_width:
v = v[:(each_width - 4)] + '...'
if (k + 1) % n_col != 0:
print(('{0: <' + str(each_width) + '}').format(v), end='')
else:
print(v)
if len(list) % n_col != 0:
print(' ' * each_width * (n_col - len(list) % n_col), end='')
print('-' * each_width * n_col)
def show_members(obj):
print(type(obj))
print('methods ->')
methods = [x for x in dir(obj.__class__)
if not x.startswith('__')]
print_multi_col(methods)
print('read only properties (_prop_map_get_) ->')
props1 = list(obj._prop_map_get_.keys())
print_multi_col(props1)
print('read / write properties (_prop_map_put_) ->')
props2 = list(obj._prop_map_put_.keys())
print_multi_col(props2)
测试一下上述代码:
xl_app = wc.gencache.EnsureDispatch('Excel.Application')
xl_app.Visible = True
xl_app.DisplayAlerts = False
wb = xl_app.Workbooks.Open(test_file_path)
ws = wb.Sheets(1)
show_members(ws)
结果为:
<class 'win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9._Worksheet._Worksheet'>
methods ->
Activate Arcs Buttons
CLSID Calculate ChartObjects
CheckBoxes CheckSpelling CircleInvalid
ClearArrows ClearCircles Copy
Delete DrawingObjects Drawings
DropDowns Evaluate ExportAsFixedFormat
GroupBoxes GroupObjects Labels
Lines ListBoxes Move
OLEObjects OptionButtons Ovals
Paste PasteSpecial Pictures
PivotTableWizard PivotTables PrintOut
PrintPreview Protect Range
Rectangles ResetAllPageBreaks SaveAs
Scenarios ScrollBars Select
SetBackgroundPicture ShowAllData ShowDataForm
Spinners TextBoxes Unprotect
XmlDataQuery XmlMapQuery _ApplyTypes_
_CheckSpelling _Evaluate _ExportAsFixedFormat
_PasteSpecial _PrintOut _PrintOut_
_Protect _SaveAs _SaveAs_
_get_good_object_ _get_good_single_object_ _prop_map_get_
_prop_map_put_ coclass_clsid
---------------------------------------------------------------------------
read only properties (_prop_map_get_) ->
Application AutoFilter AutoFilterMode
Cells CircularReference CodeName
Columns Comments CommentsThreaded
ConsolidationFunction ConsolidationOptions ConsolidationSources
Creator CustomProperties DisplayAutomaticPageB...
DisplayPageBreaks DisplayRightToLeft EnableAutoFilter
EnableCalculation EnableFormatCondition... EnableOutlining
EnablePivotTable EnableSelection FilterMode
HPageBreaks Hyperlinks Index
ListObjects MailEnvelope Name
NamedSheetViews Names Next
OnCalculate OnData OnDoubleClick
OnEntry OnSheetActivate OnSheetDeactivate
Outline PageSetup Parent
Previous PrintedCommentPages ProtectContents
ProtectDrawingObjects ProtectScenarios Protection
ProtectionMode QueryTables Rows
Scripts ScrollArea Shapes
SmartTags Sort StandardHeight
StandardWidth Tab TransitionExpEval
TransitionFormEntry Type UsedRange
VPageBreaks Visible _AutoFilter
_CodeName _DisplayRightToLeft _Sort
---------------------------------------------------------------------------
read / write properties (_prop_map_put_) ->
AutoFilterMode DisplayAutomaticPageB... DisplayPageBreaks
DisplayRightToLeft EnableAutoFilter EnableCalculation
EnableFormatCondition... EnableOutlining EnablePivotTable
EnableSelection Name OnCalculate
OnData OnDoubleClick OnEntry
OnSheetActivate OnSheetDeactivate ScrollArea
StandardWidth TransitionExpEval TransitionFormEntry
Visible _CodeName _DisplayRightToLeft
---------------------------------------------------------------------------
如何自动将Excel特定区域保存为图片
这里提供一种代码思路:
from PIL import ImageGrab
selection = ws.Range("A1:C100")
selection.CopyPicture() # 仅高版本的Office支持
ws.Paste()
# 对低版本的Office或WPS而言, 可以使用如下方法:
selection.Copy()
ws.PasteSpecial(Format="图片(Windows元文件)")
# ------------
ws.CutCopyMode = False
ws.Shapes(1).Copy() # 只适用于工作表之前没有图形的情况(当然上面一行也可以改为粘贴到一张新表中, 这样就保证新表中只有一张图形了)
img = ImageGrab.grabclipboard()
img.save(r"D:\...\test.png") # 似乎只能保存为png, 没继续研究
最后不要忘记:
wb.Close(SaveChanges=False) # 这里不保存修改
xl_app.Quit()