【Python自动化制作PPT材料(模仿人工操作)】


前言

例如:网上和书本中介绍的ppt自动化方法,多是一步步制作ppt,而实际例行工作中多是修改文字和数字,粘贴表格和图片等。所以研究了下可以通过excel配置ppt制作步骤的方法,便于模板不变材料的半自动化制作。核心是业务,本方法是技术上的辅助,模拟人工制作ppt的步骤。

该方法效果:个人平时25分钟制作完的ppt材料(纯制作,不含数据处理时间)。在excel配置好的情况下,点一下更新链接,然后选择ppt模板和逻辑excel,大概20s可以制作完24页ppt。文字更新速度很快,表格更新需要消耗一点时间。


一、用到的Python模块

1、tkinter:制作简单的操作界面;
2、win32com:模拟ppt和excel软件的操作,感觉与vba类似
3、pandas:读取表格数据用
4、re:判断并修改ppt中文字用
5、os:读取和保存文字用

二、程序说明

1.代码

代码如下:

# coding:utf-8
# Author:Matthew
from tkinter import *
from tkinter import filedialog
from tkinter.ttk import Progressbar
#分割路径和文件名
import os.path
#读取excel文件模块
import pandas as pd
#文本处理模块
import re
#设想,读取excel列表,图片名称、单击、间隔时长、步骤说明
#win32程序的操作模块
import win32com
from win32com.client import Dispatch, constants
import time
class MYauto():
    def __init__(self,init_window_name):
        #传递实例化的窗口
        self.init_windows_name = init_window_name
        #文件路径self.folder
        #是否找到
        self.isfind = 0
        self.error_texts =[]

    def set_init_window(self):
        # 设置窗体标题
        self.init_windows_name.title('Python GUI MakePPT.v3')
        # 设置窗口大小和位置
        self.init_windows_name.geometry('500x500+570+200')

        self.label1 = Label(self.init_windows_name, text='请选择PPT模板文件:')
        self.text1 = Entry(self.init_windows_name, bg='white', width=30)
        self.label2 = Label(self.init_windows_name, text='请选择excel逻辑文件:')
        self.text2 = Entry(self.init_windows_name, bg='white', width=30)
        self.label3 = Label(self.init_windows_name, text='请修改ppt保存名称:')
        self.text3 = Entry(self.init_windows_name, bg='white', width=30)
        self.label4 = Label(self.init_windows_name, text='记录:')

        self.button1 = Button(self.init_windows_name, text='浏览', width=8, command=self.selectPptfile)
        self.button4 = Button(self.init_windows_name, text='浏览', width=8, command=self.selectExcelfile)
        self.button2 = Button(self.init_windows_name, text='开始', width=8, command=self.main)
        self.button3 = Button(self.init_windows_name, text='保存', width=8, command=self.save_ppt)
        self.button5 = Button(self.init_windows_name, text='扫描ppt元素', width=12, command=self.lookshape)
        #消息文本框
        self.log_data_Text = Text(self.init_windows_name, bg='white', width=60,height=20)
        self.log_data_Text.pack()

        self.label1.pack()
        self.text1.pack()
        self.label2.pack()
        self.text2.pack()
        self.label3.pack()
        self.text3.pack()
        self.button1.pack()
        self.button4.pack()
        self.button2.pack()
        self.button3.pack()
        self.button5.pack()
        self.label4.pack()
        #设定位置
        self.label1.place(x=30, y=30)
        self.text1.place(x=150, y=30)
        self.label2.place(x=30, y=70)
        self.text2.place(x=150, y=70)
        self.label3.place(x=30, y=110)
        self.text3.place(x=150, y=110)
        self.button1.place(x=400, y=26)
        self.button4.place(x=400, y=66)
        self.button2.place(x=160, y=150)
        self.button3.place(x=260, y=150)
        self.button5.place(x=30, y=150)
        self.label4.place(x=30, y=185)

        # 创建滚动条
        self.scroll = Scrollbar()
        self.log_data_Text.place(x=30, y=210)
        # 将滚动条填充
        self.scroll.pack(side=RIGHT, fill=Y,padx=10,pady=100)  # side是滚动条放置的位置,上下左右。fill是将滚动条沿着y轴填充
        # 将滚动条与文本框关联
        self.scroll.config(command=self.log_data_Text.yview)  # 将文本框关联到滚动条上,滚动条滑动,文本框跟随滑动
        self.log_data_Text.config(yscrollcommand=self.scroll.set,state=NORMAL)  # 将滚动条关联到文本框

        #添加一个进度条
        self.var = IntVar()
        self.var.set(0)
        Progressbar(self.init_windows_name,variable=self.var,length=400).place(x=60, y=185)
        #self.progressbar1['value']

        #添加菜单
        #menu1 = Menu(self.init_windows_name)
        #menu1.add_command(label="帮助",command = self.help())
        #self.init_windows_name.config(menu=menu1)

    #def help(self):
        #初始显示信息
        self.write_log_to_Text("作者:大豆\n0.扫描ppt元素用于确定表格的shape编号\n1.通过浏览按钮选择好ppt模板和excel数据及逻辑即可开始\n2.完成后,请修改名称后点保存\nPS:逻辑的sheet页一定要放在第一个")



    def selectPptfile(self):

        #获取ppt模板文件信息
        self.file_path = filedialog.askopenfilename(title='选择PPT文件模板', filetypes=[('Ppt', '*.pptx'), ('All Files', '*')])
        self.write_log_to_Text(self.file_path)
        self.text1.insert(INSERT, self.file_path)
        #记录路径文件夹
        self.file_folder,self.f = os.path.split(self.file_path)
        self.text3.insert(INSERT, self.f)
        #打开ppt模板
        self.open_ppt(self.file_path)



    def selectExcelfile(self):

        #获取excel数据
        self.file_path2 = filedialog.askopenfilename(title='选择Excel文件模板', filetypes=[('Excel', '*.xlsx'), ('All Files', '*')])
        self.write_log_to_Text(self.file_path2)
        self.text2.insert(INSERT, self.file_path2)
        #记录路径文件夹
        self.file_folder2,f2 = os.path.split(self.file_path2)
        #打开excel逻辑及数据表,数据表在excel中做了链接
        self.open_excel(self.file_path2)

        #self.write_log_to_Text(self.Tj)

    def stop(self):
        #把程序停止
        self.isstart = 0
        pass

    def open_ppt(self,file_path):
        self.ppt = win32com.client.Dispatch('PowerPoint.Application')
        # 是否展示打开的文件
        self.ppt.Visible = True
        # 屏蔽错误弹框提示
        self.ppt.DisplayAlerts = False
        # 打开ppt,r'C:\python\MakePPT\20223月份运输优化方案.pptx'
        self.pptS = self.ppt.Presentations.Open(file_path)


    def open_excel(self,file_path):
        self.xlApp = win32com.client.Dispatch("Excel.Application")
        # 是否展示打开的文件
        self.xlApp.Visible = True
        # 屏蔽错误弹框提示

        # 打开excel,r'C:\python\MakePPT\逻辑MakePPT.xlsx'
        self.xlS = self.xlApp.Workbooks.Open(file_path, False)

    def write_textK(self,slide_order):
        '''
        对文本框内容进行查找,替换【数字】为所需数据或文字
        slide_order为ppt页数
        '''
        for i_shape in range(self.pptS.Slides(slide_order).Shapes.count):
            #
            shape_type = self.pptS.Slides(slide_order).Shapes(i_shape + 1).type
            if shape_type == 17 or shape_type == 1:  # 判断是否是文本框,并写入
                Text_shape = self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text
                self.write_log_to_Text(Text_shape)

                target_list = re.findall(r'[\[](.*?)[\]]', Text_shape)  # 匹配符合条件的【数字】

                if target_list == []:#如果没有就下一个
                    pass
                else:
                    for i_text in target_list:
                        self.write_log_to_Text(i_text)
                        # 找到替换所需值或文字
                        find_target = '[' + i_text + ']'
                        # 目标所在行
                        self.write_log_to_Text(find_target)
                        try:
                            Row_input = self.xlS.Worksheets(1).Cells.Find(What=find_target).Row
                        except:
                            self.write_log_to_Text("找不到该值,导入数据"+find_target)
                        else:
                            # 目标所在列
                            #self.xlS.Worksheets('PPT逻辑').Cells.Find(What=find_target).Column
                            # 获取G列导入数据,并改成文本格式
                            data_input = str(self.xlS.Worksheets(1).Cells(Row_input, 7).Value)

                            # 替换文本框的内容
                            self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text = \
                                self.pptS.Slides(slide_order).Shapes(i_shape + 1).TextFrame.TextRange.Text.replace(find_target,data_input)

            elif shape_type == 19:  # 判断是否是表格,并写入

                #slide_order,i_shape + 1
                #tableshape = Tj.loc[(Tj['类型'] == '表格') & (Tj['ppt页数'] == 2) & (Tj['shape'] == 4)]
                tableshape = self.Tj.loc[(self.Tj['类型'] == '表格') & (self.Tj['ppt页数'] == slide_order) & \
                                           (self.Tj['shape'] == i_shape + 1)]
                #找要转成图片的表格
                tablepic = self.Tj.loc[(self.Tj['类型'] == '图片') & (self.Tj['ppt页数'] == slide_order) & \
                                           (self.Tj['shape'] == i_shape + 1)]

                if len(tableshape) == 0 and len(tablepic) == 0:#如果没有就下一个
                    pass
                elif len(tableshape) != 0 and len(tablepic) == 0:
                    #用表格方式粘贴
                    for i_table in tableshape['index']:
                        # shape是i_shape+1,slide是
                        # excel数据源的单元区域
                        source_sheet = tableshape['数据源'][i_table]
                        source_data = tableshape['导入数据'][i_table]
                        try:
                            # zh
                            self.xlS.Worksheets(source_sheet).Range(source_data).Copy()
                            #保留原格式粘贴
                            self.pptS.Application.CommandBars.ExecuteMso("PasteSourceFormatting")
                            #不停一下会出错
                            time.sleep(0.6)
                            self.pptS.Application.windows(1).selection.ShapeRange.Left = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Left
                            self.pptS.Application.windows(1).selection.ShapeRange.Top = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Top
                            self.pptS.Application.windows(1).selection.ShapeRange.Width = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Width
                            self.pptS.Application.windows(1).selection.ShapeRange.Height = self.pptS.Slides(slide_order).Shapes(i_shape + 1).Height
                            #获取需要增大几次字号,相对的
                            Font_Increase = tableshape['字号增大N次'][i_table]
                            try:
                                #如果出错就跳过
                                Font_inc = int(Font_Increase)
                                #增大N次
                                for i_increase in range(Font_inc):
                                    #增大一下字号
                                    self.pptS.Application.CommandBars.ExecuteMso("FontSizeIncrease")
                            except:
                                pass

                            self.write_log_to_Text(
                                'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '已原格式粘贴更新')
                            # 删除原表格
                            self.pptS.Slides(slide_order).Shapes(i_shape + 1).delete()
                        except:
                            error_text = 'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '原格式粘贴更新失败'
                            self.write_log_to_Text(error_text)
                            self.error_texts.append(error_text)
                elif len(tableshape) == 0 and len(tablepic) != 0:
                    #用图片方式粘贴
                    for i_table in tablepic['index']:
                        #shape是i_shape+1,slide是
                        #excel数据源的单元区域
                        source_sheet = tablepic['数据源'][i_table]
                        source_data = tablepic['导入数据'][i_table]
                        try:
                            #zh
                            self.xlS.Worksheets(source_sheet).Range(source_data).Copy()
                            ins_shape = self.pptS.Slides(slide_order).Shapes.PasteSpecial(DataType=3)
                            #调整图片位置,依靠宽度,解除锁定纵横比
                            ins_shape.LockAspectRatio = 0
                            ins_shape.left = self.pptS.Slides(slide_order).Shapes(i_shape+1).Left
                            ins_shape.Top = self.pptS.Slides(slide_order).Shapes(i_shape+1).Top
                            ins_shape.Width = self.pptS.Slides(slide_order).Shapes(i_shape+1).Width
                            ins_shape.Height = self.pptS.Slides(slide_order).Shapes(i_shape+1).Height
                            self.write_log_to_Text('ppt'+str(slide_order)+'位置'+str(i_shape + 1)+'的表格'+'已用图片更新')
                            #删除原表格
                            self.pptS.Slides(slide_order).Shapes(i_shape + 1).delete()
                        except:
                            error_text = 'ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '的表格' + '图片更新失败'
                            self.write_log_to_Text(error_text)
                            self.error_texts.append(error_text)


                else:
                    #图片和表格两种更新方式冲突,需修改excel
                    self.write_log_to_Text('ppt' + str(slide_order) + '位置' + str(i_shape + 1) + '表格更新方式冲突,需修改excel')
            else:
                pass

    def save_ppt(self):
        #保存ppt
        ppt_name = self.text3.get()
        if ppt_name == self.f:
            self.write_log_to_Text("文件名称重复,请修改")
        else:
            self.write_log_to_Text(ppt_name)
            self.pptS.SaveAs(self.file_folder + '\\' + ppt_name)


    def main(self):
        #是否继续
        self.isstart = 1
        #标志是1,则开始执行
        #获取ppt逻辑数据
        self.Tj = pd.read_excel(self.file_path2,sheet_name=0).reset_index()
        #source_data = self.xlS.Worksheets('PPT逻辑')
        #从第1页开始,看是否要改

        for i_slide in range(self.pptS.Slides.count):
            # 切换到目标页
            self.pptS.Application.ActiveWindow.View.GotoSlide(i_slide+1)
            #开始写入
            self.write_textK(i_slide+1)
            #进度条
        self.var.set(80)
        self.write_log_to_Text('更新完成,可能存在以下错误:')
        self.write_log_to_Text(self.error_texts)


        #self.write_textK(2)
        #self.write_log_to_Text(i_slide+1)

        pass

    def lookshape(self):
        i = 1
        for slide in self.pptS.Slides:
            self.write_log_to_Text("第%d页ppt:" %(i))
            i+=1
            j = 1
            for shape in slide.shapes:
                if shape.type == 17:
                    type = "文本框"
                elif shape.type == 19:
                    type = "表格"
                elif shape.type == 1:
                    type = "形状"
                elif shape.type == 13:
                    type = "图片"
                elif shape.type == 7:
                    type = "公式"
                elif shape.type == 14:
                    type = "占位符"
                elif shape.type == 15:
                    type = "艺术字"
                else:
                    type = "其它"
                self.write_log_to_Text("shape %d : %s"%(j,type))
                j+=1
        pass
    def countshape(self,slides_order):
        #记录当前ppt中的shape数量,但是新粘贴的好像不计入,那么就默认加1
        i=0
        for shape in self.pptS.Slides(slides_order).Shapes:
            i+=1
        return i


    #日志打印
    def get_current_time(obj):
        current_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        return current_time
    #写入日志
    def write_log_to_Text(self,logmsg):
        current_time = self.get_current_time()
        logmsg_in = str(current_time) +" " + str(logmsg) + "\n"    #换行
        self.log_data_Text.insert(END, logmsg_in)
        self.log_data_Text.see(END)

    def operation(self,opt,key):
        pass

        #if opt == "输入":


if  __name__ == '__main__':
    init_window = Tk()              #实例化出一个父窗口
    MAIN_PROCESS = MYauto(init_window)
    # 设置根窗口默认属性
    MAIN_PROCESS.set_init_window()
    init_window.mainloop()


2.操作步骤

1、运行代码
2、选择ppt模板
3、选择逻辑excel
4、运行程序
5、修改文件名并保存
PS:如果第一次使用,需要将ppt制作成模板,并创建excel逻辑和数据表


3.PPT模板和EXCEL逻辑文件制作说明

提示:本方法只能更新文本框和表格。

1、PPT模板制作第一步是准备一个经常汇报的ppt
2、将里面要改的文字或数字,改成[1]、[2]、[3]等
3、在excel中写下[1]、[2]、[3]对应的内容
4、表格的话,需要用程序中的扫描,看下表格处于第几个位置(shape)
复制原表的话,可配合字号增大使用;粘成图片的话,凑活看也可以

建立EXCEL逻辑表

提示:EXCEL中必要的列,第一行列名必须有这几个,程序也是依此运行

列1ppt页数
列2数据源
列3类型
列4shape
列2目标位置
列3导入数据
列4字号增大N次

ppt页数:写上要修改的ppt页码
数据源:如果是文字不用写,可以做些链接用于自己更新数;如果是表格或图片形式粘表格的话,需要写明取自该excel的哪个sheet页
类型:写明是更新文字还是表格,还是用图片形式更新表格
shape:文字的话不用写,表格的话,需要写明表格的shape(用程序的扫描功能可以看到每页ppt的shape都是啥,找到表格是shape几)
目标位置:写明文字是要替换掉页面上的哪个位置,用英文括号和数字来制作ppt模板,如[1],表格不用写
导入数据:写入用什么来替换掉目标位置。可以写数字或文字
字号增大N次:因为发现表格粘贴后,文字可能会变小,增加此列,定性增大表格字号,相当于手动点字号增加。
其他列是辅助或标注用的。

在这里插入图片描述

配置PPT模板

1、想替换掉的地方改成英文中括号+数字
2、想更新表的地方,把表格大小拉至合适,程序复制粘贴后会保持一样大小,并删除原表
在这里插入图片描述
PS:这样在excel中可以自己设置各种公式,判断数字大小写不同文字等,并且excel中格式就是粘到ppt的格式,字号粘贴过程中容易变小,可定性增大。

使用过程如图
在这里插入图片描述
程序文件,可执行exe版文件、ppt和excel示例上传至付费资源中,上面的代码是全部了,用pycharm之类可以自己运行和制作模板。
https://download.csdn.net/download/weixin_44283188/85360428

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彼兔大豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值