Python 操作Office的PPT、Word、Excel,同时兼容WPS

发布于:2025-09-14 ⋅ 阅读:(16) ⋅ 点赞:(0)

概要

在日常办公自动化中,我们经常需要使用Python来操作Microsoft Office的Excel、Word和PowerPoint文件。然而,在国内环境下,WPS Office也被广泛使用。本文将介绍如何编写同时兼容两种办公软件的Python代码,实现无缝的自动化办公体验。

一、环境准备

1. 安装必要的Python库

我们需要使用pywin32库来通过COM接口操作Office和WPS,以及pillow库来处理图片:

pip install pywin32 pillow

如果需要处理数据,还可以安装pandas库:

pip install pandas

2. 系统要求

  • Windows操作系统(因为COM接口是Windows特有的)
  • 已安装Microsoft Office或WPS Office

二、核心实现原理

1. 检测已安装的Office类型

首先,我们需要检测系统中安装的是Microsoft Office还是WPS Office。这可以通过读取Windows注册表来实现:

import winreg

def detect_office_type():
    try:
        # 检查Microsoft Office
        winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Office")
        return "Microsoft Office"
    except WindowsError:
        try:
            # 检查WPS Office
            winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Kingsoft\Office")
            return "WPS Office"
        except WindowsError:
            return None

2. 初始化对应的应用程序

根据检测到的Office类型,我们需要初始化对应的应用程序。Microsoft Office和WPS Office的COM接口名称不同:

  • Microsoft Office的COM接口:Excel.Application, Word.Application, PowerPoint.Application
  • WPS Office的COM接口:Ket.Application, Kwps.Application, Kwpp.Application
from win32com.client import Dispatch

def initialize_applications(office_type):
    if office_type == "Microsoft Office":
        excel = Dispatch("Excel.Application")
        word = Dispatch("Word.Application")
        powerpoint = Dispatch("PowerPoint.Application")
    elif office_type == "WPS Office":
        excel = Dispatch("Ket.Application")
        word = Dispatch("Kwps.Application")
        powerpoint = Dispatch("Kwpp.Application")
    else:
        return None, None, None
    
    # 设置应用程序可见性和警告选项
    excel.Visible = True
    excel.DisplayAlerts = False
    
    word.Visible = True
    word.DisplayAlerts = False
    
    powerpoint.Visible = True
    powerpoint.DisplayAlerts = False
    
    return excel, word, powerpoint

三、完整代码实现

下面是一个完整的示例,演示如何创建一个兼容Office和WPS的处理器类,实现Excel、Word和PPT的基本操作,包括图片插入功能:

import os
import sys
import time
import winreg
import tempfile
from PIL import Image, ImageDraw, ImageFont
from win32com.client import Dispatch

