一千个读者一千个哈姆雷特,单纯
save()
表
close()
工作薄 还有
quit()
Excel APP,这三个写法就有很多不同的解释。。。
不喜欢解释太多,直接看代码吧,给一个简单的读取某个excel文件 修改后保存的例子。
excel = win32.Dispatch('Excel.Application')
excel.Visible = False
excel.DisplayAlerts = 0
wb = excel.Workbooks.open('./xxx.xls')
ws = wb.Worksheets('Sheet1')
c_column = [15, 16, 18, 41]
xing = 10
ws.Cells(11, 5).Value = 2
ws.Cells(11, 5).offset(3,2).Value =1
ws.Range('D' + str(xing)).value = c_column[0]
ws.Range('E' + str(xing)).value = c_column[1]
ws.Range('F' + str(xing)).value = c_column[2]
ws.Range('G' + str(xing)).value = c_column[3]
wb.save
wb.SaveAs('xxx.xls')
wb.Close(False)
excel.Quit()
参考Excel VBA中Offset函数的用法和自己实测
- Offset函数实为定位函数。首先要找到中心点,如果以单元格A1为中心点,则A1的位置就是Offset(0,0)。

- 上图以A1为中心,Offset两个参数分别是行和列。以0为起点。
- 同理,E11 (11,5)偏移(3,2)后 (11+3-1,5+2-1)得到(13,6)即 F13
- E11偏移(1,0)到D11 (11,5)偏移(1,0) 即 (11+1-1,5+0-1)=(11,4)=11D 即 D11
- 所以offset(0,0)反倒会向左上移动一个。想要保持不变,应该是offset(1,1)。。。实测
- 上 左 是 负向 下 右 是正向
- 这一结论和网上搜到的VBA代码结论不一致,可能是pywin32库的问题
- 此外,注意到如果写入单元格的内容很长,不会自动拉长单元格,需要自己打开excel之后手动缩放(也就是保持格式不变啦)
如果想定义Range(比如在A1-D10这个范围内的单元格搜索“报账单”),则需要使用Range对象,根据
Application.Range property (Excel),可知,定义Range的方式有两种:
//续上面的代码:
range=ws.Range("A1:D10").Find('报账单')
range=ws.Range(ws.Cell(1,1),ws.Cell(10,4))
print(range.Address)
此外,在遇到合并单元格时,返回的Range对象的Address地址范围只有左上角第一个的值,如果想要获得该合并单元格所有的行/列,可以使用offset
比如上述工作表,如果Find(‘10V’) 使用range.Address返回的只是$D$38,同时,使用range.Areas.count返回的只是1,也就是说 这个合并单元格的起始位置是$D$38且只有1个(并不是返回基本单元格的数量)。为了方便后续操作,参考Find方法如何找到合并单元格的位置,针对这种问题有两种常见解决方法
- 使用offset
- 使用Range对象的MergeArea属性 Range.MergeArea property (Excel)
由于我面临的场景不是单一合并(只是列方向或只是行方向),同时有许多合并单元格且合并的行数/列数并不一致,不能写死,所以采用第二种方法,使用Range对象的MergeArea属性(也是大多数情况下更方便推荐的一种)
range_freq = ws.Range(ws.Cells(1, 1), ws.Cells(10, 11)).Find('freq')
range_range=range_freq.Find('range')
print(range_range.Address,range_range.Areas.count)
for i in range_range.MergeArea:
print(i.Address)
print(i.row,i.column)
// 此时打印出来就可以看到这个合并单元格里所有的基本单元格的(合并的行或者列都会打印出来)
//如果某个合并单元格既有行合并又有列合并,则先按照行打印,再打印列
上图的excel表格区域打印后(先行后列):
$D$38
$E$38
$D$39
$E$39
$D$40
$E$40
$D$41
$E$41
$D$42
$E$42
$D$43
$E$43
$D$44
$E$44
$D$45
$E$45
$D$46
$E$46
$D$47
$E$47
freq_range = ws.Range(ws.Cells(10, 1),ws.Cells(20, 9))
freq_start_line = freq_range.Row
freq_end_line = freq_range.End(-4121).Row
参考:MSDN——关于Range的End()
在Python中使用时,似乎不认识 xlUp 这些关键字,所以直接用对应的数值代替。Down对应最下面一行,ToLeft对应最左侧一栏 同理,Up就是最上面一行 ToRight就是最右边一列,四个数值就是Range的范围了

