第 7 章 *Microsoft Office 编程
无论你做什么,总会有一个限制因素决定你完成它的速度和程度。你的工作就是对任务进行研究,找出那个限制因素。然后集中你所有的力量,消除这个瓶颈。
—Brain Tracy,2001 年 3 月
(Eat That Frog,2001 年,Berrett-Koehler)
本章内容:
- 简介;
- 使用Python 进行 COM 客户端编程;
- 入门示例;
- 中级示例;
- 相关模块/包。
注意:本章中的示例都需要使用 Windows 操作系统,使用 Mac 系统的苹果电脑无法运行本章的 Microsoft Office 示例。
本章将与本书的大部分章节有所区别,不再关注网络开发、GUI、Web 或基于命令行的应用,而是使用 Python 做一些完全不同的事情:通过组件对象模型(COM)客户端编程控制专有软件,具体来说就是 Microsoft Office 应用。
- 7.1 简介
无论开发者是否喜欢,都无法否认他们生活在一个需要与基于 Windows 的 PC 进行交互的世界里。它可能只是间歇性出现的,也可能是你每天都必须处理的事情,不过无论你所面对的出现频率如何,Python 总能够使我们的生活变得更简单。
在本章中,我们将学习通过使用 Python 进行 COM 客户端编程,从而能够控制诸如 Word、Excel、PowerPoint 和 Outlook 等 Microsoft Office 应用,并能够与之进行通信。COM 是一个服务,通过该服务可以使 PC 应用与其他应用进行交互。具体而言,Office 套件中那些知名的应用提供了 COM 服务,而 COM 客户端编程可以用来驱动这些应用。
传统意义上,COM 客户端一般使用两种非常强大但又非常不同的工具来编写,分别是Microsoft Visual Basic(VB)/Visual Basic for Application(VBA)和(Visual)C++。对于 COM 编程而言,Python 一般被视为一种可行的替代品,因为它比 VB 更加强大,又比 C++开发有着更好的表现力和更少的时间消耗。
有一些更新的工具,如 IronPython、.NET、VSTO,也可以帮助你编写与 Office 工具通信的应用,不过如果你去研究其底层,就会发现它们同样是 COM,所以即使你使用了更加先进的工具,本章中的内容依旧可以适用。
本章既可以使 COM 开发者学会如何在其世界中应用 Python,也可以让 Python 程序员学会如何创建 COM 客户端来自动执行任务,比如,生成 Excel 表格、创建 Word 文档、使用PowerPoint 建立幻灯片演示以及通过 Outlook 发送邮件等。我们将不会讨论 COM 的原则或概念,或者思考“为什么是 COM”。此外,我们也不会学习有关 COM+、ATL、IDL、MFC、DCOM、ADO、.NET、IronPython、VSTO 等工具的知识。
取而代之的是,我们将会让你专注于学习如何使用 Python 与Office 应用通信,进行 COM客户端编程。
7.2 使用 Python 进行 COM 客户端编程
在日常的业务环境中,你能够做的最有用的事情之一就是整合对Windows 应用的支持。能够对这些应用进行数据读写通常是非常方便的。虽然你的部门可能并没有运行在Windows 环境中,但是很有可能你的管理者或者其他项目组使用了Windows 环境。Mark Hammond 编写的 Windows Extnesions for Python 允许程序员在原生环境中与 Windows 应用进行交互。
Windows 编程的领域正在不断扩大,其中大多数都来自于 Windows Extensions for Python 包。它包括:Windows API、派生进程、MFC GUI 开发、Windows 多线程编程、服务、远程访问、管道、服务器端 COM 编程以及事件。本章后续部分会重点讨论Windows 领域中的一个重要部分:COM 客户端编程。
7.2.1 客户端 COM 编程
我们可以使用 COM(其商业名称为 ActiveX)与诸如 Outlook、Excel 等工具进行通信。对于开发者而言,其乐趣在于能够直接通过他们的 Python 代码来“控制”原生的Office 应用。
具体来说,比如,在讨论 COM 对象的使用时,启动应用并允许代码访问应用的方法和数据,这称为 COM 客户端编程;而 COM 服务器端编程则是用于客户端访问的 COM 对象的实现。
核心提示:Python 和 Microsoft COM(客户端)编程 |
Python 在 Windows 32 位平台上包含了对 COM 的连通性,Microsoft 的接口技术允许对象与其他对象进行通信,从而促进更高级别的应用与其他应用之间的通信,而不需要任何对语言或格式的依赖。在本节中我们会看到 Python 和COM(客户端编程)是如何结合起来,提供独特的时机用于创建能够直接与 Microsoft Office 应用(如 Word、Excel、PowerPoint 和Outlook)进行通信的脚本的。 |
7.2.2 入门
本节的前提条件包括:使用一台运行 32 位或 64 位 Windows 系统的 PC(或包含虚拟机的其他系统);必须安装有.NET 2.0(至少)、Python 以及Python Extensions for Windows(可以从 http://pywin32.sf.net 获取该扩展);必须有至少一个可用的 Microsoft 应用用于尝试下面的示例。你可以在命令行中进行开发,也可以使用 Extensions 分发版本中的 PythonWin IDE 进行开发。
我必须承认自己并不是COM 方面的专家,也不是 Microsoft 软件开发者,不过我有足够的能力来向你展示如何使用Python 控制Office 应用。当然,这里的例子还有很大的改进空间。所以恳请读者给我们写信,以普通读者的角度,提出意见、建议和改进方案。
本章后面几节是由一些示例应用组成的,这些例子可以让你对每种主要的 Office 应用编程有个初步认识;然后,会有几个中等难度的示例。在给出这些例子之前,需要指出客户端 COM 应用在执行中都遵循相似的步骤。这些应用进行交互的典型方式类似下面的步骤。
- 启动应用。
- 添加合适的文档以工作(或载入一个已经存在的文档)。
- 使应用可见(根据需要)。
- 执行文档所需的所有工作。
- 保存或放弃文档。
- 退出。
讨论就到这里,现在让我们看一些代码。接下来的一节会包含很多脚本,其中的每个脚本都会控制一种不同的 Microsoft 应用。所有脚本都会导入 win32com.client 模块以及一些Tk 模块来控制应用的启动(和完成)。此外,和第 5 章一样,我们使用了.pyw 扩展名,从而让不需要的 DOS 命令行窗口不再显示。
7.2 入门示例
本节将给出几个基础示例,使你在 4 个主流的 Office 应用开发中能够入门,这 4 个 Office应用分别是:Excel、Word、PowerPoint 和Outlook。
7.2.1 Excel
我们在第一个例子中使用的是Excel。在所有 Office 套件中,我们发现 Excel 是可编程化最好的应用。向 Excel 中传输数据非常有用,因为你既可以利用表格的功能,又能够以一种很好的可打印格式显示数据。此外,从电子表格中读取数据并通过真实编程语言(如 Python) 的功能来执行,也是非常有用的。本节最后还会给出一个更复杂的例子,不过我们必须先要入门才可以,所以先从示例 7-1 开始。
示例 7-1 Excel 示例(excel.pyw)
本脚本会启动 Excel 并向电子表格的单元格中写入数据。
逐行解释
第 1~6 行、第 31 行
我们导入了 Tkinter 和 tkMessageBox 模块,仅用于在演示结束后使用 showwarning 消息框。在对话框出现(第 26 行)之前,我们使用了 withdraw()方法不让 Tk 顶级窗口出现(第31 行)。如果没有事先初始化顶级窗口,那么 Tk 会为你自动创建一个,而且不会将其隐藏, 这样会在你的屏幕上造成一定的干扰。
第 11~17 行
当代码启动(或者“调度”)Excel 后,我们添加了一个工作簿(一个包含了多个可写入数据的工作表的电子表格,这些工作表在工作簿中以标签的形式进行组织),然后取得了活动工作表(显示的那个工作表)的句柄。不要过分纠结于这些术语,因为“电子表格包含多个工作表”这种话很容易使人困惑。
核心提示:静态和动态调度
第 13 行使用了静态调度。在开始脚本之前,我们在 PythonWin 中运行了 Makepy工具(启动 IDE,选择 Tools →COM Makepy utility,然后选择适合的应用对象库)。该工具会创建应用所需的对象并进行缓存。如果没有这个准备工作,对象和属性则需要在运行时构建,那样就是动态调度了。如果你希望动态运行,那么可以使用 Dispatch() 函数。
xl = win32com.client.Dispatch(‘%s.Application’ % app)
Visible 标记必须设为 True,这样应用才能够在桌面上可见;而暂停可以让你看清演示中的每一步(第 16 行)。
第 19~24 行
在该脚本中的应用部分,首先在第一个单元格(左上角、A1 或者(1, 1))写入演示的标题。然后跳过一行,并将“Line N”写到对应的单元格中(N 为 3~7 之间的数字),每写入一行停顿 1 秒,从而可以让你看到实时更新(如果没有延时,单元格的更新将会发生得非常快。这就是脚本中贯穿了对 sleep()函数的调用的原因)。
第 26~32 行
一个警告对话框会在演示结束后出现,指明你可以在观察到输出结果后退出。电子表格在关闭 时 并 不 会 进 行 保 存 , 这 里 使 用 了ss.Close([SaveChanges=]False),然后应用就会退出了。最后,脚本的“main”函数部分对 Tk 进行初始化,并运行应用的核心部分。
运行本脚本时会弹出一个 Excel 应用窗口,如图7-1 所示。
图7-1 Python-to-Excel 演示脚本(excel.pyw)
7.2.2 Word
下一个演示脚本使用的是 Word。使用 Word 编写文档没有那么好的可编程性,因为不会涉及太多的数据。不过,你可以考虑使用 Word 生成套用信函。在示例 7-2 中,创建一个文档,并逐行写入文本。
Word 的这个示例和 Excel 的那个示例非常相似。唯一的不同是,Excel 中是写入单元格, 而在 Word 中则是在文档的文本“范围”内插入字符串,并在每行写入后将光标移到下一行。这里必须手动给出行结束符:回车换行(\r\n)。
当运行脚本时,其运行结果如图 7-2 所示。
图 7-2 Python-to-Word 演示脚本(word.pyw)
示例 7-2 Word 示例(word.pyw)
本脚本会启动 Word,并在文档中写入数据。
7.2.3 PowerPoint
在应用中使用PowerPoint 并不十分常见,不过你可以考虑在匆忙赶制演示文稿时使用这种应用。比如,你可以在飞机上先将要点写入文本文件中,然后当晚上到达酒店后,使用脚本解析文件并自动生成一组幻灯片。更进一步,你还可以为这些幻灯片添加背景、动画等, 所有一切都可以通过 COM 接口完成。另一个用例是在你必须自动生成或修改新的或已存在的演示文稿时。此时你可以通过shell 脚本控制创建 COM 脚本,从而创建和调整每个演示文稿。下面让我们看一下示例 7-3 中的PowerPoint 示例。
示例 7-3 PowerPoint 示例(ppoint.pyw)
本脚本会启动 PowerPoint,并在幻灯片中将数据写入文本框中。
你看到的这个代码和之前的 Excel 以及 Word 演示都很相似。而 PowerPoint 与之不同的地方是写入数据的对象。不同于单个活动工作表或文档,PowerPoint 的情况比较麻烦,因为一个演示文稿中会包含很多张幻灯片,而每张幻灯片都可能有不同的布局(PowerPoint 的最新版本中包含了 30 种不同的布局!)。在一张幻灯片中可以执行的操作需要依赖于你所选择的布局。
在该例子中,使用了标题和文本布局(第 17 行),把主标题(第 19~20 行)填充到 Shape[0](即 Shape(1)) 中,而把文本部分(第 22~26 行)填充到 Shape[1](即Shape(2))中。需要注意,这里 Shape 的写法不同,是因为Python 中是从 0 开始索引的,而在 Windows 软件中则是从 1 开始索引的。为了找出使用哪个常量,你需要有所有可用常量的一个列表。比如,ppLayoutText 的常量值为2(整型),而 ppLayoutTitle 则是 1。你可以在大多数 Microsoft VB/Office 编程书籍中找到这些常量,也可以在网上通过搜索它们的名字进行查找。此外,你可以直接使用整型常量,而不必通过 win32.constants 命名它们。
PowerPoint 示例的屏幕截图如图 7-3 所示。
图 7-3 Python-to-PowerPoint 演 示 脚 本(ppoint.pyw)
7.2.4 Outlook
最后,我们给出 Outlook 演示,在 Outlook 中会使用比 PowerPoint 更多的常量。作为一个非常常见和通用的工具,Outlook 的使用像 Excel 一样在应用中非常有意义。在 Python 程序中,可以轻松处理邮件地址、邮件消息及其他数据。示例 7-4 是一个 Outlook 示例,它比之前的几个例子功能更多一些。
示例 7-4 Outlook 示例(olook.pyw)
本脚本会启动 Outlook,创建一封新邮件然后将其发送,并且可以让你通过 Outbox 和邮件本身打开进行查看。
在本示例中,我们使用了 Outlook 向我们自己发送一封邮件。为了使该演示可以正常运行,你需要关闭网络连接,从而使邮件消息不会真正发送出去,而可以在你的 Outbox 文件夹中看到它(如果你愿意,可以在查阅后删除该邮件)。在启动 Outlook 之后,我们创建了一封新的邮件,并填充了几个字段,比如接收人、主题、邮件正文内容等(第 15~21 行)。然后调用了 send()方法(第 22 行),使邮件假脱机进入 Outbox,一旦邮件被传递到邮件服务器中,该邮件就会从Outbox 文件夹移出,进入“已发送邮件”文件夹中。
和PowerPoint 一样,这里也有很多可用的常量,olMailItem(其常量值为 0)是用于邮件消息的一个常量。Outlook 中其他常用的项目还包括:olAppointmentItem(1)、olContactItem(2)以及 olTaskItem(3)。当然,还有更多的常量可用,你可以查阅 VB/Office 编程书籍或者在网上搜索常量及其值,以获取更多信息。
下一部分(第 24~27 行)使用了另一个常量:olFolderOutbox(4),用于打开 Outbox 文件夹并进行显示。我们会找到最新创建的几封邮件(希望包含我们刚刚创建的那封)进行显示。另一些常 用 的 文 件 夹 包 括 : olFolderInbox ( 6 )、olFolderCalendar(9)、olFolderContacts(10)、 olFolderDrafts(16)、olFolderSentMail(5)以及olFolderTasks(13)。如果你使用的是动态调度,你可能必须使用数值而不是常量名(参见前面的核心提示)。
图 7-4 Python-to-Outlook 演示脚本(olook.pyw)
图 7-4 所示为邮件窗口的截屏。
在我们更进一步之前,需要知道 Outlook 总是遭受各种各样的攻击,所以 Microsoft 内置了很多防护措施,来限制访问地址簿以及代表你发送邮件的能力。当尝试访问 Outlook 数据时,屏幕上会显示类似图 7-5 所示的弹窗,在这里你必须显式地给外部程序赋予权限。
接下来,当你尝试从一个外部程序发送邮件时,会出现图 7-6 所示的警告对话框;你必须等到时间条耗尽才能选择 Yes 按钮。
图 7-5 Outlook 地址簿访问警告
图 7-6 Outlook 邮件发送警告
当你通过所有安全检查后,其他一切事情都会很顺利地运行。有一些软件可以帮助你绕过这些检查,不过它们需要单独下载和安装。
在本书的配套网站 http://corepython.com 中,你可以找到一个应用脚本,它把这 4 个小示例都组合到了一起,在该脚本中会允许用户自己选择运行哪个示例。