class OfficeWPSHandler:
    """Office和WPS兼容处理器"""
    def __init__(self):
        self.office_type = None
        self.excel = None
        self.word = None
        self.powerpoint = None
        self.output_dir = os.path.join(os.getcwd(), 'output', 'Office_WPS演示')
        os.makedirs(self.output_dir, exist_ok=True)
    
    def detect_office_type(self):
        """检测系统安装的Office类型"""
        try:
            # 检查Microsoft Office
            winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Office")
            self.office_type = "Microsoft Office"
        except WindowsError:
            try:
                # 检查WPS Office
                winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Kingsoft\Office")
                self.office_type = "WPS Office"
            except WindowsError:
                self.office_type = None
        
        return self.office_type
    
    def initialize_applications(self):
        """初始化Office/WPS应用程序"""
        if self.office_type == "Microsoft Office":
            self.excel = Dispatch("Excel.Application")
            self.word = Dispatch("Word.Application")
            self.powerpoint = Dispatch("PowerPoint.Application")
        elif self.office_type == "WPS Office":
            self.excel = Dispatch("Ket.Application")
            self.word = Dispatch("Kwps.Application")
            self.powerpoint = Dispatch("Kwpp.Application")
        else:
            print("未检测到Microsoft Office或WPS Office!")
            return False
        
        # 设置应用程序可见性和警告选项
        self.excel.Visible = True  # 设置为True便于调试
        self.excel.DisplayAlerts = False
        
        self.word.Visible = True
        self.word.DisplayAlerts = False
        
        self.powerpoint.Visible = True  # 涉及图形操作时必须设置为可见
        self.powerpoint.DisplayAlerts = False
        
        print(f"成功初始化 {self.office_type} 应用程序")
        return True
    
    def create_excel_demo(self):
        """创建Excel演示文件"""
        try:
            # 创建工作簿
            workbook = self.excel.Workbooks.Add()
            worksheet = workbook.Worksheets(1)
            worksheet.Name = "演示数据"
            
            # 写入数据
            worksheet.Cells(1, 1).Value = "姓名"
            worksheet.Cells(1, 2).Value = "年龄"
            worksheet.Cells(1, 3).Value = "职位"
            
            worksheet.Cells(2, 1).Value = "张三"
            worksheet.Cells(2, 2).Value = 30
            worksheet.Cells(2, 3).Value = "工程师"
            
            worksheet.Cells(3, 1).Value = "李四"
            worksheet.Cells(3, 2).Value = 35
            worksheet.Cells(3, 3).Value = "经理"
            
            # 调整列宽
            worksheet.Columns("A:C").AutoFit()
            
            # 保存文件
            excel_file = os.path.join(self.output_dir, f"{self.office_type}_Excel演示.xlsx")
            workbook.SaveAs(excel_file)
            workbook.Close()
            
            print(f"Excel演示文件已保存至:{excel_file}")
            return True
        except Exception as e:
            print(f"创建Excel文件时出错:{e}")
            return False
    
    def set_word_text(self, shapes, shape_index, shape_text):
        """Word:查找并设置文本框内容的函数(兼容Microsoft Office和WPS Office)"""
        try:
            if not isinstance(shape_index, int):  # 如果shape_index是Name
                shapes.Item(shape_index).TextFrame.TextRange.Text = shape_text
            else:  # 如果shape_index是index
                shapes[shape_index].TextFrame.TextRange.Text = shape_text
            return True
        except Exception as e:
            print(f"设置Word文本时出错:{e}")
            return False
    
    def create_word_demo(self):
        """创建Word演示文件"""
        try:
            # 创建文档
            doc = self.word.Documents.Add()
            
            # 添加标题
            title_range = doc.Range(0, 0)
            title_range.Text = "Python操作Word演示文档\n"
            title_range.Font.Size = 18
            title_range.Font.Bold = True
            title_range.ParagraphFormat.Alignment = 1  # 居中对齐
            
            # 添加正文
            content_range = doc.Range()
            content_range.Text = "这是一个使用Python和win32com库操作Word的演示文档。\n"
            content_range.Font.Size = 12
            content_range.ParagraphFormat.Alignment = 0  # 左对齐
            
            # 添加列表
            list_range = doc.Range()
            list_range.Text = "\n支持的功能:\n"
            list_range.Font.Size = 12
            
            list_items = ["创建新文档", "设置文本格式", "添加表格", "插入图片", "保存文档"]
            for item in list_items:
                item_range = doc.Range()
                item_range.Text = f"• {item}\n"
                item_range.Font.Size = 12
            
            # 演示Word文本框设置(兼容处理)
            # 添加一个文本框
            text_box = doc.Shapes.AddTextbox(1, 100, 300, 400, 50)
            text_box.Name = "demo_textbox"
            
            # 使用兼容函数设置文本
            self.set_word_text(doc.Shapes, "demo_textbox", "这是通过兼容函数设置的文本内容")
            
            # 保存文件
            word_file = os.path.join(self.output_dir, f"{self.office_type}_Word演示.docx")
            doc.SaveAs(word_file)
            doc.Close()
            
            print(f"Word演示文件已保存至:{word_file}")
            return True
        except Exception as e:
            print(f"创建Word文件时出错:{e}")
            return False
    
    def get_ppt_shape(self, slide, shape_index):
        """查找并返回指定幻灯片上的形状的函数(兼容Microsoft Office和WPS Office)"""
        try:
            if not isinstance(shape_index, int):  # 如果shape_index是Name
                return slide.Shapes.Item(shape_index)
            else:  # 如果shape_index是index
                return slide.Shapes[shape_index]
        except Exception as e:
            print(f"获取PPT形状时出错:{e}")
            return None
            
    def set_ppt_text(self, slide, shape_index, shape_text):
        """PPT查找并设置文本框内容的函数(兼容Microsoft Office和WPS Office)"""
        try:
            if not isinstance(shape_index, int):  # 如果shape_index是Name
                slide.Shapes.Item(shape_index).TextFrame.TextRange.Text = shape_text
            else:  # 如果shape_index是index
                slide.Shapes[shape_index].TextFrame.TextRange.Text = shape_text
            return True
        except Exception as e:
            print(f"设置PPT文本时出错:{e}")
            return False
    
    def create_ppt_demo(self):
        """创建PPT演示文件"""
        try:
            # 创建演示文稿
            presentation = self.powerpoint.Presentations.Add()
            
            # 添加标题幻灯片
            slide1 = presentation.Slides.Add(1, 12)  # 12代表标题幻灯片布局
            slide1.Shapes.Title.TextFrame.TextRange.Text = "Python操作PPT演示"
            slide1.Shapes(2).TextFrame.TextRange.Text = "兼容Microsoft Office和WPS Office"
            
            # 添加内容幻灯片
            slide2 = presentation.Slides.Add(2, 2)  # 2代表标题和内容布局
            slide2.Shapes.Title.TextFrame.TextRange.Text = "支持的功能"
            
            # 添加文本框和列表
            text_box = slide2.Shapes.AddTextbox(1, 50, 100, 600, 300)
            text_box.Name = "demo_textbox"
            
            # 使用兼容函数设置文本
            items = ["创建演示文稿", "添加幻灯片", "设置文本格式", "插入图表", "保存演示文稿"]
            text = "\n".join([f"• {item}" for item in items])
            self.set_ppt_text(slide2, "demo_textbox", text)
            
            # 获取并设置字体大小(兼容处理)
            shape = self.get_ppt_shape(slide2, "demo_textbox")
            if shape:
                shape.TextFrame.TextRange.Font.Size = 16
            
            # 保存文件
            ppt_file = os.path.join(self.output_dir, f"{self.office_type}_PPT演示.pptx")
            presentation.SaveAs(ppt_file)
            presentation.Close()
            
            print(f"PPT演示文件已保存至:{ppt_file}")
            return True
        except Exception as e:
            print(f"创建PPT文件时出错:{e}")
            return False
            
    def create_sample_image(self):
        """创建示例图片用于演示"""
        try:
            # 创建一个简单的图片
            image = Image.new('RGB', (400, 300), color='white')
            draw = ImageDraw.Draw(image)
            
            # 尝试加载系统字体,如果失败则使用默认字体
            try:
                font = ImageFont.truetype("arial.ttf", 36)
            except:
                font = ImageFont.load_default()
            
            # 在图片上绘制文本
            draw.text((50, 100), "Python Office/WPS演示", fill=(0, 0, 255), font=font)
            draw.text((100, 160), "图片示例", fill=(0, 128, 0), font=font)
            
            # 绘制一些简单的图形
            draw.rectangle([(50, 50), (350, 250)], outline=(0, 0, 0), width=2)
            draw.ellipse([(150, 200), (250, 250)], fill=(255, 255, 0), outline=(0, 0, 0))
            
            # 保存图片
            image_path = os.path.join(self.output_dir, "sample_image.png")
            image.save(image_path)
            print(f"示例图片已创建:{image_path}")
            return image_path
        except Exception as e:
            print(f"创建示例图片时出错:{e}")
            return None
            
    def add_image_to_ppt(self):
        """将图片复制并粘贴到PPT演示文稿中"""
        try:
            # 确保示例图片存在
            image_path = self.create_sample_image()
            if not image_path or not os.path.exists(image_path):
                print("示例图片不存在,无法添加到PPT")
                return False
            
            # 创建演示文稿
            presentation = self.powerpoint.Presentations.Add()
            
            # 添加标题幻灯片
            slide1 = presentation.Slides.Add(1, 12)
            slide1.Shapes.Title.TextFrame.TextRange.Text = "图片插入演示"
            slide1.Shapes(2).TextFrame.TextRange.Text = "演示如何将图片添加到PPT中"
            
            # 添加图片幻灯片
            slide2 = presentation.Slides.Add(2, 11)  # 11代表空白幻灯片布局
            slide2.Shapes.Title.TextFrame.TextRange.Text = "图片展示"
            
            # 方法1:直接插入图片(更简单)
            slide2.Shapes.AddPicture(FileName=image_path, LinkToFile=False, SaveWithDocument=True, 
                                    Left=100, Top=100, Width=400, Height=300)
            
            # 添加说明文字(使用兼容函数)
            text_box = slide2.Shapes.AddTextbox(1, 100, 420, 400, 50)
            text_box.Name = "method1_text"
            self.set_ppt_text(slide2, "method1_text", "方法1:直接插入图片到PPT")
            
            # 获取并设置字体大小(兼容处理)
            shape = self.get_ppt_shape(slide2, "method1_text")
            if shape:
                shape.TextFrame.TextRange.Font.Size = 14
            
            # 添加第三张幻灯片,演示复制粘贴方式
            slide3 = presentation.Slides.Add(3, 11)
            slide3.Shapes.Title.TextFrame.TextRange.Text = "复制粘贴图片演示"
            
            # 方法2:通过剪贴板复制粘贴图片
            # 注意:此方法在WPS中需要特别的兼容处理
            import win32clipboard
            from PIL import Image
            
            # 打开图片并复制到剪贴板
            image = Image.open(image_path)
            output = tempfile.SpooledTemporaryFile(max_size=1024*1024)
            image.convert("RGB").save(output, "BMP")
            data = output.getvalue()[14:]  # 去掉BMP文件头
            output.close()
            
            # 将图片数据写入剪贴板
            win32clipboard.OpenClipboard()
            win32clipboard.EmptyClipboard()
            win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
            win32clipboard.CloseClipboard()
            
            # 在PPT中粘贴图片
            slide3.Select()  # 激活幻灯片(兼容WPS Office)
            shape_picture = slide3.Shapes.Paste()  # 粘贴图片
            
            # 兼容处理:在WPS中,Paste()可能返回None
            if shape_picture is None:
                shape_count = slide3.Shapes.Count
                if shape_count > 0:
                    shape_picture = slide3.Shapes.Item(shape_count)
            
            # 设置图片位置和大小(如果成功获取到图片对象)
            if shape_picture:
                shape_picture.Top = 100
                shape_picture.Left = 100
                shape_picture.Width = 400
                shape_picture.Height = 300
            
            # 添加说明文字(使用兼容函数)
            text_box2 = slide3.Shapes.AddTextbox(1, 100, 420, 400, 50)
            text_box2.Name = "method2_text"
            self.set_ppt_text(slide3, "method2_text", "方法2:通过剪贴板复制粘贴图片")
            
            # 获取并设置字体大小(兼容处理)
            shape = self.get_ppt_shape(slide3, "method2_text")
            if shape:
                shape.TextFrame.TextRange.Font.Size = 14
            
            # 保存文件
            ppt_file = os.path.join(self.output_dir, f"{self.office_type}_PPT图片演示.pptx")
            presentation.SaveAs(ppt_file)
            presentation.Close()
            
            print(f"包含图片的PPT文件已保存至:{ppt_file}")
            return True
        except Exception as e:
            print(f"向PPT添加图片时出错:{e}")
            return False
    
    def close_applications(self):
        """关闭所有应用程序并释放COM对象"""
        try:
            if self.excel:
                self.excel.Quit()
                del self.excel  # 释放COM对象
            if self.word:
                self.word.Quit()
                del self.word  # 释放COM对象
            if self.powerpoint:
                self.powerpoint.Quit()
                del self.powerpoint  # 释放COM对象
            print("所有应用程序已关闭并释放资源")
        except Exception as e:
            print(f"关闭应用程序时出错:{e}")