主要参考:Convert two lists into a dictionary
方法一是性能最高的方法,方法二类似列表构造器,但是成为字典构造器会更合适一点
//方法一
a=['1','2','3']
b=[1,2,3]
c=dict(zip(a,b))
Out[5]: {'1': 1, '2': 2, '3': 3}
//方法二
new_dict = {k:
v for k, v in zip(keys, values)}
参考
Python 分割文本使得 字母和数字 分开?
但是最后发现还是re模块用起来最简单直接
在使用win32com调用excel的使用过程中,最常见的创建excel对象的方式有以下三种:
excel = win32.gencache.EnsureDispatch('Excel.Application')
excel = win32com.client.Dispatch('Excel.Application')
excel = win32com.client.DispatchEx('Excel.Application')
- Python笔记:使用pywin32处理excel文件:
win32com.client.DispatchEx('Excel.Application') #也可以用Dispatch,前者开启新进程,后者会复用进程中的excel进程 - 排坑:运行win32com.client.Dispatch(‘Word.Application’)和docx.Documents.Open()报错
:DispatchEx会使用独立进程 - 调用win32com.client.gencache.EnsureDispatch后的坑 object has no attribute:
说明使用win32com.client.gencache.EnsureDispatch()这个方式对函数调用的大小写会把控更严格,而win32com.client.Dispatch()则不会 - Stack overflow-win32.Dispatch vs win32.gencache in Python. What are the pros and cons?
如下程序所示,
import win32com.client as win32
xl_dis = win32.Dispatch("Excel.Application")
xl_dis
Out[3]: <COMObject Excel.Application>
import win32com.client as win32
xl_ens = win32.gencache.EnsureDispatch("Excel.Application")
xl_ens
Out[3]: <win32com.gen_py.Microsoft Excel 14.0 Object Library._Application instance at 0x35671240>
Dispatch调用属于late binding 调用时python不知道Excel object有哪些属性和方法可以使用
而EnsureDispatch调用属于earlybinding 调用时python知道Excel object有哪些属性和方法可以使用,这是因为EnsureDispatch会先运行makeup.py文件, 反正找找自己的目录,类似D:\anaconda\Lib\site-packages\win32com\client

此外,还可以在C:\Users\用户名\AppData\Local\Temp\gen_py\3.7\00020813-0000-0000-C000-000000000046x0x1x8类似的目录下找到这些内容,随便打开一个,里面就是这个object的属性方法,python也就是通过读取这些文件才知道这个com对象有什么属性方法的。
如果先使用了EnsureDispatch,那么就会产生这些文件,此时,不管调用Dispatch还是EnsureDispatch结果都一样。但是如果删除了这些文件,二者的不同之处就又会显现,所以最大的不同就是一个会产这些辅助文件,一个不会。这些东西是写在缓存文件夹位置的,不确定什么时候就会被清理

个人观点:EnsureDispatch用在写程序的时候,程序弄完之后,就用Dispatch比较好吧
使用EnsureDispatch的时候,有时候需要删除缓存下的内容,重新产一遍
def open_excel():
try:
try:
excel = win32.gencache.EnsureDispatch('Excel.Application')
except AttributeError:
import shutil
import sys
MODULE_LIST = [m.__name__ for m in sys.modules.values()]
for module in MODULE_LIST:
if re.match(r'win32com\.gen_py\..+', module):
del sys.modules[module]
shutil.rmtree(os.path.join(os.environ.get('LOCALAPPDATA'), 'Temp', 'gen_py'))
excel = win32.gencache.EnsureDispatch('Excel.Application')
excel.Visible = False
excel.DisplayAlerts = 0
except Exception as e:
print('ERROR 02: excel打开错误:', e)
else:
return excel
参考Advanced Python and COM,可能是我没有认真看,找不出相关的有效信息。
- Python笔记:使用pywin32处理excel文件:
win32com.client.DispatchEx('Excel.Application') #也可以用Dispatch,前者开启新进程,后者会复用进程中的excel进程
excel=win32.DispatchEx("Excel.Application")
excel=win32.DispatchEx("excel.Application")
使用DispatchEx确实是新开了一个excel进程,关闭时候只关闭当前excel进程,而不会影响以及打开的其他excel进程。good
Rebuilding cache of generated files for COM support has no attribute 'CLSIDToClassMap'
搜索后,根据Issue in using win32com to access Excel file可知
// 如果想确保python启动一个新的excel实例(例如,访问xlsm文件中的宏),则使用
xlApp = win32com.client.DispatchEx("Excel.Application")
//这样,我可以关闭应用程序而不会损害已经打开的实例。否则,我可以简单地使用
xlApp = win32com.client.Dispatch("Excel.Application")
pywin32这里的坑挺多的
excel打开错误: module 'win32com.gen_py.45541000-5750-5300-4B49-4E47534F4655x0x3x0' has no attribute 'CLSIDToClassMap'
参考:rdapaz/win32com.client.py,感谢这位大佬,大致就是把缓存清除,重新加载模块中的一个文件
try:
xl = client.gencache.EnsureDispatch('Excel.Application')
except AttributeError:
import os
import re
import sys
import shutil
MODULE_LIST = [m.__name__ for m in sys.modules.values()]
for module in MODULE_LIST:
if re.match(r'win32com\.gen_py\..+', module):
del sys.modules[module]
shutil.rmtree(os.path.join(os.environ.get('LOCALAPPDATA'), 'Temp', 'gen_py'))
from win32com import client
xl = client.gencache.EnsureDispatch('Excel.Application')
应该才是真的核心问题,在问题1.1解决后报错:
AttributeError: '<win32com.gen_py.Upgrade WPS Spreadsheets 3.0 Object Library (Beta).Workbooks instance at 0x1553056241672>' object has no attribute 'open'
也就是说 我调用的明明是excel 但是却使用了wps(大概就是端口冲突了),核心要解决的问题。
搜索发现:1. 安装并卸载WPS后,导致office COM组件调用失败的解决方案,大哥你真是个天使,我这个小白对端口和注册表一看就头大,爱你。
部分文章截取:
造成问题的原因是WPS恶意修改了office的com组件注册信息,并且,不知道为什么,卸载和重新安装都没有修复 。WPS把office的接口全部指向自己,对应注册表里 计算机\HKEY_CLASSES_ROOT\Interface{000208**-0000-0000-C0000-000000000046}\TypeLib 默认值改为了{45541000-5750-5300-4B49-4E47534F4655},原本应该为{00020813-0000-0000-C000-000000000046},Version改为了3.0,原本应该是1.7(office2010)。共有100+项,将以上修改正常就好了。附上修改后的注册表文件。
AttributeError: '<win32com.gen_py.Microsoft Excel 16.0 Object Library.Workbooks instance at 0x1898809804360>' object has no attribute 'open'
不用修改注册表?直接使用wps配置工具取消兼容?(反正我把wps配置工具里的所有默认关联打开文件全都取消了,哈哈哈),有兴趣的可以自己去根据
1. 安装并卸载WPS后,导致office COM组件调用失败的解决方案这里面给的注册表去看看,看是不是使用wps配置工具后 注册表文件发生了改变。
反正是可以用了,解决,yeah!
pywintypes.com_error: (-2147417851, '服务器出现意外情况。', None, None)
尝试过读写excel数据出现服务器出现意外:我电脑上没有福昕阅读器或者其他阅读器的插件,看过了,无效。
还有很多方法:
- open的文件名/路径过长,反正服务器报错,涉及的问题其实很多,出现这个报错不要考虑了,造成这个错误的可能太宽泛
excel=win32.client.Dispatch('Excel.Application')
print(excel.Name)
print(excel.Version)
Microsoft Excel 15.0(office2013对应的版本) 不是很区分大小写(上面改成小写的 excel.name 或者 excel.version都可以)
但是如果在office2016版本(Microsoft Excel 16.0)运行小写形式的属性name和version,则报错
'<win32com.gen_py.Microsoft Excel 16.0 Object Library._Application instance at 0x3142152794952>' object has no attribute 'name'
所以为了防止版本冲突(微软office官方给的都是大写),最好都改成大写
部署在其他人电脑的时候,报错
服务器没有响应 这个错误。
然后想起之前搜索相关错误的时候,出现过 excel中如果有福昕阅读器插件的话,会占用excel的com口,所以试了一下,关闭了那人电脑上的福昕阅读器的com加载项。 就ok了
相关函数参考
python win32.com对excel的基本操作
python对于excel的操作有很多库,我也尝试了很多,例如openpyxl,xlrd\xlwt,win32.com。现在先和大家说一下我遇到的坑。
openpyxl
调用这个库的打开excel函数时,你会发现你保存的文件的图片和打印格式(冻结的excel行)没有了,所以对于要操作的excel表中有图片或者格式的一般不建议用这个库。
xlrd/xlwt
在用这个库的时候,我也发现了如上的问题,我的excel文件中,原先的图片和打印格式没
之前使用win32com库的时候我常用的打开方式是
excel = win32com.client.Dispatch()
readbook = excel.Workbooks.Open()
一直相安无事,从其中调用api完成对行列的增删的语句也很简单
wb.api.rows(i).delete
wb.api.rows(i).insert
最近在使用Python调用win32com库生成excel透视表的过程中,我使用了新的打开方式:
Excel = win32com.client.gencache.Ensu
解决AttributeError: module ‘win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x9‘ has no attribu
本篇博客是 Python 操作 excel 系列的第5篇,前4篇博客阅读地址如下所示:
2022 之Python操作 Excel,xlrd 与 xlwt 模块一文掌握
Python 操作 Excel,从 xlwings 模块开始
Python 操作 Excel 第3篇博客,python openpyxl 模块一文打通
python处理excel文件,python xlsxwriter 一文初掌握
本篇咱们要学习的模块是 pywin32,该模块主要封装了 Windows 系统的 Win32 API,
发生这个错误的原因并不是很清楚, 大概是升级了一下系统, 但是我并不清楚内部原因.微博@mlln-cn, 并附上文章url链接, 我就能回答你的问题奥!运行这段代码, 就会找到它的位置. 然后删除。文件夹下的所有包含这一堆数字的文件夹。然后你的程序又能顺利运行了.2018年04月23日。
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Administrator\.virtualenvs\cms-venv\lib\site-packages\win32com\client\gencache.py", line 534, in ...
支持库pypiwin32中含有win32com模块,安装(这个 pypiwin32没有github项目,主页:pypiwin32。
> pip install pypiwin32
// 我是使用这种最简单的方式安装完成的
> python -m pip install pypiwin32
// 可能有些安装不成 需要用这种方式 或者
> pip install pypiwin32 --user
不使用python自带的一些操作excel的库是因为这次的项目对excel格式要求
import win32com.client
#Excel模块加载
xlApp=win32com.client.Dispatch(“Excel.Application”)
#WPS模块加载
xlApp=win32com.client.Dispatch(“et.Application”)
#测试版本加载
xlApp = win32com.client.gencache.EnsureDispatch(“Excel.Application”)
.........