Python使用pywin32更新MS Excel单元格范围(无循环)
在Python中(也是Python的新成员:-),我尝试使用pywin32操作MS-Excel文件。我正在尝试做一些目前只有pywin32可以做的事情,以及其他一些库负载可以做的事情,但理想情况下,我想用pywin32做所有事情。除了一件事(grr),我能做我需要的一切!我无法从pandas数据帧或numpy数组填充一系列单元格。我可以用VBA很好地实现这一点,示例代码如下:Python使用pywin32更新MS Excel单元格范围(无循环),python,excel,pywin32,Python,Excel,Pywin32,在Python中(也是Python的新成员:-),我尝试使用pywin32操作MS-Excel文件。我正在尝试做一些目前只有pywin32可以做的事情,以及其他一些库负载可以做的事情,但理想情况下,我想用pywin32做所有事情。除了一件事(grr),我能做我需要的一切!我无法从pandas数据帧或numpy数组填充一系列单元格。我可以用VBA很好地实现这一点,示例代码如下: Dim i As Long: i = 1 Dim arr(1 To 11, 1 To 1) As Variant Dim
Dim i As Long: i = 1
Dim arr(1 To 11, 1 To 1) As Variant
Dim rex As Variant
For rex = -10 To 10 Step 2
arr(i, 1) = rex
i = i + 1
Next rex
ActiveSheet.Cells(1, 1).Resize(15).Value = arr
ActiveSheet.Range(Cells(1, 2), Cells(15, 2)).Value = arr
Dim myArray() As Variant
myArray = '[{1; 3; 4; 2; 5; 7; 6; 8; 9; 0}]'
ActiveSheet.Cells(1, 4).Resize(15).Value = myArray
ActiveSheet.Range(Cells(1, 5), Cells(15, 5)).Value = myArray
使用Python和pywin32,我可以更新一个范围,但只能获取数组中的第一个值,而不是数组中的所有值。我的Python代码的节略版本如下:
import os
import sys
import pandas as pd
import win32com.client as win32
import numpy as np
import psutil
import win32com
from win32com.client import VARIANT
import pythoncom
win32c = win32.constants
xlOpenXMLWorkbook = 51
folderOrFilePath = sys.argv[1]
# Split fullpath, filename, base filename and extension from argument
fullPath, fileName = os.path.split(folderOrFilePath)
fileNameBase, fileExtension = os.path.splitext(fileName)
# set excel object
excel = win32.gencache.EnsureDispatch('Excel.Application')
# excel can be visible or not
excel.Visible = True # Should be False for normal running / True for debugging
excel.ScreenUpdating = True # Turn off (false) for performance reasons
excel.DisplayAlerts = False
excel.EnableEvents = False
xlWb = excel.Workbooks.Open(fullFileNamePath)
ws_obj = xlWb.Sheets('sheet1')
last_row = ws_obj.UsedRange.Rows.Count
last_col = ws_obj.UsedRange.Columns.Count
ws_content_temp = ws_obj.Range(ws_obj.Cells(1, 1), ws_obj.Cells(last_row, last_col))
df1 = pd.DataFrame(ws_content_temp.Value)
dcc = df1.iloc[0].tolist()
dcc = [x.lower() for x in dcc]
df1.columns = df1.iloc[0] # Make first row the df1 column names
df1 = df1.iloc[1:] # Remove first row from the df1 as now column names
#tried defining the contents differently until I can get it working
#win32Array = ws_obj.Range(n2a(dcc.index('x')+1) + "1:" + n2a(dcc.index('x')+1) + str(lastRow)).GetValue()
#tried to populate the array manually until I can get it working
#win32Array = win32com.client.VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_R8, [1, 3, 4, 2, 5, 7, 6, 8, 9, 0])
#tried to populate the array manually until I can get it working
#win32Array = VARIANT(pythoncom.VT_ARRAY | pythoncom.VT_VARIANT,
# [VARIANT(pythoncom.VT_UI4, 3), VARIANT(pythoncom.VT_UI4, 1), VARIANT(pythoncom.VT_UI4, 4),
# VARIANT(pythoncom.VT_UI4, 2), VARIANT(pythoncom.VT_UI4, 5), VARIANT(pythoncom.VT_UI4, 7),
# VARIANT(pythoncom.VT_UI4, 6), VARIANT(pythoncom.VT_UI4, 8), VARIANT(pythoncom.VT_UI4, 9),
# VARIANT(pythoncom.VT_UI4, 0)])
#tried
#ws_obj.Cells(2, dcc.index('x')+2).Resize(df1.shape[0]).Value = df1['x'].to_numpy()
#ws_obj.Range(ws_obj.Cells(2, dcc.index('x')+2), ws_obj.Cells(df1.shape[0],dcc.index('x')+2)).Value = df1['x'].to_numpy()
#ws_obj.Cells(2, dcc.index('x')+2).Resize(df1.shape[0]).Value = win32Array
#ws_obj.Range(ws_obj.Cells(2, dcc.index('x')+2), ws_obj.Cells(df1.shape[0],dcc.index('x')+2)).Value = win32Array
xlWb.SaveAs(os.path.normpath(f'{fullPath}\\{fileNameBase}_Output.xlsx'), xlOpenXMLWorkbook)
xlWb.Close(False)
excel.ScreenUpdating = True
excel.DisplayAlerts = True
excel.EnableEvents = True
由于我能够更新范围,但无法获得数组/数据帧中的所有值在整个范围内的正确分布,因此我将搜索/尝试的重点放在了确保数组/数据帧的正确定义上,因此查看了像和这样的链接,只突出显示了两个,但到目前为止仍然没有运气
期待着您的建议。我已经找到了答案。这个问题显然是因为我选择了一列,因此在pywin32 range对象需要二维数组时生成了一维数组。正在处理下面的节略代码
import os
import sys
import pandas as pd
import win32com.client as win32
import numpy as np
import psutil
import win32com
from win32com.client import VARIANT
import pythoncom
win32c = win32.constants
xlOpenXMLWorkbook = 51
folderOrFilePath = sys.argv[1]
# Split fullpath, filename, base filename and extension from argument
fullPath, fileName = os.path.split(folderOrFilePath)
fileNameBase, fileExtension = os.path.splitext(fileName)
# set excel object
excel = win32.gencache.EnsureDispatch('Excel.Application')
# excel can be visible or not
excel.Visible = True # Should be False for normal running / True for debugging
excel.ScreenUpdating = True # Turn off (false) for performance reasons
excel.DisplayAlerts = False
excel.EnableEvents = False
xlWb = excel.Workbooks.Open(fullFileNamePath)
ws_obj = xlWb.Sheets('sheet1')
last_row = ws_obj.UsedRange.Rows.Count
last_col = ws_obj.UsedRange.Columns.Count
ws_content_temp = ws_obj.Range(ws_obj.Cells(1, 1), ws_obj.Cells(last_row, last_col))
df1 = pd.DataFrame(ws_content_temp.Value)
dcc = df1.iloc[0].tolist()
dcc = [x.lower() for x in dcc]
df1.columns = df1.iloc[0] # Make first row the df1 column names
df1 = df1.iloc[1:] # Remove first row from the df1 as now column names
dataArray = pd.DataFrame(df1['x'].apply(pd.Series)).to_numpy() # Need to ensure not output a 1D Array as the Excel Range Object is expecting a 2D Array
ws_obj.Range(ws_obj.Cells(2, dcc.index('x')+1),ws_obj.Cells(df1.shape[0]+1,dcc.index('x')+1)).Value = dataArray
xlWb.SaveAs(os.path.normpath(f'{fullPath}\\{fileNameBase}_Output.xlsx'), xlOpenXMLWorkbook)
xlWb.Close(False)
excel.ScreenUpdating = True
excel.DisplayAlerts = True
excel.EnableEvents = True
可能值得注意的是,pywin32中的.Resize函数的工作原理与VBA中的不同。只能将其用于更新单个单元格,因此使用.Range对象方法。