四、使用示例

下面是如何使用上面的处理器类来操作Office或WPS文件的完整示例:

if __name__ == "__main__":
    print("Python操作Office与WPS兼容演示程序")
    print("==================================")
    
    # 创建处理器实例
    handler = OfficeWPSHandler()
    
    # 检测Office类型
    print("正在检测系统安装的Office类型...")
    office_type = handler.detect_office_type()
    
    if office_type:
        print(f"检测到:{office_type}")
        
        # 初始化应用程序
        if handler.initialize_applications():
            # 演示Excel操作
            print("\n开始创建Excel演示文件...")
            handler.create_excel_demo()
            
            # 演示Word操作
            print("\n开始创建Word演示文件...")
            handler.create_word_demo()
            
            # 演示PPT操作
            print("\n开始创建PPT演示文件...")
            handler.create_ppt_demo()
            
            # 演示PPT图片插入操作
            print("\n开始创建包含图片的PPT演示文件...")
            handler.add_image_to_ppt()
    else:
        print("未检测到Microsoft Office或WPS Office,程序无法运行。")
    
    # 关闭所有应用程序
    print("\n正在关闭所有应用程序...")
    handler.close_applications()
    
    print("\n演示完成!")
    input("按任意键退出...")
    sys.exit()

五、WPS兼容处理详解

