pywin32+excel(四)使用pywin32操作excel进阶 |
您所在的位置:网站首页 › excel修改字体颜色就无响应 › pywin32+excel(四)使用pywin32操作excel进阶 |
在使用dll钩子注入目标程序获取数据后,得到存放数据的文本文件 文章目录 1. python调用exe1.1 直接使用os.system( )来调用1.2 使用subprocess.call()1.3 编码问题 2.判断是否获取到了数据文件以及数据处理2.1 判断文件是否存在2.2 含有中文的list类型进行转置2.3 字符串自动判断是转为整型还是浮点型 3. excel的问题3.1 excel精确匹配值的问题3.1.1 使用LookAt参数3.1.2 奇怪的现象LookAt参数生效问题3.1.3 关闭excel的问题3.1.3.1 Workbook.Close method (Excel)3.1.3.2 Application.Quit method (Excel) 3.1.4 上述打开excel方式不同带来的相关衍生错误 3.2 excel改变值的颜色3.2.1 使用RGB值3.2.2 使用预定义的一些颜色常量值 3.3 关于nan值3.5 合并单元格值的问题3.7 搜索结果range最后一行是655363.8 excel显示打印线的问题3.9 pywin32给cell加边框border问题3.9.1 参考文档/属性说明3.9.2 代码3.9.3 线型问题 3.10 合并单元格并写入值3.11 合并值相同的单元格3.11.1 说明/相关参考3.11.2 代码 3.12 excel列号字母转数字 4. pyinstaller打包问题尝试1尝试2 成功解决 5.交互过程中的问题 1. python调用exe 1.1 直接使用os.system( )来调用参考:在python中实现调用可执行文件.exe的3种方法 直接搬运过来好了 import os main = "project1.exe" r_v = os.system(main) print (r_v ) 1.2 使用subprocess.call()虽然这个会有返回值,但是是这个函数的返回值,用来判断call的内容执行是否正确,也不是获取call的内容的返回值,不是我要的,算了 1.3 编码问题出现的问题,由于我的.exe程序是C++写得,使用的编码默认是 UNICODE字符集,调试时,.exe输出在控制台上的内容是可以正确显示为中文的,查看了控制台的编码为:当前代码页 936(ANSI/OEM-简体中文GBK) 搜索资料,根据以下: 中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030python爬虫解决gbk乱码问题Visual Studio中C++关于Unicode字符集和多字节字符集可知:反正我还是没解决,头大的编码,哈哈哈 2.判断是否获取到了数据文件以及数据处理 2.1 判断文件是否存在参考 Python判断文件是否存在的三种方法 import os filepath="D:/haha.txt" if os.path.exists(filepath) and os.path.isfile(filepath): print("存在这个目录,且是文件 不是文件夹")使用os.path.exists()方法,判断文件和文件夹是一样,所以后面还需要使用os.path.isfile()来判断是一个文件,而不是一个文件夹 2.2 含有中文的list类型进行转置
由于numpy的reshape只针对于矩阵,而矩阵中的元素必须都是数字类型,我这个数据含有字符,所以只能手写一个转换,不能调用现成的函数了。(现成的也有,但是看起来很麻烦的样子) dflist = df['value'].tolist() cvList = [] for index in range(2, len(dflist) // 12): singelList = [] for i in range(3, 12): singelList.append(dflist[index * 12 + i]) cvList.append(singelList) # 为了方便后续搜索key 某些数据类型要改变 所以把二维列表变成一个类似实验1的json dict列表形式 dictList = [] for i in cvList: rowDict = {} rowDict['LC'] = i[0] rowDict['BCFH'] = eval(i[1]) rowDict['YGBC'] = eval(i[2]) rowDict['YGSJ'] = float(i[3]) # 对nan使用eval会报错 rowDict['WGBC'] = eval(i[4]) rowDict['WGSJ'] = float(i[5]) rowDict['JZD'] = eval(i[6]) rowDict['EDEC'] = i[7] rowDict['GLYS'] = float(i[8]) dictList.append(rowDict) 2.3 字符串自动判断是转为整型还是浮点型使用 eval函数 这里涉及到一个 搜索问题,Excel里直接的find其实是类似正则表达式匹配的。 因此,搜索 excel 精准匹配 VBA 根据:[求助] 如何精确匹配查找 以win32.gencache.EnsureDispatch('Excel.Application')这种方式打开excel,会提前运行gen_py来产生一些相关的文档,使得程序知道这些对象有什么方法和属性,在这种方式下,LookAt参数有效,确实是精确查找。但是单纯使用这个方式,没法达到每次运行,重启一个excel实例的目的,会把用户当前打开的excel文件关掉。 以win32.DispatchEx("excel.Application")这种方式打开,则可以重启一个新的excel实例。但是LookAt参数无效 故,需要使用方法1中的方式来产生一些文件缓存(让程序知道对象的方法和属性),然后再使用2中的方式来进行真正的excel调用。 这里有一个地方需要注意: 这里的Dispatch只是构建了一个excel对象,但是并没有打开表格,打开表格的操作是创建excel对象之后使用excel.Workbooks.Open(template_excel)引起的。所以即便先调用win32.gencache.EnsureDispatch('Excel.Application') ,只要不是这个excel对象执行excel.Workbooks.Open(template_excel)操作,就不会关闭用户的excel表格。 故执行1之后执行2创建excel的方式,再执行excel.Workbooks.Open(template_excel) 就不仅可以使LookAt属性生效,还可以以新建一个excel实例的方式运行excel。 疑惑的地方:一开始总觉得,需要先关闭excel=win32.gencache.EnsureDispatch('Excel.Application') 这句创建的excel对象,然后再创建excel = win32.DispatchEx("excel.Application"),虽然同名可以覆盖。 搜索后,发现只有Application.Quit method (Excel)和Workbook.Close method (Excel)这两个相关的内容。查看3.1.3关于这两个函数的说明,如果在方式1后面加上excel.Quit(),则用户的工作表界面也会被关闭,所以就算啦,不关就好了。操作完也不关了,因为不清楚用户是不是在使用excel。(反正是后台,应该没什么大问题) def open_excel(): try: # 以这种方式打开excel,会提前运行gen_py来产生一些相关的文档,使得程序知道这些对象有什么方法和属性,在这种方式下,LookAt参数有效,确实是精确查找 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 = win32.DispatchEx("excel.Application") excel.Visible = False # True 打开excel界面 excel.DisplayAlerts = 0 # 不弹窗显示警告信息 覆盖同名文件时不弹出确认框(但是无法打开同名文件时会出错 这个不属于弹窗警告信息) except Exception as e: print('ERROR 05: excel打开错误:', e) else: return excel 3.1.3 关闭excel的问题 3.1.3.1 Workbook.Close method (Excel)MSDN-Workbook.Close method (Excel) 代码demo wb = excel.Workbooks.Open(template_excel) wb.SaveAs(save_path) # 另存为 路径是绝对路径 wb.Close(False) # 关闭该文件,并保存。函数说明 用于关闭工作表Workbook对象 expression.Close (SaveChanges, FileName, RouteWorkbook)参数说明 "SaveChanges": 如果没有对工作表进行修改,这个参数会被忽略。如果对这个工作簿进行了修改但是这个工作簿显示在其他窗口,这个参数也会被忽略。如果工作簿被修改且没有呈现在其他窗口,则这个参数表明是否要保存修改。True就是保存对这个工作表的修改。False就是虽然我改了,但是我不保存这个修改。 比如:我打开了一个模板文件,修改后,另存为一个文件,但是模板本身我不希望改变,则使用False。 此外,如果这个工作表暂时没有名称(也就是说这个工作表没有被保存过,还是默认的 类似"工作簿1")这样的名称,则使用"FileName"参数,如果这个参数被省略了,则需要要求用户提供一个文件名 "FileName":使用这个文件名来保存文件 "RouteWorkbook":用不到,不管了 3.1.3.2 Application.Quit method (Excel)MSDN-Application.Quit method (Excel) 函数说明:退出excel程序(这条语句相当于excel右上角的关闭) A.Quit A变量表示一个Application对象如果使用这个方法的时候有未保存的工作表,则Excel会显示一个对话框询问是否要保存修改,如果不想让Excel显示这个对话框,则最好在使用Quit方法之前保存所有的工作表,或者设置DisplayAlerts属性为False,这样Excel就不会展示那些提示框了(无论什么情况下),但是当你没有保存修改就离开程序时,这些修改就丢失了。。。 如果之前设置过某个工作表的Saved属性是True(已保存),则不会将工作簿保存到硬盘,Excel会直接退出,而不会再询问是否要保存 3.1.4 上述打开excel方式不同带来的相关衍生错误错误信息,This COM object can not automate the makepy process - please run makepy manually for this object 有时如果打开了 代码中要访问的excel文件,就会报这个错误。 解决方案,参考python 报错 This COM object can not automate the makepy process - please run makepy manually for this 其实就是不要用 win32.gencache.EnsureDispatch('Excel.Application')这个方式打开,改成下面那种就好win32.DispatchEx("excel.Application") 说白了,还是因为自己提前打开了程序要访问的excelw文件。 3.2 excel改变值的颜色使用的是pywin32这个包,所以和VBA直接搜索的结果有一定出入, 根据:Excel如何用VBA更改字体颜色 考虑到python,根据:Setting a cell’s fill RGB color with pywin32 in excel? 还是想找更简单的方法,比如直接有颜色值可以使用的那种,根据MSDN-Font.Color property (Excel) →→ RGB function→→Color constants 在颜色常量中看到了常见颜色的 Value 从软件中获取的数据,有些没有值就会返回nan,但是发现excel会将nan值转为65535,搜索后发现,根据 微软社区问答-Microsoft.Office.Interop.Excel Range.set_value converts NaN to 65535:大意就是这个问题从Excel2007就有了,但是没法解决,所以要自己写个方法处理下,把那些nan变得65535变成空的。 合并单元格的英语应该是MergeCells,搜索对应的 MSDN官方文档-Range.MergeCells property (Excel) 参考: 很奇怪,虽然不影响代码,也可以根据项目的具体情况直接取代掉。 返回结果: 不小心手贱(项目甲方对excel报告打印效果有一定的效果),改模板的时候不小心点了打印,出现了打印线。参考:百度经验https://jingyan.baidu.com/article/a501d80c49d471ec620f5e45.html 主要就是 选项->高级,然后找找下面选项,去掉就好了 参考:stack-overflow_python win32com excel border formatting 这里要注意一个问题,你是要给 一个范围Range内的每个cell都加边框(上下左右) excel里的实现是选中范围,然后使用 所有框线 下图左 还是要给某个范围Range最外层加边框 excel里的实现是选中范围,然后使用 外侧框线 下图右区别如下: 参考官方: MSDN-Borders object (Excel) MSDN给出的VB的例子 Worksheets(1).Range("A1").Borders.LineStyle = xlDouble Worksheets("Sheet1").Range("A1:G1"). _ Borders(xlEdgeBottom).Color = RGB(255, 0, 0) 这里注意区别,如果只有一个单元格,Range里只有一个单元格,调用的其实是 Range对象的Borders属性,参见:MSDN-Range.Borders property (Excel)如果是一个Range范围,而不是单个的单元格,则需要使用Border object来进行使用,也就是代码上面那个链接的部分。 这里注意一下 Borders对象里的参数,是XlBordersIndex 常量,其可以为以下值xlDiagonalDown。xlDiagonalUp, xlEdgeBottom, xlEdgeLeft,xlEdgeRight,xlEdgeTop,xlInsideHorizontal,xlInsideVertical。 在python里使用需要找到对应的数值,XlBordersIndex enumeration (Excel)![]() 我的需求是右边(给范围加外侧框线 最直接的选择 外侧框线 之后的效果) # 左侧外边框 ws.Range("B13:I" + str(LineFlag-1)).Borders(7).Color = 0x0 ws.Range("B13:I" + str(LineFlag-1)).Borders(7).LineStyle = 1 ws.Range("B13:I" + str(LineFlag-1)).Borders(7).Weight = 2 # 下侧外边框 ws.Range("B13:I" + str(LineFlag - 1)).Borders(9).Color = 0x0 ws.Range("B13:I" + str(LineFlag - 1)).Borders(9).LineStyle = 1 ws.Range("B13:I" + str(LineFlag - 1)).Borders(9).Weight = 2 # 右侧外边框 ws.Range("B13:I" + str(LineFlag - 1)).Borders(10).Color = 0x0 ws.Range("B13:I" + str(LineFlag - 1)).Borders(10).LineStyle = 1 ws.Range("B13:I" + str(LineFlag - 1)).Borders(10).Weight = 2 关于颜色 参考本文 3.2部分,3.2.2 预定义的颜色常量值 关于线宽![]() 按照文档 应该是 LineStyle = 1 Continuous line应该就是连续实线,但是得到的却实点线??(结合代码实际效果,初步判断,使用 实线 但是出现的却是 点 的原因是 weight值为1 最细的线,改为 2 Thin. 就正常了 验证正确) LineStyle = -4115 Dashed line. 出来的效果也是下面这样LineStyle =4 Alternating dashes and dots.同上LineStyle =5 Dash followed by two dots. 同上LineStyle =-4118 Dotted line.LineStyle =-4119 Double line.LineStyle =13 Slanted dashes.注意:当weight=1时,所有的线型设置都会表现为如下,基本失效,当weight-2时,就正常了,其他值还没验证过,但是应该没问题 实验2电压部分的内容修改了,没有明确的excel模板了,有一部分要自己代码写入。 类似: ![]() ![]() 和上面的情况不太一样,这次的是要把某几列中上下相同的值(列方向上)进行合并 自己的代码(不一定是最好的,性能最高的,但是一定满足需求。。) 上述网页中都提到了一个问题,就是合并单元格的时候会提示 下面代码以一列为例(因为实际的需求就是几列需要进行合并单元格操作,不是某个连续范围的Range,而是分离的几个Column,写成函数形式好了 PS:不是对一个表里所有列操作,只对传入列号的列进行合并操作) # 其实是一个二重循环,一个指向要基准值的cell,一个不断向下搜索新的值并判断是否相等,进而考虑是否要合并 def mergeColumn(self, worksheet, index, stopLine): """ 合并某列中数值相同的单元格(列方向) :param worksheet: 工作表对象 :param index: 列的序号 A B C D 这样的 :return: None(直接对excel表的操作) """ colRng = worksheet.Range(index + "13:" + index + str(stopLine)) # print("区域范围",colRng.Address) # 范围正确 xRows = colRng.Rows.Count # 获取行数 为循环做准备 # print("行数",xRows) # 注意 已经使用Rng.Cells来获取数字了, # 里面的row和col就是在当前Rng范围里的序号了(不按照整张工作簿的了 按照相对于当前Rng的序号) i=0 j=0 # i的范围是colRng的第一到 倒数第二 最后一个值是j比较的 i不用取到 # (正常i需要的值是 1到xRows 因为最后一个数不用取 但是range(a,b)取[a,b-1],所以i的取值和j就是下面这样了 ) for i in range(1,xRows+1): for j in range(i+1,xRows+2): # 判断值相等且不为空 if (colRng.Cells(i,1).Value!=colRng.Cells(j,1).Value) : # print("!= i:{},j:{}".format(colRng.Cells(i, 1).Value, colRng.Cells(j, 1).Value)) break # 相等且不为空 elif not(colRng.Cells(i,1).Value is None): # print("== 非空 i:{},j:{}".format(colRng.Cells(i,1).Value,colRng.Cells(j,1).Value)) pass else: # print("不等且空 i:{},j:{}".format(colRng.Cells(i, 1).Value, colRng.Cells(j, 1).Value)) break # 上面只是为了递推最后一个相等的j的序号,合并操作在外面进行 colRng.Parent.Range(colRng.Cells(i, 1), colRng.Cells(j - 1, 1)).Merge() i = j - 1参考: 利用 pywin32 操作 excel:比网上直接查到的一些博客要详细一点,不属于伸手党,有自己的内容??pywin32模块操作Excel 这个也写得很好呀,像我一样默默无名但是又认真干活的小白码农,还有好多呀,(* ̄︶ ̄)。win32com: how to tell if an excel cell is empty 3.12 excel列号字母转数字在处理 3.11的时候,遇到的问题, clRng=ws.Range("B11:C20") # 定义Range的时候使用的列号是 字母 clRng.Cells(11,2) 11行 2列 # 但是在使用Cells时,其使用的却是 Cells(row,col) # 所以,当已知列号字母的时候,需要多加一个步骤把字母变成数字序号,才能使用Cells,其实字母转数字很方便,数字转字母略不方便 colNum=clRng.Column MSDN-Range.Cells property (Excel):excel没有直接从列号字母形式转为数字形式的函数,需要开发者自己利用某些已有函数造一个VBA Code To Convert Column Number to Letter Or Letter To Number[分享] VBA列标字母与数字的转化办法汇总Range.Column property (Excel)![]() 使用如下语句打包,报错RecursionError:maximum recursion depth exceeded pyinstaller main.py -F 尝试1搜索后,根据 pyinstaller 打包错误:RecursionError: maximum recursion depth exceeded 尝试2 成功解决无效,我的应该是一些报错信息,命令行看不全,重定向到文件 根据:Windows 重定向命令行输出可知: pyinstaller main.py -F>a.txt //只会输出正确的信息到目标文件,错误信息还是会输出到控制台 pyinstaller main.py -F>a.txt 2>&1 //可以把错误信息和正确信息都输出到一个流 pyinstaller main.py -F>suc.txt 2>fail.txt //可以将正确和错误信息分开输出到不同的文件查看错误文件发现: 确实显示 打包成功了,但是在执行生成的exe时,闪退 以管理员身份运行cmd,转入该exe目录下运行, 再重新生成一次,ok 5.交互过程中的问题报错 Expression:("Buffer too small",0) |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |