在你日常工作环境中所能做的最有用的事情之一就是集成对Win32程序的支持。实现从这样的应用程序中读写数据是很容易的事。虽然你所在的部门可能用不着Win32环境,但很有可能你的经理或是其他的工程组在用。Mark Hammond的Python的Windows扩展使得程序员可以在本地环境直接与Win32程序进行交互。
Win32编程是一个相当广泛的概念。Python的Windows扩展包包含了其中的大部分。如:Windows API、进程、Microsoft Foundation Classes (MFC)图形界面接口(GUI)开发、Windows多线程开发、服务、远程访问、管道、COM服务端编程和事件。还有一个能在。NET/Mono开发环境中使用的Python语言的C#实现:IronPython。在本节,我们主要关注Win32程序设计的一部分——客户端COM编程,它有着相当广泛的实际用途。
我们可以使用组件对象模型,另一个比较熟悉的名字是COM(市场化的名字是ActiveX)来与诸如Outlook和Excel之类的工具进行通讯。对于程序员来说,能在Python代码中直接“控制”一个本地Office应用程序是一件很快乐的事情。
特别地,当说到使用一个COM对象时,即启动一个应用程序,并允许代码访问该应用程序提供的方法,被称为客户端的COM编程。实现一个COM对象供其他客户端调用则被称为服务端的COM编程。
核心笔记:Python与微软COM(客户端)编程
在Windows 32位平台上,Python与COM是可以相互操作的。COM是微软的一种接口技术,它定义了语言及格式无关的对象与对象之间或是更高层次的应用程序与应用程序之间的通讯。本节中,我们将看到如何把Python与COM(客户端编程)组合起来,与微软Office的应用程序如Word、Excel、PowerPoint和Outlook之间进行通讯。
本节的先决条件是要运行在Win32平台上,并且安装了Python和Python的Windows扩展。同时,必需要安装一个或多个例子中用到的微软应用程序。Python的Windows扩展的下载说明很容易看懂,照着做一般不会出问题。我们推荐用扩展自带的PythonWin作为创建和测试你Win32脚本的IDE。
在本节中,我们将演示如何与Office应用程序进行交互。我们将给出几个示例,并详细解释它们。其中有一些例子是非常实用的。你也能在“Python Cookbook”网站找到一部分例子。必须承认的是,我们并不是COM或是Visual Basic的专家同时,我们也知道,这些例子还有很大的可以改进的空间。我们强烈希望所有读者把您认为对大家有用的评论、建议或改进发给我们。
我们先从很简单的微软Excel、Word、PowerPoint、Outlook的启动和交互开始。在展示例子之前,我们要先指出,客户端COM应用程序运行时都遵循相同的几个步骤。与这些应用程序进行交互的典型的方法是这样的:
1.启动应用程序;
2.打开要编辑的文档;
3.显示应用程序(如果有必要的话);
4.对文档做一定的操作;
5.保存或放弃文档;
6.退出。
说的够多了,下面开始看一些代码吧。以下是一系列脚本,用于控制不同的微软的应用程序。这些脚本都导入了win32com.client模块和一些Tk模块来控制各个应用程序的启动(和其他操作)。同第19章一样,我们釆用。pyw后缀来避免不必要的DOS命令窗口。
我们的第一个例子演示如何使用Excel。在整个Office系列软件中,我们发现Excel是最可编程的。用Excel处理数据非常的有用,一方面可以利用电子表格的功能优势,另一方面可以用非常好的打印格式来查看数据。而且可以从电子表格中读取数据,然后使用像Python这样的编程语言来处理数据,这一点也非常有用。在这一部分的最后我们会给出一个使用Excel的更加复杂一点的例子,但是我们总得开始吧,所以我们先从例23.2开始。
例23.2 Excel例子(excel.pyw)
这个脚本启动Excel,然后将数据填到电子表格的空格中。
逐行解释
1 ~ 6、31行
我们导入Tkinter和tkMessageBox模块只是为了使用showwaming消息框来终止演示。在显示对话框(26行)之前,我们调用withdraw()函数先绘出Tk最顶层的窗口(31行)。如果你不首先初始化顶层窗口,系统会自动地为你创建一个,不过,自动创建的不会自动关闭,而会很讨厌地显示在屏幕上。
11 ~ 17行
当代码启动(或调用)Excel后,我们添加了一个工作簿(就是包含了多个可以写数据的工作表的电子表格)。并得到了正在显示的活动表格的句柄。不要在术语上花太多精力,因为“工作簿包含好几个工作表”这种话很容易使人迷惑。
核心笔记:静态和动态调用
在第13行,我们使用的是静态调用。在运行这个脚本之前,我们从PythonWin中运行Makepy工具(启动IDE,选择Tools—>COM Makepy工具,然后选择相应的应用程序库),这个工具创建并缓存应用程序需要的对象。没有这些预先准备工作,对象和属性得在运行时建立。如果是在运行时创建对象和属性,那么就叫做动态调用。如果您想动态运行,那么请使用常用的Dispatch()函数。
xl = win32com. client. Dispatch(‘%s. Application’% app)
Visible标记必须设为True,这样才可以让应用程序显示在桌面上,然后停下来,这样用户可以看到演示的每一步(行16)。要知道第17行sleep()调用的含义,请阅读接下来的内容。
19 ~ 24行
在这个脚本程序的应用部分(application portion),我们把这个演示的标题写到了左上角的第一格,也就是(Al)或(1, 1),然后跳过了一行,把“Line N”写到相应的格中,N是从3到7的数字。在写每一行的时候中间停顿1秒,这样您就可以看到演示过程了(如果没有延迟,写每一行的过程会非常快)。
26 ~ 32行
在演示结束的时候,会弹出一个消息对话框,以方便用户在看完输出后,结束演示程序。电子表格关闭时不会被保存,首先调用ss. Close([SaveChanges=]False),然后应用程序结束。最后,脚本的“main”部分只是初始化Tk,然后执行应用程序的核心部分。运行这个脚本程序,会弹出一个Excel应用程序窗口,如图23-1所示。
图 23-1 Python-to-Excel示例脚本(excel.pyw)
下面来演示一下如何使用Word。由于涉及到的数据不多,用Word写文档的可编程性就不是那么强了。你可以考虑用Word来自动生成格式化的信件等。不过,在例23. 3中,我们将创建一个文档,然后简单地写几行字。
例23.3 Word例子(word.pyw)
这个脚本启动Word,然后向文档中写数据。
这个Word的例子和上面的Excel例子非常相似,惟一的不同是我们要在文档“范围”内插入字符串,每写一次向前移动一下光标,而不是像在Excel中那样写在每一格中。我们还要在程序中写明行结束符,也就是回车换行(\r\n)。
如果我们执行这个脚本程序,会显示如图23-2的界面。
图 23-2 Python-to-Word示例脚本(word.pyw)
在应用程序中使用PowerPoint并不太常见,但是当您急于制作演示文稿的时候可能会考虑使用它。您可以在飞机上用文本文件写下核心内容,然后在抵达酒店的夜里用脚本程序处理这个文件来自动生成一系列的幻灯片。您甚至可以通过添加背景和动画等东西来增强效果,这些都可以通过COM接口做到。另外一个使用到的情况就是当您不得不自动生成或修改新的或已存在的演示文档的时候。您可以通过shell脚本程序控制COM脚本来创建或者调整每个生成的幻灯片。好了,解释得够多了……现在来看一下我们的PowerPoint例子,如例23.4所示。
您会再一次注意到这个例子和上面的Excel和Word演示非常相似。PowerPoint的不同之处在于您写入数据的对象不一样了。不是向单独的表格或文档中写入数据,PowerPoint更为复杂,因为每一张幻灯片可以有不同的布局。在一个演示文档中,您有多张幻灯片,其中每一张幻灯片可以有不同的布局(最新版本的PowerPoint有30种不同的布局)。你可以进行的操作依您所选的布局不一样而各有不同。
在本例中,我们选用一个只有标题和文本的布局(17行),并填充主标题(19〜20行),即Shape[0]或Shape(l)——Python的下标从0开始,微软的软件从1开始——然后填充文本(22〜26行),即Shape[1]或Shape(2)。为了了解要使用哪一个常量,你需要一个所有可用的常量列表。例如,ppLaycmtText常量的值被定义为2(整型),ppLayoutTitle为1,等等。你可以在大多数微软VB/Office编程的书中或根f名字在线查找相关的定义。或者,你也可以直接使用整型值,而不使用win32.coristaiits中的名字。
例23.4 PowerPoint示例(ppoint.pyw)
这个脚本启动PowerPoint并在幻灯片中写入一些数据。
最后,我们给出一个Outlook的例子,它使用了比PowerPoint例子更多的常量,作为一个十分常见和通用的工具软件,在应用程序中使用Outlook非常有意义,这与前面Excel的例子一样。总是有电子邮件地址、邮件和其他数据可以在Python程序中轻松地处理。例23.5就是Outlook的一个例子,但是比前面的例子都要复杂一点。
在这个例子中,我们用Outlook给自己发了一封电子邮件。为了更好地演示这个例子,你需要先关闭网络访问,以确保你的email并不会真正被发送出去,这样,你就可以在发件箱里看到这封邮件(如果需要的话,还可以在看完后删除它)。启动Outlook后,我们写一封新的电子邮件,然后填好各个栏,例如收信人、主题和信件内容等(15〜21行)。然后调用send() (22行)将信存储到发件箱,在这里,信件一旦被确实发送到邮件服务器上,就会被移动到“已发送”。
图 23-3 Python-to-PowerPoint示例脚本(ppoint.pyw)
像PowerPoint一样,Outlook有很多可以使用的常量…… olMailltem(其值为0)常量被用于电子邮件信息。其他常用的Outlook常量有:olAppointmentItem(1), > olContactltem(2)、 olTaskItem(3)。当然,还有很多没有一一列出,你可以在介绍VB/Office编程的书中或者在线文档中查找相关常量的定义。
下一部分(24~27行),我们使用了另一个常量olFolder Outbox(4),来打开并显示发件箱目录,我们找到最新的几封邮件(有可能是我们刚刚创建的)并显示它们。其他几个常用的目录有:olFolderlnbox (6)、olFolderCalendar (9)、olFolderContacts(lO)、olFolderDrafts (16)、olFolderSentMail(5)和olFolderTasks(13)。如果你使用动态调用,你可能要使用具体的数值,而不是常量的名字(见之前的核心笔记)。
例23.5 Outlook例子(olook.pyw)
这个脚本启动Qiitlook,创建一封邮件,“发送”这封邮件,并允许你打开发件箱浏览这封邮件。
图23-4为邮件窗口的截图
图 23-4 Python-to- Outlook示例脚本(olook.pyw)
由于以前的Outlook总是被用于各种各样的攻击中,微软在Outlook中加入了一些保护措施,来限制对通讯簿的访问以及代表你发送邮件。当外部程序想要访问你的Outlook的数据的时候,会弹出一个如图23-5所示的对话框,以征取你的同意。
当你想要用外部程序发送邮件的时候,你会看到一个如图23-6所示的警告对话框。你必需等到计时器倒数结束后才能点击“确定”按钮。
一旦你完成了所有安全检查,其他所有的事都能很顺利地完成。也有一些软件可以帮助你绕过这些检查,但它们需要单独下载和安装。
在本书的网站http://corepython.com上,你能找到一个把这所有4个小脚本集成在一起的一个脚本,允许用户选择要运行哪一个示例。
图 23-5 Outlook地址薄访问警告
图 23-6 Outlook电子邮件传输警告
现在,我们对Office编程己经有了一些概念,接下来,我们要把本节所列的知识与Web服务那一节的知识组合起来,写一个更实用的应用程序。如果我们把股票报价的例子与Excel演示脚本合起来,就能形成一个能从网上下载股票报价,并把结果直接放到Excel中的应用程序,而不用把数据放在CSV文件中作为中介。
逐行解释
1~13行
我们导入股票报价和Excel脚本两个例子中的所使用的模块与常量。
15 ~ 32行
核心功能的第一部分是像之前那个脚本(17〜21行)那样启动Excel。把标题和时间写到相应的单元格中(23〜29行),然后是粗体(30行)的列的头。从第6行开始(32行)的单元格会写入实际的股票报价的数据。
34 ~ 43行
如同之前一样,打开一个URL(34行),但不再把结果写到标准输出,我们把结果填到电子表格的单元格中。一次放一列数据,每行一个公司的股票信息(35〜42行)。
45 ~ 51行
脚本的剩下几行作用与之前看到的一样。
例23.6 股票报价与Excel例子(estock.pyw)
这个脚本从Yahoo!下载股票报价并把数据写入到Excel。
图23-7显示的是运行了我们的脚本后有实际数据的窗口。
图 23-7 Python-to-Excel股票报价示例脚本(estock.pyw)
注意,存放数字的那几列的原始格式信息已经没有了,因为Excel用默认的单元格格式把它们存为数字了。我们把数字的格式改为保留小数点后两位。例如,虽然Python传递的是“34.20”,但显示的时候,还是显示“34.2”。而“自上次收盘的变动”那一列,则不仅少了小数点后的数字,而且数字前面的用于表示升值的正号(+)也没了(这是Excel的输出和原始文本版的比较。这些问题在本章结尾的练习中有详细说明)。