在实现Office和WPS兼容时,有一些关键的处理点需要特别注意。下面我们详细介绍这些兼容处理方法:

1. 形状和文本框访问兼容处理

Microsoft Office和WPS Office在访问形状和文本框时存在细微差异。为了解决这个问题,我们实现了几个通用函数:

def set_word_text(self, shapes, shape_index, shape_text):
    """Word:查找并设置文本框内容的函数(兼容Microsoft Office和WPS Office)"""
    try:
        if not isinstance(shape_index, int):  # 如果shape_index是Name
            shapes.Item(shape_index).TextFrame.TextRange.Text = shape_text
        else:  # 如果shape_index是index
            shapes[shape_index].TextFrame.TextRange.Text = shape_text
        return True
    except Exception as e:
        print(f"设置Word文本时出错:{e}")
        return False

# 类似的函数还有:
# get_ppt_shape - 获取PPT形状的兼容函数
# set_ppt_text - 设置PPT文本框的兼容函数

这些函数通过检查参数类型,判断是使用索引还是名称来访问形状,从而实现对两种办公软件的兼容。

2. PPT图片粘贴兼容处理

在WPS中粘贴图片是一个需要特别处理的操作。主要有以下几个要点:

  1. 幻灯片激活:在粘贴图片之前,需要先激活目标幻灯片

  2. 粘贴返回值处理:在WPS中,Paste()方法可能返回None,需要通过其他方式获取粘贴的图片

  3. 图片定位和尺寸设置:需要确保图片正确放置在幻灯片上

