使用win32com和Python操作Excel

3
我想知道如何使用Python的win32com客户端在不迭代Excel表格的情况下读取整个列。
3个回答

14

使用 Range 集合可以在不迭代工作表的情况下阅读整个列。如果性能是任何问题,您应该永远不要使用Cells。Python 使用 win32com 模块与 Excel COM 库交互。每当您使用 Python 和 COM(Excel、PowerPoint、Acess、ADODB 等)时,最大的性能限制因素之一将是 COM 和 Python 之间的 IO。使用 Range 方法只需要进行一次 COM 方法调用,而使用 Cells 则每行都需要进行一次。如果您在 VBA 或 .NET 中执行相同操作,这也会更快。

在接下来的测试中,我创建了一个工作表,在单元格 A1 到 A2000 中随机生成了 10 个字符,然后使用 Range 和 Cells 将这些值提取到列表中。

import win32com.client
app = win32com.client.Dispatch("Excel.Application")
s = app.ActiveWorkbook.Sheets(1)

def GetValuesByCells():
    startTime = time.time()
    vals = [s.Cells(r,1).Value for r in range(1,2001)]
    return time.time() - startTime

def GetValuesByRange():
    startTime = time.time()
    vals = [v[0] for v in s.Range('A1:A2000').Value]
    return time.time() - startTime

>>> GetValuesByRange()
0.03600001335144043

>>> GetValuesByCells()
5.27400016784668

在这种情况下,Range方法比Cells方法快两个数量级(146倍)。请注意,Range方法返回一个二维列表,其中每个内部列表都是一行。列表迭代将vals转置为一个二维列表,其中内部列表是一列。


1
好的,尽管在其当前形式下我并不认为它是一个答案,但我仍然会点赞。对我来说,这是一个非常长的评论。我认为它值得点赞的原因是,它比迄今为止提出的任何一个答案都更有用、更有帮助(尽管yuvi的答案已经被接受了)。这里显示的代码片段明显最接近于说明如何“使用win32com读取整列而不进行迭代”。 - John Y
我刚才回顾了一下这个答案,并修改了它以回答原始问题。 - Michael David Watson
我想知道它与xlrd相比表现如何。如果差异微不足道,那么xlrd将是明显的赢家。 - yuvi
@yuvi:我自己没有进行过广泛的测试,但我认为这在很大程度上取决于数据的性质和您尝试做什么的性质。工作簿越大、越复杂,仅仅是加载时间方面,Excel就会有更大的优势。您越能依赖Excel本身来完成繁重的工作(通过其范围和计算引擎),Excel就会有更大的优势。只需确保尽可能少且高效地进行COM调用即可。 - John Y

2

你是否看过openpyxl库?根据文档:

from openpyxl import load_workbook
wb = load_workbook(filename='file.xlsx')
ws = wb.get_sheet_by_name(name='Sheet1')
columns = ws.columns()

此外,还支持迭代器和其他好用的工具。


1
最快的方法是使用内置的Range功能,通过win32com.client API实现。然而,我不是它的粉丝。我认为API很混乱且文档不好,使用它并不是很Pythonic(但这只是我的看法)。
如果效率对您不是问题,您可以使用优秀的xlrd库。像这样:
import xlrd
book = xlrd.open_workbooks('Book1')
sheet = book.sheet_by_name('Sheet1')
sheel.col(1)
sheet.col(2)
# and so on...

那会给你单元格对象。要获取纯值,请使用sheet.col_values(还有一些其他非常好用的方法)。
只需记住xlrd代表“excel read”,因此如果您想写入Excel文件,您需要一个名为“xlwt”的不同库(据我看来,这个库也相当不错,尽管不如xlrd)。

是的,我尝试编写了这段代码,并且在思考时,Python 可以尽可能地减少编写量,所以我在想是否有任何方法可以仅返回一个包含所需列值的列表,而无需编写迭代部分。 - Nischal Hp
你可以使用xlrd库,等一下我会添加一个例子。 - yuvi
那就希望能有所帮助! - yuvi
从概念上讲,我认为 OP 正在寻找一种以“一次性”检索整个范围的方法,就像使用 SELECT 从数据库中检索结果集一样。也就是说,在检索之前必须处理任何必须进行的“迭代”。在数据库的情况下,SQL 引擎可能在内部进行迭代,但您看到的只是一个“返回值”,其中包含多个值。因此,对于 Excel,OP 希望指定一个范围,然后将所有值“一次性”抓取到元组中。这可能是可能的,也可能不可能;我不太了解 COM。 - John Y
当然,在某种程度上,肯定会有某种迭代。但是,如果您可以让Excel通过COM(但使用范围操作;即Excel程序本身扮演“SQL引擎”的角色)来完成繁重的工作,那么它将是最快的。如果您必须在“高级”(在这种情况下使用Python)中进行迭代,则直接读取文件比COM更快,因为与COM机制相关的开销(Python与Windows通信与运行的Excel实例通信)存在。我非常喜欢xlrd,但它并没有什么特别优化的地方。 - John Y
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接