# 粘贴图片的兼容处理示例
slide3.Select()  # 激活幻灯片(兼容WPS Office)
shape_picture = slide3.Shapes.Paste()  # 粘贴图片

# 兼容处理:在WPS中,Paste()可能返回None
if shape_picture is None:
    shape_count = slide3.Shapes.Count
    if shape_count > 0:
        shape_picture = slide3.Shapes.Item(shape_count)

# 设置图片位置和大小(如果成功获取到图片对象)
if shape_picture:
    shape_picture.Top = 100
    shape_picture.Left = 100
    shape_picture.Width = 400
    shape_picture.Height = 300

3. 资源释放的重要性

在操作完成后,正确释放COM对象非常重要,特别是在长时间运行的自动化脚本中:

def close_applications(self):
    """关闭所有应用程序并释放COM对象"""
    try:
        if self.excel:
            self.excel.Quit()
            del self.excel  # 释放COM对象
        if self.word:
            self.word.Quit()
            del self.word  # 释放COM对象
        if self.powerpoint:
            self.powerpoint.Quit()
            del self.powerpoint  # 释放COM对象
        print("所有应用程序已关闭并释放资源")
    except Exception as e:
        print(f"关闭应用程序时出错:{e}")

使用del语句明确释放COM对象,可以避免资源泄漏和进程残留问题。

六、图片操作实现详解

在办公自动化中,图片处理是常见需求。我们的代码提供了两种将图片添加到PPT的方法:

1. 直接插入图片

这种方法简单直接,适合大多数场景:

# 方法1:直接插入图片(更简单)
slide2.Shapes.AddPicture(FileName=image_path, LinkToFile=False, SaveWithDocument=True, 
                        Left=100, Top=100, Width=400, Height=300)

这种方法在Microsoft Office和WPS Office中都能很好地工作,不需要特别的兼容处理。

2. 通过剪贴板复制粘贴图片

这种方法更灵活,特别是在需要对图片进行预处理或从其他来源获取图片时:

import win32clipboard
from PIL import Image

# 打开图片并复制到剪贴板
image = Image.open(image_path)
output = tempfile.SpooledTemporaryFile(max_size=1024*1024)
image.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]  # 去掉BMP文件头
output.close()

# 将图片数据写入剪贴板
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
win32clipboard.CloseClipboard()

# 在PPT中粘贴图片(需要WPS兼容处理)
slide3.Select()
shape_picture = slide3.Shapes.Paste()

# WPS兼容处理逻辑...

这种方法在WPS中需要特别注意幻灯片激活和粘贴返回值的处理。

七、注意事项

  1. 应用程序可见性设置:在处理图形或需要界面交互的操作时,建议将应用程序设置为可见(Visible = True),特别是在操作PowerPoint时。

  2. 资源释放:使用完毕后,一定要调用Quit()方法关闭应用程序并释放COM对象,避免资源泄漏。

  3. 文件格式兼容性:Microsoft Office和WPS Office的文件格式虽然高度兼容,但在某些高级功能上仍可能存在差异。

  4. 运行权限:某些操作可能需要管理员权限才能执行,特别是在修改系统注册表相关的功能时。

  5. 错误处理:在实际应用中,应该添加完善的错误处理机制,以应对可能出现的各种异常情况。

  6. 环境准备:确保已安装所有必要的库,特别是在使用图片处理功能时,需要安装pillow库。

八、总结

通过本文介绍的方法,我们可以编写同时兼容Microsoft Office和WPS Office的Python代码,实现Excel、Word和PowerPoint文件的自动化操作。特别是通过添加set_word_textget_ppt_shapeset_ppt_text等兼容函数,以及特别处理PPT图片粘贴等操作,我们可以确保代码在不同的办公环境中都能稳定工作。

这种兼容方案可以大大提高办公自动化脚本的适用性,使其在企业内部的自动化系统或个人的办公效率工具中都能发挥重要作用,帮助用户节省时间和精力,提高工作效率。

希望本文对您有所帮助,如果您有任何问题或建议,欢迎留言讨论!