最全面的Python自动化教程,包括:word、excel、ppt、pdf、视频等自动化代码生成,以及编辑音视频并添加字幕、添加水印、取消水印、加密文档、解密文档,十万字图文详细讲解使用方法(附源码)
人生苦短, 我用Python! Python语法简炼、易上手,且有丰富的库可用,实现一个应用很简洁。
Python常用于自动化。自动化的基本含义,是把人的动作写成程序,让计算机代替人工作。主要分为几类:
1、自动化办公:对excel、word、ppt等office文档或pdf进行批量化、自动化等处理。
2、自动化媒体处理:对图片、视频等媒体文件进行批量化、自动化等处理。
3、自动化机器人:比如微信客服/聊天机器人、网站操作/录入、网络爬虫/网页信息抓取、自动化数据服务等
由于python开发社区的广泛性,各类自动化python都有对应的库,可以很方便的调用。
Excel自动化
Excel自动化,是用Python程序创建、编辑、修改Excel文件,处理其中的数据,从而无人化、大批量处理excel文件数据。
处理excel常用的库有:openpyxl、xlwings、xlrd、xlwt等。数据处理的库常用 pandas
这里主要讲 openpyxl、xlwings、pandas 三个库。
一、首先用 PIP 安装 openpyxl、xlwings、pandas 库
打开命令行窗口,分别输入三行命令
pip install openpyxl
pip install xlwings
pip install pandas
为快速下载,可以使用 阿里云 镜像 (pandas 库比较大)
pip install openpyxl -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install xlwings -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install pandas -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
二、Excel的基本概念
WorkBook (工作簿) 一个Excel文件就是一个WorkBook(工作簿)
WorkSheet(工作表) 一个WorkBook(工作簿)中包含多张WorkSheet工作表。每个WorkSheet有一个标题(title), 如:Sheet1
Cell (单元格), 一个WorkSheet工作表包含多个单元格。一个单元格有行号、列号。例如:B3
Reference Address (引用地址): B3 表示一个单元格, B3:D6 表示一个区域(Range),包含多个单元格。 Sheet2!B3:D6 表示 工作表Sheet2中的 B3:D6 这个区域
三、openpyxl 库的基本使用方法
用PyCharm创建一个新项目,创建一个新的.py文件,在程序开头引用 openpyxl
import openpyxl
或
import openpyxl as xl
import openpyxl as xl 是将openpyxl库起一个别名xl, 以便后续程序简化书写
1, 打开Excel文件, 打印所有的工作表标题
import openpyxl as xl
filename = "202201报表.xlsx"
# 打开excel文件,取得workbook对象
workbook = xl.load_workbook(filename)
# 列出所有worksheet
for worksheet in workbook:
print(type(worksheet), worksheet.title) # 打印worksheet的类型, 标题
其中:excel文件 202201报表.xlsx 是这样的。
注意:
1、由于程序中未指明文件路径,因此要将 202201报表.xlsx 文件放在 .py程序文件同一目录下。
2、openpyxl 库只支持 .xlsx 文件, 不支持 后缀为 .xls 的老格式excel文件(Excel 2003之前的)。
3、如果执行程序时, excel文件正在被 Excel程序打开,会因为共享冲突而出错。
PermissionError: [Errno 13] Permission denied: ‘202201报表.xlsx’
运行程序,结果如下
<class 'openpyxl.worksheet.worksheet.Worksheet'> 商品销售
<class 'openpyxl.worksheet.worksheet.Worksheet'> 客户
<class 'openpyxl.worksheet.worksheet.Worksheet'> 库存
<class 'openpyxl.worksheet.worksheet.Worksheet'> 汇总
说明:
1、workbook = xl.load_workbook(filename) 打开文件。
如果要创建新的excel文件。一般情况下,是复制一个模板文件到新的文件。
例如:
import shutil
template_file = "报表模板.xlsx"
new_file = "新报表.xlsx"
# 使用shutil库的copyfile()函数复制文件,如new_file文件不存在则创建新文件
shutil.copyfile(template_file, new_file)
2、xl.load_workbook(filename)的返回值 workbook 是一个Workbook对象
3、通过 for worksheet in workbook: 循环可以获得每一张工作表 Worksheet对象
2, 通过标题,取得WorkSheet
# 如果 workbook 中有名为 '商品销售' 的 worksheet
if '商品销售' in workbook:
# 取得 worksheet
worksheet = workbook['商品销售']
3、通过地址取得单元格Cell对象, 读取单元格的值、修改值
# 取得一个单元格
cell = worksheet["B3"]
print(type(cell))
# 取得单元格的值
print(cell.value)
# 取得单元格的行号(数字, 第一行列为1), 列号(数字, A列为1)
print('row, col=', cell.row, cell.column)
# 取得单元格的另一个方法:使用row, col 数字
row = 3
col = 2
cell2 = worksheet.cell(row, col) # 相当于 B3
# 写入单元格的值
cell2.value = "北京"
运行程序,结果如下
<class 'openpyxl.cell.cell.Cell'>
深圳
row, col= 3 2
说明:
1、worksheet[address] 返回一个 Cell对象。 cell.value 可以读取或写入值
如果cell中有公式,则 cell.value 返回公式字符串,如: ‘= B2 + D2’, 如果要修改公式,直接将公式字符串赋值给 cell.value即可。例如: cell.value = ‘=B3+D2’
2、cell.row 取得单元格的行(整数,第一行是1)
cell.column 取得单元格的列(整数,A列 是1,依次类推)
3、取得单元格B3有两个写法: 第一种是使用引用地址字符串: worksheet[‘B3’]
第二种是使用 行、列数值, 如: worksheet(row=3, column=2) , 第二种便于书写循环程序,批量读取数值, 例如:
for row in range(1, 11):
for col in range(1, 5):
print(worksheet.cell(row, col).value)
4、通过地址取得一个区域(多个单元格), 读取区域的值
# 取得一个区域
range1 = worksheet['A1:B5']
print(range1)
# 取得区域内所有单元格的值
data = []
for row in range1:
row_values = []
for cell in row:
row_values.append(cell.value)
data.append(row_values)
print(data)
运行程序,结果如下
((<Cell '商品销售'.A1>, <Cell '商品销售'.B1>), (<Cell '商品销售'.A2>, <Cell '商品销售'.B2>), (<Cell '商品销售'.A3>, <Cell '商品销售'.B3>))
[['地区分类', '城市'], ['二类', '广州'], ['一类', '北京']]
说明:
range1 = worksheet[‘A1:B3’] # 取A1: B3区域
print(range1) 显示 range1 是一个tuple, 其中每一个子元素是一行(多个cell对象的 tuple),共3行,即range tuple包含了多个行、多个列的cell
for row in range1 这个循环列出每一行
for cell in row 这个循环列出一行内的每一个cell
row_values 是一行的数值列表
data 是所有数据的列表, print(data) 显示出所有cell的值
5、Worksheet 的最大行数、最大列数
# 工作表的最大行数
print(worksheet.max_row)
# 工作表的最大行数
print(worksheet.max_column)
工作表实际使用的最大行数、最大列数
6、保存文件(保存WorkBook),关闭文件(关闭WorkBook)
# 保存文件
workbook.save(filename)
# 关闭文件
workbook.close()
保存WorkBook,则将数据修改存入文件了。不保存直接关闭,修改就丢了。
7、openpyxl 库小结
以上是 openpyxl 库的基本操作,常规工作中基本够用了。比如:
(1) 合并报表:每个月有一个报表,通过python读取多个文件,写入另一个汇总文件。
(2)拆分报表:将一个汇总表,生成多个子表。
(3)读取或写入数据
(4)修改图表: 在excel文件中预先手工生成图表,修改数据即可更新图表。
openpyxl库还可以处理单元格的颜色、字体、边框,创建图表等复杂操作。但平时用的很少。一般情况,我们手工创建 excel文件模板、编写好公式、画好图表,python程序读写数值即可。
三、xlwings 库的基本使用方法
与openpyxl库一样, xlwings库可以读写excel文件。不同的是, xlwings库是调用本机安装的Microsoft Excel程序打开并读写excel文件,因此运行 python程序的本机必须安装Excel程序。相反,openpyxl库不依赖Excel程序,因此openpyxl可以在linux服务器上使用。 同时,由于xlwings使用Microsoft Excel, 因此能打开老式的 .xls文件, 具有Microsoft Excel所具备的一切能力。
import xlwings as xw
# 创建 App对象
app = xw.App(visible=True, add_book=False)
print(type(app))
# 使用App对象, 打开excel文件
filename = "202201报表.xlsx"
workbook = app.books.open(filename)
print(type(workbook))
# 列出所有 worksheet
for sheet in workbook.sheets:
print(type(sheet), sheet.name) # 注意:要使用 sheet.name 取得工作表标题
workbook.close()
app.quit() # 退出Excel程序
运行结果:
<class 'xlwings.main.App'>
<class 'xlwings.main.Book'>
<class 'xlwings.main.Sheet'> 商品销售
<class 'xlwings.main.Sheet'> 客户
<class 'xlwings.main.Sheet'> 库存
<class 'xlwings.main.Sheet'> 汇总
说明:
1, 与openpyxl库不同, 使用xlwings库时,首先要创建 App对象,再用App对象打开excel文件
app = xw.App(visible=True, add_book=False)。 一个App对象就是 一个Excel程序实例。
visible=True 表示显示Microsoft Excel界面。运行时可以看到Excel界面出现了。
add_book=False 表示打开Excel 程序时,不添加空白工作表
2, 通过 for worksheet in workbook: 循环可以获得每一张工作表 (与openpyxl库一样)
3,使用 worksheet.name 取得工作表标题。 (与openpyxl库使用 worksheet.title 不同)
4,由于是使用Excel程序打开文件,打开后文件被锁定,其他程序将无法同时读写该excel文件。
5,结束前,要调用 app.quit() 退出Excel程序 (否则Excel程序将不会关闭)
2, 通过标题,取得WorkSheet
# 取得 标题是 '商品销售' 的 worksheet
worksheet = workbook.sheets('商品销售')
print(type(worksheet))
说明: xlwings库不支持 in 写法: if ‘标题’ in workbook
3、通过地址取得单元格, 读取单元格的值、修改值
# 取得一个单元格 B3
cell = worksheet['B3']
print(type(cell), cell.value) # 打印cell的类型, 读取cell的值
# 设置单元格的值
cell.value = "新城"
# 取得单元格的行号(数字, 第一行列为1), 列号(数字, A列为1)
print('row, col=', cell.row, cell.column)
# 取得 E2 格中的公式、 值
print(worksheet['E2'].formula, worksheet['E2'].value)
说明:
(1)、worksheet[address] 返回一个 Range 对象。 cell.value 可以读取或写入值
(2)、cell.row 取得单元格的行(整数,第一行是1)
cell.column 取得单元格的列(整数,A列 是1,依次类推)
(3)、使用 cell.formula 读取或设置单元格的公式, 使用 cell.value读取或设置单元格的值
# 另一种方式:使用row, col 数字取得 B3 单元格
row = 3
col = 2
cell2 = worksheet.cells(row, col)
print(type(cell2), cell2.value)
(4)、取得单元格B3的第二种写法是使用 行、列数值, 如: worksheet(row, column)
4、通过地址取得一个区域(多个单元格), 读取区域的值
# 取得一个区域
range1 = worksheet['A1:B3']
# 取得区域内所有单元格胡值
print(range1.value)
运行结果:
<class 'xlwings.main.Range'> 新城
[['地区分类', '城市'], ['二类', '广州'], ['一类', '新城']]
可以看到: range1.value 直接返回一个 list, 每个元素表示一行,直接是各单元格的值。(这个比openpyxl 方便一点)
5、保存文件(保存WorkBook),关闭文件(关闭WorkBook)、退出App
# workbook 保存
workbook.save(filename)
# workbook 关闭
workbook.close()
# 注意:要退出 app(即关闭Microsoft Excel程序)
app.quit()
6、xlwings 库基本用法小结
xlwings 库用法与 openpyxl库 大同小异。
7、xlwings库的特殊用法:在Microsoft Excel程序中调用 python程序
xlwings 库有一个很好用的功能:将python程序作为Microsoft Excel的插件/扩展程序运行,就是说,无需打开Python 或 PyCharm, 在Excel程序中直接运行python。另外,也可以用python语言为Exce编写用户自定义函数(User Defined Function, 简称UDF), 扩展Excel的功能。
众所周知, Microsoft Office程序(包括Excel) 支持 以Visual Basic for Application 或 CSharp 语言编写扩展程序,允许用户增强Excel的功能。 xlwings作为python与Excel的桥梁,支持将python程序作为Microsoft Excel的插件/扩展程序运行。
使用方法如下。
首先,关闭Excel程序, 打开命令行窗口,输入以下命令,安装 xlwings for Excel 的插件 (addin).
xlwings addin install
运行结果:表明xlwings for Excel 的插件(addin) 安装成功。
xlwings version: 0.27.11
Successfully installed the xlwings add-in! Please restart Excel.
There is already an existing ~/.xlwings/xlwings.conf file. Run ‘xlwings config create --force’ if you want to reset your configuration.
然后, 重新启动Microsoft Excel程序, 则可以看到 Excel 多了一个名为 xlwings 的菜单页
菜单页上有多个选项和文本框,不用管它们。我们只使用上图最左边红色方框指示的 "Run Main"这个按钮就够了。
按下 “Run Main” 按钮会发生什么呢?
比如:当前打开的文件名是 abcd.xlsx, 当按下 “Run Main” 按钮,Excel会调用xlwings库,xlwings库将寻找 与 abcd.xlsx 文件同一个目录下的同名.py文件 (即:abcd.py), 运行这个python文件中的 main() 函数。 main() 函数以python编写,写什么内容都行,比如:可以从网络、或数据库读取数据,再写入工作表中。
注意:
1、xlwings库不支持中文名的.py文件。因此,使用该功能的excel文件名不能包含中文(否则出错)。
2、xlwings库将以import 模块的方式加载 .py文件。 因此,使用该功能的excel文件名必须以英文字母开头、且不能包含空格、特殊字符等,excel文件名必须是一个合法的python变量名,且不能与已有的python库重名。否则出错。
3、本人认为,上述两点是xlwings库的bug。 没办法只能遵守。 (PS: 本人将xlwings addin 改了一下,可不受此限制)
实战:
将 “202201报表.xlsx” 文件复制一份,改名为 abcd.xlsx, 在同目录下编写一个名为 abcd.py 程序文件。程序如下:
import xlwings as xw
def main():
# 获得调用本程序的 workbook
workbook = xw.Book.caller()
# 获得当前激活的 worksheet
worksheet = xw.sheets.active
# 在 B9 单元格中写入一个数值
worksheet['B9'].value = "你好,我来了"
abcd.py 中只定义了一个 main() 函数, 该函数无输入参数。
代码注释写得很清楚: 首先用 xw.Book.caller() 获得调用本程序的 workbook对象,然后,取得当前工作表,在单元格B12中写入一串文字。
用Excel程序打开abcd.xlsx, 点击 xlwings菜单的 "run main"按钮, 运行效果如下:
如图: 在Excel程序中,点击 xlwings 菜单中的 Run main 按钮(左上红框), B9单元格(蓝框) 将自动写入python程序运行的结果。
实际上, .py程序可以是任意合法的python程序,可以调用各种库、写多个函数。
xlwings为扩展Excel功能提供了无限的潜力和想象力.
比如: 读取Excel单元格中的股票名称,到网络上查出该股票当前价格。
读取Excel单元格中的人员名称,在数据库中查出该人员上班有否迟到。
总之,运行python, 一切都可行。
xlwings for Excel 插件功能是否很棒呢!
在excel文件 ”202201报表.xlsx“ 的 “商品销售” Worksheet 上 自动找到 值为 “广州” 的单元格:
import openpyxl
def find(sheet1, value):
""" 在sheet1中查找值为value的单元格, 找到到返回Cell对象,找不到则返回None"""
for row in range(1, sheet1.max_row + 1):
for col in range(1, sheet1.max_column + 1):
cell = sheet1.cell(row, col)
if cell.value == value:
return cell
filename = "202201报表.xlsx"
workbook = openpyxl.load_workbook(filename)
cell = find(workbook['商品销售'], '广州')
运行结果: <Cell ‘商品销售’.B2>
在excel文件 ”202201报表.xlsx“ 的 “商品销售” Worksheet 上 自动找到两个值 “广州”, “金额” 的两个单元格交叉的单元格的值, 就是说:找到广州的金额:
import openpyxl
def find(sheet1, value):
""" 在sheet1中查找值为value的单元格, 找到返回Cell对象,找不到则返回None"""
for row in range(1, sheet1.max_row + 1):
for col in range(1, sheet1.max_column + 1):
cell = sheet1.cell(row, col)
if cell.value == value:
return cell
def find2(sheet1, value1, value2):
""" 在sheet1中查找值为value1, value2的两个单元格, 返回其交叉的Cell,找不到则返回None"""
cell1 = find(sheet1, value1)
cell2 = find(sheet1, value2)
if cell1 and cell2:
return sheet1.cell(cell1.row, cell2.column)
def find_file(filename, sheetname, value1, value2):
""" 在文件中,指定工作表名, 查找值为value1, value2的两个单元格, 返回其交叉的Cell,找不到则返回None"""
workbook = openpyxl.load_workbook(filename)
if sheetname in workbook:
return find2(workbook[sheetname], value1, value2)
# 使用范例: 查找 商品销售表中 广州的金额
cell = find_file("202201报表.xlsx", '商品销售', '广州', '金额')
if cell:
print(cell.value)
else:
print('not found')
运行结果: 1003
找到广州的金额是1003
这个是有用的,比如说:每月有一个报表文件,我们要找到某个月,某业务,某地区的金额。
使用场景可以是: 你对微信机器人讲,请找2022年1月广州商品销售金额。机器人分析后,定位为202201报表.xlsx文件,把数据找出来,回答你。这个故事我们将在随后的章节中实现它。
在excel文件 ”202201报表.xlsx“ 的 “库存” Worksheet 上, 表格的位置不是从 A1开始的:
自动找到 “库存” Worksheet中的表格:
import openpyxl
def find_first_cell(sheet1):
""" 在sheet1中查找值不为空的第一个单元格, 找到返回Cell对象,找不到则返回None"""
for row in range(1, sheet1.max_row + 1):
for col in range(1, sheet1.max_column + 1):
cell = sheet1.cell(row, col)
if cell.value is not None:
return cell
def expand_column(cell):
""" 从单元格cell出发,水平向右查找,找到最后一个不为空值的Cell对象 """
for col in range(cell.column + 1, cell.parent.max_column + 2):
c = cell.parent.cell(cell.row, col)
if c.value is None:
return cell.parent.cell(cell.row, col - 1)
def expand_row(cell):
""" 从单元格cell出发,垂直向下查找,找到最后一个不为空值的Cell对象 """
for row in range(cell.row + 1, cell.parent.max_row + 2):
c = cell.parent.cell(row, cell.column)
if c.value is None:
return cell.parent.cell(row - 1, cell.column)
def find_table(sheet1):
""" 查找sheet1中的首个表格。 返回 tuple, 每一个元素是一行Cell. 找不到则返回空的tuple """
result = []
cell = find_first_cell(sheet1) # 查找值不为空的第一个单元格
if cell:
cell1 = expand_column(cell) # 向右扩展
cell2 = expand_row(cell) # 向下扩展
if cell1 and cell2:
# 构造返回值
for row in range(cell.row, cell2.row + 1):
r = []
for col in range(cell.column, cell1.column + 1):
r.append(cell.parent.cell(row, col))
result.append(tuple(r))
return tuple(result)
# 使用范例
filename = "202201报表.xlsx"
workbook = openpyxl.load_workbook(filename)
sheet1 = workbook['库存']
area = find_table(sheet1)
if len(area) > 0:
print(area)
else:
print("not found")
运行结果:
((<Cell ‘库存’.B6>, <Cell ‘库存’.C6>, <Cell ‘库存’.D6>), (<Cell ‘库存’.B7>, <Cell ‘库存’.C7>,…
这个结果与使用 sheet[‘B6:D10’] 返回值是一样的。
使用场景可以是: 你对微信机器人讲,请查一下库存情况。机器人分析后,定位为当前 月份是202201, 查找202201报表.xlsx文件的库存工作表,把表格找出来,列个表回答你。
使用pandas库
一、首先用 PIP 安装 openpyxl、xlwings、pandas 库
打开命令行窗口,分别输入三行命令
pip install openpyxl
pip install xlwings
pip install pandas
为快速下载,可以使用 阿里云 镜像 (pandas 库比较大)
pip install openpyxl -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install xlwings -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
pip install pandas -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
由于pandas库将使用openpyxl 或 xlwings 库读写excel文件,因此openpyxl 或 xlwings必须最少安装一个。
二、pandas 简介
Pandas 是一个开放源码、BSD许可的python库,提供高性能、易于使用的数据结构和数据分析工具,广泛应用于办公、学术、金融、统计学等各个数据分析领域。
Pandas 可以从各种文件格式比如 Excel文件、CSV文件、JSON、数据库SQL等 导入数据或导出数据。
Pandas 名字衍生自术语 “panel data”(面板数据)。
Pandas库使用Numpy库提供高性能的矩阵运算, 安装Pandas库时,Numpy库将自动安装。
三、pandas 的基本数据结构
Pandas 的主要数据结构是 Series类 (一维数据系列)与 DataFrame类(二维数据表)。
Series对象保存一组数据,类似于一维数组列表,例如: [1, 2, 3, 4].
DataFrame 对象是一个表格型的数据结构,有多个列、多个行,类似于Excel表格或数据库的表。
提取DataFrame的一列或一行将获得一个Series对象。类似于数据库,DataFrame有索引列,用于加快查找。
三、pandas 读取 / 保存 excel 文件
用PyCharm创建一个新项目,创建一个新的.py文件,在程序开头引入 pandas
import pandas as pd
PS: 开发社区习惯于用 pd 作为 pandas 的别名
1、从excel文件读入数据表
import pandas as pd
# read DataFrame from excel
df = pd.read_excel('202201报表.xlsx')
print(type(df))
print(df)
其中:excel文件 202201报表.xlsx 是这样的。
运行程序,结果如下:
<class 'pandas.core.frame.DataFrame'>
地区分类 城市 销量 金额 单价
0 一类 广州 20773 1003.0 0.048284
1 一类 深圳 32005 1233.8 0.038550
2 二类 东莞 13433 567.3 0.042232
3 二类 佛山 13898 522.5 0.037595
4 二类 中山 9878 225.0 0.022778
说明:
(1) pd.read_excel(filename) 读取excel文件,返回值 df 是一个 DataFrame 对象。
如果excel文件中有多个worksheet, 则 pd.read_excel() 默认将读取第1个worksheet
(2) print(df) 显示 DataFrame 是一个表格,其中:第一列 [0, 1, 2, 3, 4] 是pandas自动加上的行号索引列
2、对于有多个worksheet的excel文件, 指定worksheet的名称, 读入数据表
# 指定worksheet的名称,读入数据表
df = pd.read_excel('202201报表.xlsx', sheet_name="客户")
print(df)
说明: 从名为 "客户"的 worksheet 中读入数据表
3、将DataFrame保存到excel文件
# 将DataFrame存入excel文件(注意:直接使用 to_excel() 将会丢弃原excel文件中的其他worksheet)
filename = '新报表.xlsx'
df.to_excel(filename, sheet_name="商品销售", index=False)
说明:
(1) df.to_excel(filename, sheet_name) 将 DataFrame 对象的数据保存入 excel文件中。
index=False 表示不保存索引列
(2) 但是直接使用 to_excel() 有一个问题:如果存盘excel文件已经存在,则原excel文件中的其他worksheet将会被丢弃。所以, 直接使用 to_excel() 仅限于生成新excel文件,不适合于将数据存入已有excel文件.
4、将DataFrame保存到已有的excel文件
import openpyxl
import pandas as pd
def save_to_exist_excel(df, filename, sheet_name, index=False,
startrow=0, startcol=0, **kwargs):
"""
将DataFrame存入已有的excel文件
:param df: DataFrame 对象
:param filename: Excel 文件名
:param sheet_name: 工作表名称(标题)
:param index: (可选)索引列是否保存
:param startrow: (可选)开始写入的行号, 第一行为0, 第二行为1, ...
:param startcol: (可选)开始写入的列号, A列为0, B列为1 ...
:param kwargs: (可选)其他参数
:return: None
"""
book = openpyxl.load_workbook(filename)
writer = pd.ExcelWriter(filename, engine='openpyxl')
writer.book = book
writer.sheets = {}
for ws in book.worksheets:
writer.sheets[ws.title] = ws
df.to_excel(writer, sheet_name=sheet_name, index=index,
startcol=startcol, startrow=startrow, **kwargs)
writer.save()
# 读出数据
filename = '202201报表.xlsx'
df = pd.read_excel('202201报表.xlsx', sheet_name="商品销售")
df.loc[1, '城市'] = "新城" # 修改单元格
# 将DataFrame存入已存在的excel文件
save_to_exist_excel(df, filename, sheet_name="商品销售")
说明:
(1) 将 DataFrame 对象的数据保存到已有的 excel文件稍微有点复杂。在此,提供一个函数 save_to_exist_excel(df, filename, sheet_name, index=False), 各参数说明见注释。
函数中使用了openpyxl库。
对于 .xlsx 文件读写, pandas 默认调用openpyxl库。
(2) 上面的例程显示了 save_to_exist_excel()的使用。
四、Pandas 的行、列的基本读写
1、df.columns 是一个 Series 对象,保存着每一列的名称
# df. columns 是一个 Series 对象
print(df.columns)
# 显示每一列的名称
for i in range(len(df.columns)):
print(df.columns[i])
2、取得一列
# 如果存在名为"城市"的列
if '城市' in df.columns:
column = df['城市'] # 取得名为"城市"的一列
print(type(column)) # column 是一个 Series 对象
print(column)
print(column[0]) # 取得 columns 第1个数据(索引号从0开始)
print(column.to_list()) # 将series转换为 list
运行结果:
<class 'pandas.core.series.Series'>
0 深圳
1 东莞
2 广州
3 佛山
Name: 城市, dtype: object
深圳
['深圳', '东莞', '广州', '佛山']
3、取得一行
# 取得一行 (Series)
if len(df) > 0:
row = df.iloc[0] # 取得第一行(从0开始)
print(type(row)) # row 是一个 Series 对象
print(row)
print(row['城市']) # 取得该行中 列名为"城市"的单元格的值
说明:.iloc[row_number] 是以行号取得一行
4、取得或写入一个单元格的值
# 取得一个格子的值
print(df.loc[1, '城市'])
# 写入一个格子的值
df.loc[1, '城市'] = "新城"
print(df.loc[1, '地市'])
# 取得 金额列的 最大、最小、平均值
print(df['金额'].max(), df['金额'].min(), df['金额'].mean())
说明: .loc[index, column_name] 是以 行号索引、列名取得一个单元格
5、DataFrame有多少行、多少列
print(len(df)) # len(df)取得行数
print(len(df.columns)) # len(df.columns)取得列数
五、数据查询:取得 DataFrame的子集
DataFrame是一个数据集合。数据查询就是取得 DataFrame 的子集。
1、简单查询
import pandas as pd
# read DataFrame from excel
df = pd.read_excel('202201报表.xlsx')
# 取df的子集:取开头的两行
print(df.head(2))
# 取df的子集:取最后的3行
print(df.tail(3))
# 取df的子集:仅取两列
df2 = df[['城市', '金额']]
print(df2)
# 查询:取df的子集,返回金额 > 600的所有行
df3 = df[df['金额'] > 600]
print(df3)
# 查询:取df的子集:返回金额 > 600的所有行
df5 = df.query('金额 > 600')
print(df5)
说明:
(1) df.head(2) 返回最开始的 2行。 相当于数据库SQL语言中的:
select top 2 from df
类似的: df.tail(3) 返回最末尾的 3行
(2) df[[‘城市’, ‘金额’]] 表示只取’城市’, '金额’两列, 相当于数据库SQL语言中的:
select 城市, 金额 from df
(3) df[df[‘金额’] > 600] 返回金额 > 600的所有行, 相当于数据库SQL语言中的:
select * from df where 金额 > 600
(4) 查询有两种形式:
第一种是 python 列表风格: df[df[‘金额’] > 600]
第二种是 数据库风格 : df.query(‘金额 > 600’)
这两种是等价的。对于熟悉数据库SQL语言的人来说,第二种更熟悉一些
(5) 返回的df子集是 原df 的 复制品。修改子集不会影响原df.
2、复合查询
# 复合查询:取df的子集:返回金额 > 600 且 销量 < 25000的所有行
df4 = df[(df['金额'] > 600) & (df['销量'] < 25000)]
print(df4)
# 复合查询:取df的子集:返回金额 <= 600 或 销量 < 25000的所有行
df4 = df[(df['金额'] <= 600) | (df['销量'] < 25000)]
print(df4)
# 复合查询:取df的子集:金额 > 600 且 销量 < 25000的所有行
df6 = df.query('金额 <= 600 and 销量 < 25000')
# 复合查询:取df的子集:金额 <= 600 或 销量 < 25000
df6 = df.query('金额 <= 600 or 销量 < 25000')
print(df6)
# 取得 df6 的 城市列表
print(df6['城市'].to_list())
说明:
(1) df[(df[‘金额’] > 600) & (df[‘销量’] < 25000)] 是一个两个条件的复合查询。 ‘&’ 是 and(且) 的意思。注意:每一个条件必须以括号 ()把它括起来,否则会出错。
同理, ‘|’ 是 or(或) 的意思, 每一个条件也必须以括号 ()把它括起来,否则会出错。
注意: 在这种形式的查询中, ‘&&’, ‘||’ , ‘and’, ‘or’ 都是不能写的。
(2) df.query(‘金额 <= 600 and 销量 < 25000’) 是SQL语言的查询形式,可以不写括号。与上面的等价。
df.query(‘金额 <= 600 or 销量 < 25000’) 是 or 的关系。
3、排序
# 对金额排序 (逆序: 从大到小)
df7 = df.sort_values('金额', ascending=False)
print(df7)
说明: sort_values(列名) 对数据行进行排序, ascending 缺省是 True, 由小到大排序。
以上程序相当于SQL语言中的: select * from df order by 金额 desc
如果要以两个以上的进行排序,则写为: df.sort_values([‘地区分类’,’金额’]) , 意思是先按 地区分类排序,如相同,再按 金额排序. 相当于SQL语言中的:
select * from df order by 地区分类, 金额
4, 写在一起:一个较完整的查询
# 取地区分类为二类的前两名的城市、金额
df8 = df.query('地区分类 == "二类"').sort_values('金额', ascending=False).head(2)[['地区分类', '城市', '金额']]
print(df8)
说明:以上程序 既有查询,也有排序、取部分行、取部分字段。相当于SQL语言中的:
select top 2 地区分类, 城市, 金额 from df where 地区分类=“二类”
5, 分组统计
import pandas as pd
import numpy as np
# read DataFrame from excel
df = pd.read_excel('202201报表.xlsx')
# 分类统计
df8 = df.groupby("地区分类").agg({"城市": np.size, "金额": np.sum})
print(df8)
说明:
(1) .groupby(‘地区分类’) 是按照 地区分类 列进行分组, 类似于与SQL语言中的GROUP BY
(2) .agg() 是对分组进行统计
agg() 的参数是一个 dictionary, key是列名, value是numpy库中的统计函数名. np.size 是统计个数(相当于SQL语言中的 count), np.sum是统计加总值(相当于SQL语言中的 sum)
(3) 上面的程序,相当于 SQL语句:
select 地区分类, count(城市), sum(金额) from df group by 地区分类
六、DataFrame 列计算
1、按列赋值,或从其他列计算产生新的列
import pandas as pd
# 读取数据表
df = pd.read_excel('202201报表.xlsx')
# 增加一列,设为统一值:'未定义'
df['价值档次'] = '未定义'
# 增加一列,取值:从其他列计算产生
df['单价'] = df['金额'] * 10000 / df['销量']
print(df)
说明:
(1) df[‘价值档次’] = ‘未定义’, 对’价值档次’列统一赋值为‘未定义’。
因为原df中没有’价值档次’列, 则该列自动增加。 如果该列已有,则更新值。
(2) df[‘单价’] = df[‘金额’] * 10000 / df[‘销量’] # 单价=金额*10000/销量
因为原df中没有’单价’列, 则’单价‘列自动增加.
2、增加一个分类列
# 增加一列:价值档次 默认值为 低价值
df['价值档次'] = '低价值'
# 当 单价 >= 300, 价值档次 为 中价值
df.loc[df['单价'] >= 300, '价值档次'] = '中价值'
# 当 单价 >= 400, 价值档次 为 高价值
df.loc[df['单价'] >= 400, '价值档次'] = '高价值'
print(df)
说明:分类列的值由其他列按条件多次计算产生
3、更改列名称
# 将列名 单价 更改为 平均金额
df.rename(columns={'单价': '平均金额'}, inplace=True)
说明:可以一次更改多个列名,例如:columns={‘单价’: ‘平均金额’, ‘城市’: ‘地方’}
inplace=True的意思是就地,即:更改原df的值。之前说过,DataFrame的操作结果默认是产生一个新的DataFrame,复制原DataFrame的值,不修改原df的值。 当指定inplace=True时,则修改原df的值。
4、按列排序
# 按 平均金额列 就地排序(逆序),更改原df的值
df.sort_values('平均金额', ascending=False, inplace=True)
说明:
(1) sort_values(列名) 是按列排序, 如果要求按两列以上排序,则写为一个list, 例如:
sort_values(['地区分类', '平均金额‘])
(2) inplace=True的意思是‘就地’,即:更改原df的值。
七、两个DataFrame的合并
1、 纵向合并
import pandas as pd
# 读取表1
df1 = pd.read_excel('202201报表.xlsx')
# 读取表2
df2 = pd.read_excel('202202报表.xlsx')
# print(df2)
# 将 df1, df2 合并(纵向合并、df2的行排在df1后)为df3
df3 = pd.concat([df1, df2])
print(df3)
说明:
(1) pd.concat([df1, df2]) 是将 df2的行排在df1后, 每一行内容不变,即:纵向合并
2、横向合并
# 读取表1
df1 = pd.read_excel('202201报表.xlsx')
# 从worksheet '客户' 中 读取表
df4 = pd.read_excel('202201报表.xlsx', sheet_name='客户')
# 将 df1, df2 横向合并, 关联字段是 城市, 体会:how="outer", how="inner" 有何区别
df5 = pd.merge(df1, df4, on='城市', how="inner")
print(df5)
# 将 df1, df2 横向合并, 关联字段是 城市, 体会:how="outer", how="inner" 有何区别
df5 = pd.merge(df1, df4, on='城市', how="outer")
print(df5)
说明:
(1) df5 = pd.merge(df1, df4, on=‘城市’, how=“inner”
将 df1, df2 横向合并, 关联字段是 城市。 相当于 SQL语句:
select df1.*, df4.* from df1, df2 where df1.城市=df4.城市
(2) how 参数表达关联的方式。
how="inner" 时, 如果有一个城市在 df1 中存在,在df4中不存在,则该行将删去。
how="outer" 时, 如果有一个城市在 df1 中存在,在df4中不存在,则该行将保留。
八、从其他文件或数据格式中导入、导出数据
Pandas的数据导入、导出能力是很强的。
Pandas 支持从 excel文件、csv文件、json文件、数据库SQL查询等导入数据, 提供名为 read_xxx()的一系列函数, 这些函数的返回值均是一个DataFrame对象:
pd.read_excel(filename) # 读取 excel文件
pd.read_csv(filename) # 读取 .csv 文件
pd.read_json(filename) # 读取 json 文件
pd.read_html(html_text) # 读取 html 文本
pd.read_sql(sql, db_connection) # 在数据库连接中执行SQL,读取数据
DataFrame 支持将数据导出为 excel文件、csv文件、json、dict、数据库等,DataFrame对象有名为 to_xxx()的一系列方法:
df.to_excel(filename) # 导出 excel文件
df.to_csv(filename) # 导出 .csv 文件
df.to_json(filename) # 导出 json 文件
df.to_html() # 导出 html 文本
df.to_sql(name, db_connection) # 导出到数据库,写入数据
df.to_dict() # 导出 dictionary 对象
同时, DataFrame类支持以 list, dict 等数据直接创建。
Pandas 的导入、导出功能为数据的生成、转换、保存提供了方便。
1、.csv 文件导入、导出
.csv 文件是逗号分割的文本文件。
import pandas as pd
# 从 excel 文件读取DataFrame
df = pd.read_excel('202201报表.xlsx')
print(df)
# DataFrame存盘为 .csv 文件, index=False表示不存索引列
df.to_csv('202201.csv', index=False)
# 从 .csv 文件读取DataFrame
df = pd.read_csv('202201.csv')
print(df)
说明: 调用 df.to_csv() 是, 参数index=False表示不保存索引列。
用文本编辑器打开 202201.csv 文件,结果如下:
地区分类,城市,销量,金额
一类,广州,20773,1003.0
一类,新城,32005,1233.8
二类,东莞,13433,567.3
二类,佛山,13898,522.5
二类,中山,9878,225.0
2、html 文本的导入、导出
import pandas as pd
# 从 excel 文件读取DataFrame
df = pd.read_excel('202201报表.xlsx')
print(df)
# DataFrame导出为html文本,index=False表示不存索引列
html = df.to_html(index=False)
print(html)
# 从 html 文本读取
# read_html(html) 的返回值是一个DataFrame列表
# html 可以是一个网页URL
df_list = pd.read_html(html)
if len(df_list) > 0:
df = df_list[0] # 取得第1个DataFrame
print(df)
说明: read_html(url) 可以方便地从网页读取其中的表格, 返回值是一个DataFrame列表。但是,如果网页html书写不规范,则会抛出错误: lxml.etree.XMLSyntaxError
DataFrame导出的html文本,结果如下:
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th>地区分类</th>
<th>城市</th>
<th>销量</th>
<th>金额</th>
</tr>
</thead>
<tbody>
<tr>
<td>一类</td>
<td>广州</td>
<td>20773</td>
<td>1003.0</td>
</tr>
<tr>
<td>一类</td>
<td>新城</td>
<td>32005</td>
<td>1233.8</td>
</tr>
<tr>
<td>二类</td>
<td>东莞</td>
<td>13433</td>
<td>567.3</td>
</tr>
<tr>
<td>二类</td>
<td>佛山</td>
<td>13898</td>
<td>522.5</td>
</tr>
<tr>
<td>二类</td>
<td>中山</td>
<td>9878</td>
<td>225.0</td>
</tr>
</tbody>
</table>
3、从 excel 文件导入、导出 (指定单元格位置)
上文 讲了 read_excel(), to_excel() 的基本用法。
但是,仍然有一个问题, 之前读取的excel表格都是从工作表的 A1单元格开始的, 如果表格不是从A1格开始,比如, 202201报表.xlsx文件中的 '库存‘工作表数据开始于B6格, 则导入、导出数据不对。 如何处理呢?
3.1 从 excel 文件导入, 指定工作表,指定表格开始的行和需要的列
import pandas as pd
# 从 excel 文件读取DataFrame, 指定工作表为 "库存"
# 参数 skiprows=range(0,5) 表示跳过 0-4行共5行(第一行为0, range函数中5不包含)
# 参数 usecols 表示使用哪几行作为列(第一列为0), [1, 2, 3] 表示 B, C, D 列
df = pd.read_excel('202201报表.xlsx', sheet_name="库存",
skiprows=range(0, 5), usecols=[1, 2, 3])
print(df)
运行结果:从B6格开始正确读出表格 ( B, C, D 三列)
城市 库存数量 金额
0 广州 3233897 289.8
1 深圳 4287005 367.5
2 东莞 1532353 212.0
3 佛山 1232232 199.0
3.2 写入 excel 文件, 指定工作表,指定表格开始的行号和列号
将DataFrame写入 excel文件中,如果不是从 A1格开始写入,需在 to_excel()函数中使用 startcol, startrow 参数。 使用上文提供的 save_to_exist_excel() 函数, 如下
import pandas as pd
import openpyxl
def save_to_exist_excel(df, filename, sheet_name, index=False,
startrow=0, startcol=0, **kwargs):
"""
将DataFrame存入已有的excel文件
:param df: DataFrame 对象
:param filename: Excel 文件名
:param sheet_name: 工作表名称(标题)
:param index: (可选)索引列是否保存
:param startrow: (可选)开始写入的行号, 第一行为0, 第二行为1, ...
:param startcol: (可选)开始写入的列号, A列为0, B列为1 ...
:param kwargs: (可选)其他参数
:return: None
"""
book = openpyxl.load_workbook(filename)
writer = pd.ExcelWriter(filename, engine='openpyxl')
writer.book = book
writer.sheets = {}
for ws in book.worksheets:
writer.sheets[ws.title] = ws
df.to_excel(writer, sheet_name=sheet_name, index=index,
startcol=startcol, startrow=startrow, **kwargs)
writer.save()
# 从 excel 文件读取DataFrame, 指定工作表为 "库存"
# 参数 skiprows=range(0,5) 表示跳过 0-4行共5行(第一行为0, range函数中5不包含)
# 参数 usecols 表示使用哪几行作为列(第一列为0), [1, 2, 3] 表示 B, C, D 列
df = pd.read_excel('202201报表.xlsx', sheet_name="库存",
skiprows=range(0, 5), usecols=[1, 2, 3])
df.loc[1, '城市'] = "新城" # 修改一个单元格的值,以体现变化
print(df)
# 写入Excel文件, startrow=5 表示从第6行开始(第1行为0), startcol=1表示从第2列开始(第1行为0)
save_to_exist_excel(df, '202201报表.xlsx', sheet_name="库存", startrow=5, startcol=1)
4、DataFrame 与 dictionary 的相互转换
import pandas as pd
# 从 dictionary 创建DataFrame
dict1 = {
"Name": ["Peter", "Sam", "Mary"],
"Age": [22, 35, 58],
"Sex": ["male", "male", "female"],
}
df = pd.DataFrame(dict1)
print(df)
# 将 DataFrame 转化为 dictionary
d = dict(df.to_dict("series"))
dd = {}
for key in d:
dd[key] = list(d[key])
print(dd)
5、DataFrame 与 list 的相互转换
# 从 list 创建DataFrame
list1 = [
['Name', 'Age', 'Sex'],
["Peter", 22, "male"],
["Sam", 35, "male"],
["Mary", 58, "female"],
]
df = pd.DataFrame(list1[1:], columns=list1[0])
print(df)
# 将 DataFrame 转化为 list
print(df.to_dict("split"))
# 从 list 创建DataFrame
list2 = [
{'Name': 'Peter', 'Age': 22, 'Sex': 'male'},
{'Name': 'Sam', 'Age': 35, 'Sex': 'male'},
{'Name': 'Mary', 'Age': 58, 'Sex': 'female'}
]
df = pd.DataFrame(list2)
# 将 DataFrame 转化为 list
print(df.to_dict(orient="records"))
# orient='records' : list like [{column -> value}, … , {column -> value}]
6, DataFrame 与 json 文本的 相互转换
# 从 json 文本中 创建DataFrame
json = '[{"Name":"Peter","Age":22,"Sex":"male"},{"Name":"Mary","Age":58,"Sex":"female"}]'
df = pd.read_json(json)
# 将 DataFrame 转化为 json 文本
json = df.to_json(orient="records")
自动生成PPT文件
自动化办公中,经常要批量处理office文件。
比如:每月花很多时间写PPT,能自动生成PPT,就好了。
1、office库简介
本人用 python 写了一个 office库,用于办公自动化,功能是很强的, 包括:PPT自动生成、PPT转长图、PPT带语音播放、Word自动生成、Excel数据处理、图片处理、视频处理、office文档转为PDF、PDF加解密、加水印等等,都是实用的干货。
使用方法极简,大多数功能只需一行、两行代码。
1.1、一行代码自动生成PPT的实战效果
import office
# 以 template.pptx 为模板,创建 output.pptx 文件, 填入datafile.xlsx文件数据, 保存
office.open_file("output.pptx", "template.pptx").fill('datafile.xlsx').save()
代码简单,但生成的PPT效果却是不简单的。如图:
1.2、使用PIP 安装office库:
请在命令行,通过PIP安装:
pip install jojo-office
office库的安装名称是 jojo-office
使用时, import office 即可。
import office
office库依赖库包括:python-docx, openpyxl, python-pptx, PyPDF4, reportlab, playsound等, 安装时将自动安装完成。
如需要导入导出DataFrame, 则依赖 pandas 库,请按需要安装
pip install pandas -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
office库只支持新版的office文件(扩展名为 .docx, .xlsx, .pptx),不支持office2003以前的老版本office文件(扩展名为 .doc, .xls, .ppt)。
2、自动生成PPT文件的原理
自动生成PowerPoint文件的方法是:首先写一个模板PowerPoint文件,复制模板创建新文件,再填入数据。 填入不同的数据,则产生不同的PPT文件,从而实现批量生成, 比如:使用每个月的Excel报表文件数据,生成当月的PPT。
模板PPT文件就是一个普通的PPT文件,内容和格式按需要写。只不过在要填入数据的地方,写入变量即可。变量的写法如下:
比如:模板PowerPoint文件 template.pptx, 幻灯片中的文字内容如下:
其中:大括号 { xxx } 包含文字叫作变量。{name}、{age}就是变量。
生成PPT的过程就是填入数据,将变量将替换为相应的值。name变量将替换为name的值。age变量将替换为age的值。
注意:要使用英文的大括号,不要使用全角字符的大括号,否则变量将无法识别。
3、将Excel文件作为数据源,填入PowerPoint模板文件
3.1 文字
Excel文件是 datafile.xlsx,其 Sheet1工作表B2单元格内容是 ‘Peter’, C2格内容是 18。
模板PowerPoint文件 template1.pptx 写成这样:
变量 {Sheet1!B2} 指明 数据来自 Excel文件的 Sheet1 工作表的 B2 单元格。
变量 {Sheet1!C2} 指明 数据来自 Excel文件的 Sheet1 工作表的 C2 单元格。
生成PPT的python程序如下:
import office
# 以 template1.pptx 为模板,创建 output.pptx 新文件
# 如果 output.pptx 文件已存在,则将覆盖原文件
ppt = office.open_file("output.pptx", template="template1.pptx")
# 从 datafile.xlsx 文件中取数据, 填入, 保存
ppt.fill('datafile.xlsx').save()
上述程序也可以连写为一行,如:
office.open_file("output.pptx", "template1.pptx").fill('datafile.xlsx').save()
程序运行后,生成 output.pptx 文件, 其内容如下:
小结:
写模版文件就是在适当的位置写入变量。变量以 { 号开头,} 号结尾。
指向Excel数据的变量名就是 工作表及单元格的引用地址, 如: {Sheet1!B2} 。
生成PPT就是填入数据。同一模板生成不同的PPT,更换数据即可。
填入数据时,格式(包括字体、大小、位置、颜色)都没有变。
模版PPT文件可以包含多张幻灯片,每一页上都可写入变量,数量不限。
3.2 表格
在模板PPT中创建表格,表格的每一列定义一个变量,可以把多行数据填入PPT表格中。
datafile.xlsx 的 Sheet1工作表有一个表格
模板文件 template2.pptx 中画了一个表格 4行 X 2列,每一列的第一行写上变量,写成这样:
python程序如下:
import office
ppt = office.open_file("output.pptx", template="template2.pptx")
# 从 datafile.xlsx 文件中取数据, 填入, 保存
ppt.fill('datafile.xlsx').save()
程序运行后,生成 output.pptx 文件, 其内容如下:
可见,Excel的表格数据,填入到PPT表格中了。
注:填入表格的数据行数,取决于PPT模板中表格的行数。如果Excel表格行数大于PPT表格行数,则后面的数据不会被填入。
3.3 图表
在PPT模板中创建图表。每个图表有一个数据表,将图表数据表每一列定义为一个变量。生成PPT时,数据将填入PPT图表的数据表,则PPT图表将更新。
在PowerPoint程序中打开模板文件 template3.pptx,创建一个直方图。
在PowerPoint程序中, 右键单击图表,选择菜单:“编辑数据", 则可以看到图表的数据表。
修改数据表的第一行,每一列的第一行修改为变量,例如:{商品销售1!B1} 表示本列的数据来自 Excel数据文件的 商品销售工作表 的 B列。 修改后数据表如下图:
python程序如下:
import office
# 以 template3.pptx 为模板,创建 output.pptx 文件, 填入datafile.xlsx 文件数据, 保存
office.open_file("output.pptx", "template3.pptx").fill('datafile.xlsx').save()
程序运行后,生成 output.pptx 文件, 其内容如下:
可见, PPT图表已更新。
在PowerPoint中打开刚才生成的文件 output.pptx,右键单击图表,选择菜单:“编辑数据",
则可以看到PPT图表的数据表已经被更改为Excel文件的相应数据表,如下:
事实上, office库的处理方法,就是更新PPT图表的数据表后, 重建图表。
注:office库的图表功能目前支持2D图表,不支持3D图表。因此,模板中的图表不能是3D图表类型。
3.4 插入图片、视频、音频
如果数据是图片文件名,则可以在PPT中插入该图片文件。
模板文件 template4.pptx 中画了一个文本框,填入文字,写上变量 {@Sheet1!D2},变量名前加上一个 ‘@’字符表明它是一个特殊变量。当它是一个图片文件名时,将插入该图片文件。模板如图:
python程序如下:
import office
# 以 template4.pptx 为模板,创建 output.pptx 文件, 填入datafile.xlsx 文件数据, 保存
office.open_file("output.pptx", "template4.pptx").fill('datafile.xlsx').save()
注意: datafile.xlsx 文件 Sheet1!D2 单元格 的值是 “peter.jpg”,是一个图片文件名。 该文件名没有指明路径,因此这个图片文件要放在当前目录下。当然,文件名使用绝对路径则没有问题。
程序运行后,生成 output.pptx 文件, 其内容如下。可见,PPT文档插入了一张图片 peter.jpg, 图片大小和位置与变量所在的文本框一致。
同理, .mp3, .mp4 等音频、视频文件也可以插入PPT文档。
3.5 生成PPT综合报告
将上述 文字、表格、图表、图片功能合在一起,可以生成PPT综合报告了。
数据文件在 datafile.xlsx , 这个文件中有多个工作表: 商品销售、客户、库存、汇总。
模板文件 template5.pptx 是一个典型的PPT报告,有表格、图表、文字、图片等。其内容如下:
python程序如下:
import office
# 以 template5.pptx 为模板,创建 report.pptx 文件, 填入datafile.xlsx 文件数据, 保存
office.open_file("report.pptx", "template5.pptx").fill('datafile.xlsx').save()
程序运行后,生成 output.pptx 文件, 其内容如下:
3.6 将PPT存盘为一张长图
一张长图就是把PPT每一页变成图片,连接为一张长图。
注意:存盘为长图的功能,需要本机安装了Microsoft Powerpoint程序或WPS Office
打开pptx文件,存盘为一个jpg文件,即可保存为一张长图。
python程序如下:
# 打开 report.pptx, 存盘为 一张长图 (注:存盘文件名为一个jpg文件,就是保存为一张长图)
office.open_file("report.pptx").save("long.jpg")
如果长图需要加水印,则在调用save()时加上 watermark 参数, 程序如下:
# 打开 report.pptx, 存盘为 一张长图 (注:存盘文件名为一个jpg文件,就是保存为一张长图)
office.open_file("report.pptx").save("long.jpg", watermark="商业秘密,注意保管")
一张漂亮的长图就产生了。
3.6 将PPT存盘为PDF
# 打开 report.pptx, 存盘为PDF, 加水印
office.open_file("report.pptx").save("report.pdf", watermark="商业秘密,注意保管")
存为PDF,save()文件名取名为 .pdf 即可。 watermark是水印文字。
注意:PPTX转PDF的功能,需要本机安装了Microsoft Powerpoint程序或WPS Office
4、循环播放PPT,同步播放语音
放PPT,每隔几秒自动翻页,播放到最后一页后跳回第一页,循环播放
python程序如下:
# 循环播放PPT,打开 report.pptx, 播放PPT, 每隔3秒换到下一页
office.open_file("report.pptx").play(3)
程序运行后,将启动Microsoft Powerpoint程序(或WPS Office),自动进入全屏模式,逐页显示PPT,循环播放。上面的代码是每隔3秒换一页。播放过程中,按ESC键中断播放,退出程序。
注意:播放PPT的功能,需要本机安装了Microsoft Powerpoint程序或WPS Office
如果每一页的跳转时间不同,可以把间隔时间写成一个数组。
office.open_file("report.pptx").play([1, 3, 2, 1])
间隔时间数组 [1, 3, 2, 1] 的含义是: 第一页停1秒,第二页停3秒,第三页停2秒,第四页停1秒。
如果有更多页,把数组写长即可。
播放PPT时,可以在播放到某个页面时同步播放语音文件。
# 循环播放PPT, 在第2页时,播放语音文件 1.wav
office.open_file("report.pptx").play([
1,
[3, "1.wav"],
3,
[1, "2.wav"]
])
把间隔时间数组中,需要播放语音的页面位置写成 数组, 形如: [间隔秒数,语音文件名]。
如上, 当播放到第二页时,播放 1.wav, 停留3秒。 当播放到第四页时,播放 2.wav, 停留1秒。
也可以把播放间隔写成一个文本文件。 比如: play.txt,内容如下:
1
3 1.wav
3
1 2.wav
格式为: 每一行表示一页PPT的播放 间隔秒数 + 空格 + 语音文件名。
则,python程序中, 引用这个文件即可。
office.open_file("report.pptx").play("play.txt")
效果与之前用数组表达的是一样的。
播放PPT带语音的应用场景:例如: 开展览会时,自动放PPT+语音。省去解说人员。
小结:
1, office库提供了强大的PPT生成功能。
2, 写一个模板PPT文件,编写变量。填入数据,即可生成PPT.
3, 数据可以放在Excel文件中。变量为 Excel的 {工作表!单元格} 即可。
4,PPT可以存为长图。可以带语音播放。
用 python 写了一个 office库,用于办公自动化,功能是很强的, 包括:PPT自动生成、PPT转长图、PPT带语音播放、Word自动生成、Excel数据处理、图片处理、视频处理、office文档转为PDF、PDF加解密、加水印等等,都是实用的干货。
使用方法极简,大多数功能只需一行、两行代码
使用PIP 安装office库:
请在命令行,通过PIP安装:
pip install jojo-office
office库的安装名称是 jojo-office
使用时, import office 即可。
import office
office库依赖库包括:python-docx, openpyxl, python-pptx, PyPDF4, reportlab, playsound等, 安装时将自动安装完成。
5、将 dictionay 作为数据源,填入PowerPoint模板文件
写一个模板PPT文件,编写变量。填入dictionay 数据,即可生成PPT。只是,以dictionary为数据源时,变量写法有一点不同。
模板文件 template6.pptx 如下, 变量名就是dictionary的key值。 注:图表的变量输入,要右键点击图表,点击“编辑数据”菜单,在数据表第一行写入变量。
python代码如下:
import office
data = {
"姓名": "Peter",
"年龄": 18,
"相片": "peter.jpg",
'学习': {
'课程': ['语文', '数学', '英语'],
'成绩': [95.3, 68, 75],
'评价': ['优', '差', '中']
}
}
# 以 template6.pptx 为模板,创建 report.pptx 文件, 填入data dict数据, 保存
office.open_file("report.pptx", "template6.pptx").fill(data).save()
生成PPT如下:
说明:
该示例演示了, 在填入dictionay数据时,文字、图片、表格、图表的变量写法。
6、将 DataFrame对象作为数据源,填入PowerPoint模板文件
pandas库的 DataFrame 对象,也可以作为填充的数据源。
模板文件 template7.pptx 如下,
变量写法:
1, 变量 {课程[0]} 表示 DataFrame 的 “课程”列的第0行
2, 对于表格,第一行写: 以 DataFrame的列名 为变量
图表的变量输入,要右键点击图表,点击“编辑数据”菜单,在数据表第一行写入变量。以 DataFrame的列名 为变量
7、多个数据源,多次填入PowerPoint文件
有时,有多个数据源,可以多次调用 fill() 多次填入数据。
模板文件 template8.pptx 如下,
模板中, 表格中的 {Sheet1!B1} 等变量数据来自 Excel.
{姓名} {年龄} 等变量数据来自 dictionary
python 程序如下:
import office
person = {"姓名": "Peter", "年龄": 18, "相片": "peter.jpg"}
# 以template8.pptx为模板创建文件, 填入datafile.xlsx文件数据, 再填入person数据,保存
office.open_file("report.pptx", "template8.pptx").fill('datafile.xlsx').fill(person).save()
运行结果 生成report.pptx 如下:
可见, 经过两次调用fill()分别填入了 Excel文件数据 和 dictionary 数据。 多个数据源合成在一个PPT文件中了。
8、重复产生幻灯片
比如:有一个3个人的人员名单表,一张幻灯片的PPT模板,按人员数量每人生成一张幻灯片。
datafile.xlsx 的 Sheet1工作表有一个表格
模板文件 template9.pptx 如下,
模板中, 变量名前加了 @repeat 标志,表明这个变量需要重复生成幻灯片。 Sheet1!D1变量前还有一个 @ 符, 表明这个变量值是一张图片。
python 程序如下:
# 以 template9.pptx 为模板,创建 report.pptx 文件, 填入datafile.xlsx 文件数据, 保存
office.open_file("report.pptx", "template9.pptx").fill("datafile.xlsx").save()
生成的 report.pptx 如下:
可见, 模板中的一张幻灯片,变成了3张幻灯片,分别填入了 Excel表格中各行的数据,其中: Sheet1!D1 所在的数据 是图片文件名, 插入了图片。
小结:
本篇介绍了 使用office库自动生成PPT的进一步的方法。总结PPT自动生成的特点:
1, office库提供了强大的PPT生成功能。
2, 写一个模板PPT文件,编写变量。填入数据,即可生成PPT.
3,填入数据可以生成PPT的文字、表格、图表,可以插入图片
4, 数据可以放在Excel文件中。变量为 Excel的 {工作表!单元格} 。
5, 数据可以是 dictionary。变量为 键名,如:{key}。
6, 数据可以是 DataFrame。变量为 列名,如:{column} 。
7、对数据列表,支持重复生成幻灯片
8,PPT可以存为长图带水印、存为PDF。PPT可以带语音播放。
自动生成Word文件
office库简介
office库是笔者写的python库,用于办公自动化,功能是很强的, 包括:PPT自动生成、PPT转长图、PPT带语音播放、Word自动生成、Excel数据处理、图片处理、视频处理、office文档转为PDF、PDF加解密、加水印等等,都是实用的干货。
使用方法极简,大多数功能只需一行、两行代码。
使用PIP 安装office库:
请在命令行,通过PIP安装:
pip install jojo-office
office库的安装名称是 jojo-office
使用时: import office 即可。
import office
office库依赖库包括:python-docx, openpyxl, python-pptx, PyPDF4, reportlab, playsound等, 安装时将自动安装完成。
如需要导入导出DataFrame, 则依赖 pandas 库,请按需要安装
pip install pandas -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
office库只支持新版的office文件(扩展名为 .docx, .xlsx, .pptx),不支持office2003以前的老版本office文件(扩展名为 .doc, .xls, .ppt)。
五、自动生成Word文件
1、一行代码自动生成Word的实战效果
import office
# 以 试卷模板.docx为模板,生成output.docx, 填入datafile.xlsx文件数据,保存
office.open_file("output.docx", "试卷模板.docx").fill("datafile.xlsx").save()
生成了一张试卷 output.docx 文件, 如下:
一张漂亮的考试卷就产生了, 有单选题、多选题、简答题、编程题等等
2、自动生成Word文件的原理
自动生成Word文件的方法是:首先写一个模板Word文件,复制模板创建新文件,再填入数据。
填入不同的数据,则产生不同的文件内容。
例如:模板Word文件 template.docx 的文字内容如下:
姓名 : {name}
年龄 : {age}
大括号 { } 中包含的叫变量, 上例中的:name, age。
在填入数据时,变量将替换为相应的值。
2.1 将Excel数据填入Word文件
Excel文件 datafile.xlsx 中,Sheet1工作表B2单元格内容是 ‘Peter’, C2格内容是 18。
则,模板Word文件 template1.docx 写成这样:
姓名 : {Sheet1!B2}
年龄 : {Sheet1!C2}
python程序如下:
import office
# 以 template1.docx 为模板,创建 output.docx 文件
wd = office.open_file("output.docx", template="template1.docx")
# 从 datafile.xlsx 文件中取数据, 填入, 保存
wd.fill('datafile.xlsx').save()
上述程序也可以连写为一行:
office.open_file("output.docx", template="template1.docx").fill('datafile.xlsx').save()
程序运行后,生成 output.docx 文件, 其内容如下:
姓名 : Peter
年龄 : 18
可见,Excel文件中的数据,替换了 Word文档中的变量,生成了Word文档内容。
小结:
写模版文件就是在适当的位置写入变量。变量以 { 号开头,} 号结尾。
指向Excel数据的变量名就是 工作表及单元格的引用地址, 如: {Sheet1!B2} 。
生成Word就是填入数据。同一模板生成不同的Word文件,更换数据即可。
填入数据时, Word 文字格式(包括字体、大小、位置、颜色)都没有变。
2.2 将dictionary数据 填入Word文件
模板Word文件 template3.docx 写成这样:
姓名 : {name}
年龄 : {age}
即: 有两个变量 name, age
python程序如下:
import office
# 数据
data = {'name': 'Peter', 'age': 18}
# 以 template3.docx 为模板,创建 output.docx 文件
wd = office.open_file("output.docx", template="template3.docx")
# 填入数据data, 保存
wd.fill(data).save()
上述程序也可以连写为一行:
office.open_file("output.docx", template="template3.docx").fill(data).save()
程序运行后,生成 output.docx 文件, 其内容如下:
姓名 : Peter
年龄 : 18
如果 dictionary 是多层级的,比如:
data = { 'friend': { 'name': 'Mary', 'age': 19} }
则模板写为:
姓名:{friend.name}
年龄:{friend.age}
2.3 多次填入数据
如果数据分布在多个Excel文件或 dictionary 中,可以多次调用fill()填充数据,例如:
wd = office.open("output.docx", "template.docx")
# 先填充 1.xlsx Excel数据,再填充 dict1 数据
wd.fill('1.xlsx').fill(dict1).save()
2.4 重复书写文字段落
有时,我们需要重复写某些文字段落,比如:列出人员名单。
Excel文件 datafile.xlsx 的 Sheet1工作表B2:C4区域有一个表格。
模板Word文件 template2.docx 写成这样:
{@repeat 姓名 : {Sheet1!B2}, 年龄 : {Sheet1!C2} }
‘{@repeat’ 表明需要重复,重复部分为 ‘姓名 : {Sheet1!B2}, 年龄 : {Sheet1!C2}’。
注意最后有一个 } 符号,与 {@repeat 形成闭环。
重复次数由其中的变量决定。 从 Sheet1!B2 开始,每次向下读取一行 Sheet1!B3、Sheet1!B4 … 直达空值为止。
python程序如下:
import office
wd = office.open_file("output.docx", template="template2.docx")
# 从 datafile.xlsx 文件中取数据, 填入, 保存
wd.fill('datafile.xlsx').save()
程序运行后,生成 output.docx 文件, 其内容如下:
姓名 : Peter, 年龄 : 18
姓名 : Sam, 年龄 : 19
姓名 : Mary, 年龄 : 2
因为Excel表格数据有三行,所以重复了3次。
2.5 将Word文件另存为PDF
python程序如下:
# 打开 output.docx 文件, 另存为 output.pdf
office.open_file("output.docx").save("output.pdf")
注: 存为PDF的功能需要本机安装有Microsoft Word或 WPS,(Windows环境)。
3、应用示例:
3.1 应用示例:邀请函
开大会,每个客户要打印一张纸的邀请函。
把客人姓名、称谓写入列表,写一个循环,生成一批word文件, 打印它们即可。
模板文件见邀请函模板.docx, 大致内容如下:
尊敬的{name}{title}:
您好!我们很荣幸地邀请您...
python代码如下:
import office
persons = [
["张三", "先生"],
["李四", "女士"],
["王五", "总经理"],
]
filenames = []
for person in persons:
data = {'name': person[0], 'title': person[1]}
filename = person[0] + ".docx"
office.open_file(filename, "邀请函模板.docx").fill(data).save()
filenames.append(filename)
# 可以使用 print_files() 批量打印文件
office.print_files(filenames)
程序运行后,生成了 3个Word文件。
3.2 应用示例:生成一张考试卷
一张考试卷, 有多道选择题、多道简答题等等。
将题目、选项等数据写在Excel文件 datafile.xlsx 的 '试卷’工作表中。
模板文件为 试卷模板.docx, 内容大致如下。
模板说明:
{日期} 是从 dict 数据中填入的。
其他数据均来自 Excel数据的 '试卷’工作表
‘一’ 这个部分的 重复段落 ‘{@repeat … }’ 中包括四行。
第一行是 {@index}序号、{试卷!A6}题目、{试卷!F6}答案。
{@index} 是一个特殊变量,表示重复的序号。
第二行是 {试卷!B6} 选项A 、 {试卷!C6} 选项B。
第三行是 {试卷!D6} 选项C 、 {试卷!E6} 选项D。
第四行是一个空行。表示每道题之间空一行。
python程序如下:
import office
wd = office.open_file("output.docx", "试卷模板.docx")
wd.fill('datafile.xlsx') # 填入Excel数据
wd.fill({'日期': '2022年'}) # 填入变量 '日期'
wd.save()
程序运行后,生成 output.docx 文件, 其内容如下:
一张漂亮的考试卷就产生了, 有单选题、多选题、简答题、编程题等等。
Word模板文件只是定义了试卷的组成部分和格式、变量。
试卷的所有数据内容都是在Excel文件中定义。
以上方法是通用的, 可以生成任何试卷、或其他类型的文档。
小结:
1, office库提供了 Word生成功能。
2, 写一个模板Word文件,编写变量。填入数据,即可生成Word文件.
3, 数据可以放在Excel文件中。变量为 Excel的 {工作表!单元格}。
4, 数据可以是 dictionary。变量为 键名,如:{key}。
5,段落可以重复生成
6, Word可以存为PDF。
PDF文件处理
office库简介
office库是笔者写的python库,用于办公自动化,功能是很强的, 包括:PPT自动生成、PPT转长图、PPT带语音播放、Word自动生成、Excel数据处理、图片处理、视频处理、office文档转为PDF、PDF加解密、加水印等等,都是实用的干货。
使用方法极简,大多数功能只需一行、两行代码。
使用PIP 安装office库:
请在命令行,通过PIP安装:
pip install jojo-office
office库的安装名称是 jojo-office
使用时: import office 即可。
import office
六、PDF文件处理
1,各类office文档转为PDF
对于 Word, Excel, Power文档,均可存为PDF文件 (office库调用相应Office程序完成,需本机安装有Office)。
import office
# 打开word文件,存为pdf文件
office.open_file("input.docx").save("output.pdf")
# 打开excel文件,存为pdf文件
office.open_file("input.xlsx").save("output2.pdf")
# 打开ppt文件,存为pdf文件
office.open_file("input.pptx").save("output3.pdf")
2,提取PDF部分页面
import office
# 打开PDF文件
pdf = office.open_file("report.pdf")
# 取得页数
total_pages = len(pdf)
# 需要的页的列表
need_pages = [0, 1]
# 存盘为新文件,只保留需要的页
pdf.save("report_0_1.pdf", pages=need_pages)
说明:
1, 调用 save()方法时, pages 参数指定一个页数列表 (第一页为0, …), 则存盘时只保存指定的页,其他页不要了。
2, 对pdf对象, len(pdf) 将返回pdf文件的总页数。
3, office.open_file() 可以打开 .pdf文件, 返回 PDF类的对象。也可以直接调用PDF类打开文件,效果是一样的:
pdf = office.PDF("report.pdf")
3,PDF文件加密
PDF文件支持密码。
# 打开PDF文件, 存盘时加上 password 参数,则存盘pdf文件将有密码保护
office.open_file("report.pdf").save("report_encrypted.pdf", password="123")
4,PDF文件解密
import office
# 打开已加密的PDF文件时,应加上 password 参数
pdf = office.open_file("report_encrypted.pdf", password="123")\
# 再存盘时,不加 password 参数,则存盘文件将无密码。
pdf.save("report_new.pdf")
干货: pdf文件的密码不能太简单,否则,他人可以通过暴力破解法轻松获得密码(暴力破解法就是拿一个密码字典,一个一个密码不断去试,直到攻破)。 office库提供了一个 对PDF文件的 guess_password() 的方法,支持密码字典破解。破解程序如下:
import office
# 打开已加密的PDF文件时, 注意:没有password参数
pdf = office.open_file("report_encrypted.pdf")
# 调用 guess_password() 方法,进行密码破解
password = pdf.guess_password()
print('password is', password)
程序运行结果: password is 123
可见,弱密码是多么可怕。一个不弱的密码应不少于8个字符,由大小写字母、数字、特殊符号组成,不要用连续数字、字母、生日、手机号码等。
可以自己写一个密码字典文件(文本文件,每一行是一个密码),调用 guess_password() 时代入字典文件名即可,如下:
# 字典文件是 dict.txt
pdf.guess_password("dict.txt")
5,PDF文件加水印
import office
# 打开PDF文件
pdf = office.open_file("report.pdf")
# 存盘时,加上 watermark 参数,则存盘文件将有水印文字
pdf.save("report_with_mark.pdf", watermark="商业秘密,注意保管")
注意:
1, 加水印功能依赖 reportlab 库, 请先安装
2, 加水印并不是十分安全的,因为有方法可以去水印 (PS: 不详细讲了).
6, 提取PDF文件中的文字、表格
注意: 取pdf文字、表格的功能,依赖 pdfplumber 库,请先安装: pip install pdfplumber
# 打开PDF文件
pdf = office.open_file("report.pdf")
# 获得PDF文件中的文字
text_list = pdf.text()
print(text_list)
# 获得PDF文件中的表格,返回值是一个列表,每个元素是一个表格(一个表格是一个二维数组)
table_list = pdf.tables()
print(table_list)
程序运行结果:
业务发展汇报
2022年01月
编制人
...
[[['城市', '销量', '金额'], ['广州', '20773', '1003'], ['深圳', '32005', '1233.8'], ...
如果只想取某一页的文字、图标,则代码为:
# 打开PDF文件
pdf = office.open_file("report.pdf")
# 获得第2页中的文字 (注:第1页索引号为0)
text = pdf.pages[1].text()
print(text)
# 获得第2页中的文字
table_list = pdf.pages[1].tables()
print(table_list)
说明: pages[index] 可以取得某一页, 再调用 text(), tables()
PPT的自动化
在日常工作中,我们总是需要创建或修改PPT。但你也可以用Python来创建或修改PPT文件。本文将告诉你如何使用Python-pptx模块自动或用PPT模板生成ppt,以及如何通过实例修改现有的PPT。
1.Python模块python-pptx。
python-pptx是Python的一个处理ppt文件的库。它的重点是读写,不能导出,也没有渲染功能。
在使用python-pptx模块之前,需要在终端运行命令**pip3 install -i [pypi.doubanio.com/simple/pyth…]
$ pip3 install -i https://pypi.doubanio.com/simple/ python-pptx
Looking in indexes: https://pypi.doubanio.com/simple/
Collecting python-pptx
Downloading https://pypi.doubanio.com/packages/eb/c3/bd8f2316a790291ef5aa5225c740fa60e2cf754376e90cb1a44fde056830/python-pptx-0.6.21.tar.gz (10.1 MB)
|████████████████████████████████| 10.1 MB 2.1 MB/s
Preparing metadata (setup.py) ... done
Requirement already satisfied: lxml>=3.1.0 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from python-pptx) (4.6.2)
Requirement already satisfied: Pillow>=3.3.2 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from python-pptx) (9.0.1)
Requirement already satisfied: XlsxWriter>=0.5.7 in /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages (from python-pptx) (1.3.7)
Using legacy 'setup.py install' for python-pptx, since package 'wheel' is not installed.
Installing collected packages: python-pptx
Running setup.py install for python-pptx ... done
Successfully installed python-pptx-0.6.21
在终端中运行命令pip show python-pptx来确认安装。
$ pip show python-pptx
Name: python-pptx
Version: 0.6.21
Summary: Generate and manipulate Open XML PowerPoint (.pptx) files
Home-page: http://github.com/scanny/python-pptx
Author: Steve Canny
Author-email: python-pptx@googlegroups.com
License: The MIT License (MIT)
Location: /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages
Requires: lxml, Pillow, XlsxWriter
Required-by:
2.如何使用python-pptx模块创建一个带有简单文本的PPT。
下面的示例源代码将使用python-pptx模块创建一个PPT。
它还将设置PPT的标题和副标题文本,然后将其保存为一个pptx文件。
# Import the Presentation class from the pptx module.
from pptx import Presentation
# Create an instance of the Presentation class.
prs = Presentation()
# Create the title slide.
title_slide_layout = prs.slide_layouts[0]
# Add the title slide to the PPT slides array.
slide = prs.slides.add_slide(title_slide_layout)
# Get the PPT title object.
title = slide.shapes.title
# Get the PPT subtitle object.
subtitle = slide.placeholders[1]
# Set the PPT title.
title.text = "Hello python-pptx Module!"
# Set the PPT title slide sub title.
subtitle.text = "pip install python-pptx"
# Save the PPT to a .pptx file.
prs.save("test.pptx")
.如何使用python-pptx模块在PPT文件中添加图表。
下面的源代码可以创建一个图表并将其添加到输出的PPT文件中。
# Import the Presentation class from the pptx module.
from pptx import Presentation
# Import the ChartData class form the pptx.chart.data package.
from pptx.chart.data import ChartData
# Import the chart type constants variable.
from pptx.enum.chart import XL_CHART_TYPE
# Import the units type.
from pptx.util import Inches
# Create the Presentation object to build the PPT file.
prs = Presentation()
# Add a slide to the PPT file.
slide = prs.slides.add_slide(prs.slide_layouts[5])
# Create the ChartData object to save the chart data.
chart_data = ChartData()
# Save the categories data in an array, the categories data will be displayed in the horizontal x axis .
chart_data.categories = ['Java', 'Python', 'JavaScript']
# Save the series data in a tuple, the series data will be displayed in the vertial y axis.
chart_data.add_series('Series 1', (19.2, 21.4, 16.7))
# Define the x, y axis unit.
x, y, cx, cy = Inches(2), Inches(2), Inches(6), Inches(4.5)
# Add the column chart to the PPT slide.
slide.shapes.add_chart(
XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)
# Save the PPT file.
prs.save('chart-01.pptx')
4.如何使用PPT模板用Python-pptx模块生成PPT文件。
准备一个PPT模板文件(你可以从网上下载一个,或者自己创建一个PPT模板文件)。
加载PPT模板文件,使用python-pptx模块在你的Python源代码中使用指定的幻灯片样式。
向PPT模板文件添加数据,并生成一个新的PPT文件。
下面是源代码的例子。
# Import the pptx module Presentation class.
from pptx import Presentation
# Import the pptx x axis unit.
from pptx.util import Inches
from pptx.util import Cm #Inches
# Import the ChartData class.
from pptx.chart.data import ChartData
# Import the Chart type XL_CHART_TYPE.
from pptx.enum.chart import XL_CHART_TYPE
from pptx.enum.chart import XL_LEGEND_POSITION
if __name__ == '__main__':
# Create the Presentation object based on the template PPT file.
prs = Presentation('template.pptx')
# Add the first slide, title only slide.
title_only_slide_layout = prs.slide_layouts[5]
slide = prs.slides.add_slide(title_only_slide_layout)
shapes = slide.shapes
# Set the slide title text
shapes.title.text = 'Report'
# Define the chart table data in an array.
name_objects = ["object1", "object2", "object3"]
name_AIs = ["AI1", "AI2", "AI3"]
val_AI1 = (19.2, 21.4, 16.7)
val_AI2 = (22.3, 28.6, 15.2)
val_AI3 = (20.4, 26.3, 14.2)
val_AIs = [val_AI1, val_AI2, val_AI3]
# Define the chart table style.
rows = 4
cols = 4
top = Cm(12.5)
left = Cm(3.5) #Inches(2.0)
width = Cm(24) # Inches(6.0)
height = Cm(6) # Inches(0.8)
# Add the chart table to the slide.
table = shapes.add_table(rows, cols, left, top, width, height).table
# Set the table column width.
table.columns[0].width = Cm(6)# Inches(2.0)
table.columns[1].width = Cm(6)
table.columns[2].width = Cm(6)
table.columns[3].width = Cm(6)
# Set the table text row.
table.cell(0, 1).text = name_objects[0]
table.cell(0, 2).text = name_objects[1]
table.cell(0, 3).text = name_objects[2]
# Fill data to the table.
table.cell(1, 0).text = name_AIs[0]
table.cell(1, 1).text = str(val_AI1[0])
table.cell(1, 2).text = str(val_AI1[1])
table.cell(1, 3).text = str(val_AI1[2])
table.cell(2, 0).text = name_AIs[1]
table.cell(2, 1).text = str(val_AI2[0])
table.cell(2, 2).text = str(val_AI2[1])
table.cell(2, 3).text = str(val_AI2[2])
table.cell(3, 0).text = name_AIs[2]
table.cell(3, 1).text = str(val_AI3[0])
table.cell(3, 2).text = str(val_AI3[1])
table.cell(3, 3).text = str(val_AI3[2])
# Define the ChartData object.
chart_data = ChartData()
chart_data.categories = name_objects
chart_data.add_series(name_AIs[0], val_AI1)
chart_data.add_series(name_AIs[1], val_AI2)
chart_data.add_series(name_AIs[2], val_AI3)
# Add the chart to the PPT file.
x, y, cx, cy = Cm(3.5), Cm(4.2), Cm(24), Cm(8)
graphic_frame = slide.shapes.add_chart(
XL_CHART_TYPE.COLUMN_CLUSTERED, x, y, cx, cy, chart_data
)
chart = graphic_frame.chart
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.TOP
chart.legend.include_in_layout = False
value_axis = chart.value_axis
value_axis.maximum_scale = 100.0
value_axis.has_title = True
value_axis.axis_title.has_text_frame = True
value_axis.axis_title.text_frame.text = "False positive"
value_axis.axis_title.text_frame.auto_size
# Save a new PPT file based on the template.
prs.save('test_template.pptx')
使用win32com操作ppt
官方文档:https://docs.microsoft.com/zh-cn/office/vba/api/powerpoint.shape.copy
pip安装win32com
pip install pypiwin32
win32com复制ppt模板
有时候我们需要对ppt的模板进行复制,然后再添加相应内容,由于python-pptx对复制模板也没有很好的支持(我没找到~忧伤),所以我们用win32com对模板页进行复制,然后再用python-pptx增加ppt内容。
参考官方文档:https://docs.microsoft.com/zh-cn/office/vba/api/powerpoint.slide.copy
编辑音视频并添加字幕
使用Python编辑视频,各位有没有试过,我试过。虽然不如剪辑软件直观,但是各种剪辑软件需要手工操作每一步,一个小的操作不慎就需要挨个调节,那是考验耐心和费时费力的一件事儿。
那么有没有可以使用程序进行视频编辑的方法?当然有!
程序的好处是:设置好,一遍效果不好,重新设置下再运行一次就行,根本不用挨个操作。尤其是字幕!下面我们就简单介绍下如何利用Python通过MoviePy库编辑视频。
一、Moviepy是什么?
MoviePy是一个用于视频编辑的Python模块,它可被用于一些基本操作(如剪切、拼接、插入标题)、视频合成(即非线性编辑)、视频处理和创建高级特效。它可对大多数常见视频格式进行读写,包括GIF。
二、安装Moviepy
安装Moviepy很简单,使用如下命令即可安装:
pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple
三、使用Moviepy
- 导入Moviepy库
在使用Moviepy之前,我们需要使用以下代码先导入Moviepy
from moviepy.editor import *
- 视频剪辑
在进行视频剪辑之前,首先需要加载视频文件。使用以下代码可以加载视频文件:
video = VideoFileClip("input.mp4") # 这里是相对路径,如果使用绝对路径,请注意路径。
比如,我们要截取视频的某个时间段作为新的视频片,如用如下代码:
# 定义剪辑的开始和结束时间,这里的时间以秒为单位
start = 5
end = 25
# 对视频进行剪辑
clip_video = video.subclip(start, end)
使用如上方法后,subclip()方法可将第5秒剪切到第25秒,生成一个新的视频片段clip。
- 音频剪辑
使用AudioFileClip即可载入音频文件,同时使用subclip方法即可截取对应时间音频,与上面视频剪辑方法效果一样。只是这里截取的是音频。
clip_audio = AudioFileClip("input.mp3").subclip(5, 25)
- 添加文字
使用TextClip可以创建一个文本片段对象,如下:
text = TextClip("Moviepy太好用啦!", font='simhei.ttf', fontsize=80, color='white')# 设置文本内容,字体、大小以及颜色
text = text.set_position('center').set_duration(5)# 设置文本位置为剧中,并持续5秒
- 将文字和音乐合成到视频中
final_video = CompositeVideoClip([clip_video, text])
final_video = final_video.set_audio(clip_audio)
- 导出视频
视频剪辑完成后,我们使用write_videofile将最终的视频导出为文件。
final_video.write_videofile("output.mp4", threads = 8, fps=24, codec='mpeg4')
以上代码将使用8线程、每秒24帧,mpge4编码格式导出剪辑后的视频,并保存为output.mp4。
有些人导出了视频,但使用Windows播放器只能听到声音看不到图像,就是codec没有设置好,导致视频无时长,只能播放音频。
四、完整代码示例
from moviepy.editor import *
# 载入视频
video = VideoFileClip("input.mp4") # 这里是相对路径,如果使用绝对路径,请注意路径。
# 定义剪辑的开始和结束时间,这里的时间以秒为单位
start = 5
end = 25
# 对视频进行剪辑
clip_video = video.subclip(start, end)
# 载入并剪辑音频
clip_audio = AudioFileClip("input.mp3").subclip(5, 25)
# 添加文字
clip_text = TextClip("Moviepy太好用啦!", font='simhei.ttf', fontsize=80, color='white')# 设置文本内容,字体、大小以及颜色
clip_text = clip_text.set_position('center').set_duration(5)# 设置文本位置为剧中,并持续5秒
# 合成音视频及文字
final_video = CompositeVideoClip([clip_video, clip_text])
final_video = final_video.set_audio(clip_audio)
# 导出编辑后的最终视频
final_video.write_videofile("output.mp4", threads = 8, fps=24, codec='mpeg4')
总结
以上只是Moviepy库使用方法的一个简单示例。通过以上方法,我们可以方便地进行视频剪辑、音频剪辑、添加文字的操作。其实Moviepy的功能远不止于此,比如使用图片生成视频,还可以添加字幕等。关于字幕生成和添加,由于涉及内容较多,后期单独一篇进行介绍。
更多使用说明详见:https://moviepy-cn.readthedocs.io/zh/latest/
ppt制作成配音视频课件
ppt视频课件制作过程
2.1、将ppt保存为一张张图像
打开ppt,选择:文件 --> 另存为,保存类型选择为PNG或jpg,如图:
巨人网络通讯
请输入你要查找的知识关键词
知 识
400-1100-266
9:00-24:00(工作日)
首 页
企业400电话
Hot
网站建设
商标✡知产
网络优化推广
热
AI电话机器人
呼叫中心
彩铃•短信
增值拓展业务
新
主页 > 知识库 > Python快速将ppt制作成配音视频课件的操作方法
Python快速将ppt制作成配音视频课件的操作方法
热门标签:智能手机 美图手机 网站文章发布 检查注册表项 呼叫中心市场需求 银行业务 铁路电话系统 服务器配置
目录
一、引言
二、ppt视频课件制作过程
2.1、将ppt保存为一张张图像
2.2、按页录音
2.3、编写代码进行合成
三、效果
四、小结
一、引言
老猿从来没有录播个视频课件,但最近有要求在一周内必须录制一个视频课件,为此花了3天时间准备ppt,花了一个小时录播了一个20多分钟的课件。
由于第一次干这个活,讲课时情绪还是有点紧张,导致录播的语音出现了各种重复、不该有的间断、两页切换时课件讲解过快、部分词语发音不准等问题,导致效果一团糟。
为了解决这些问题,又使用剪辑软件进行了剪辑,光剪辑就花了2天时间,结果效果还是不好,最后想到了一个办法,就是废掉原录播材料,将ppt导出成图像,然后逐页录音,再使用合成软件将图像和音频逐一匹配,再进行制作。花了40多分钟逐页录音并试听,最后花了半天时间制作和输出,终于赶上最后的截止时间前上交了视频。如果最开始就用这个方法,可以节省大部分时间。
基于上述过程,老猿又想到最后这个处理过程完全不需要使用合成软件,而是使用Moviepy是否更好呢?今天付诸行动,发现使用Moviepy进行合成比图形操作界面的合成软件效果更好,完美地解决了音频和ppt材料的协同问题。下面就详细介绍一下这个过程,供ppt视频课件制作生手提供一个可以高效制作视频的方法。
二、ppt视频课件制作过程
2.1、将ppt保存为一张张图像
打开ppt,选择:文件 --> 另存为,保存类型选择为PNG或jpg,如图:
然后点击保存,出现:
选择“每张幻灯片”。
这样就可以将每页ppt导出成图片了,如:
相关图片会输出到一个单独的目录,以“幻灯片XX.png”等形式逐页输出保存。
2.2、按页录音
对照ppt每页的内容,将该页讲解的语音使用手机录音软件等方式录制成一个个音频文件,下面是老猿录制的音频文件目录:
注意,在以上录音时,第18页和20页录制成了2段,这种方式处理和其他页面不一样,是不适合用程序来处理的,除非对此针对性的改造。
2.3、编写代码进行合成
代码的说明与注释,不单独进行补充说明,完整代码如下:
from moviepy.editor import *
import os,traceback
def isdigit(c):
return c>='0' and c='9'
def getPattern(patternString):
"""
:param patternString: 含有模式串的字符串,模式串仿C语言整型输出格式,类似于:%d、%02d等
:return: 返回将patternString拆分成三段的一个列表,三个元素分别是:模式串前面的字符串、模式串(含百分号、数字和d)、模式串后面的字符串,如果没有找到模式串则返回None
"""
patternIndex = patternString.index("%")
if patternIndex0:
print("模式字符串中未发现模式匹配符:%")
return None
matched = False
for patternEnd in range(patternIndex+1,len(patternString)):
if patternString[patternEnd]in'dD':
matched = True
break
else:
if not isdigit(patternString[patternEnd]):
print("模式字符串中的模式存在非数字")
return None
if matched: return [patternString[:patternIndex],patternString[patternIndex:patternEnd+1],patternString[patternEnd+1:]]
else:
print("模式字符串中的模式不是字母d结尾")
return None
def composePPTImgsAndSounds(imgFilePattern,soundFilePattern,startSeq=1,endSeq=None):
"""
:param imgFilePattern: 图像文件模式,要求图像文件中必须含文件序号,序号采用%d、%02d/%03d的方式来识别
:param soundFilePattern:音频文件格式,要求文件中必须含文件序号,序号采用%d、%02d/%03d的方式来识别
:param startSeq:文件序列号其实值,一般为0或1
:param endSeq:文件序列号结束值,可以不填
:return:生成的视频
"""
if endSeq is None:endSeq=9999999 #当对应序号找不到文件时结束
patterns = getPattern(imgFilePattern)
if patterns is None:
print('图像文件名不符合模式格式要求')
return None
else:
imgPrefix,imgPattern,imgPostfix = patterns
patterns = getPattern(soundFilePattern)
if patterns is None:
print('音频文件名不符合模式格式要求')
return None
else:
soundPrefix, soundPattern, soundPostfix = patterns
clips = []
try:
for seq in range(startSeq,endSeq):
imgFName = f"{imgPrefix}{seq:{imgPattern[1:]}}{imgPostfix}"
soundFName = f"{soundPrefix}{seq:{soundPattern[1:]}}{soundPostfix}"
if os.path.exists(soundFName) and os.path.exists(imgFName):
soundClip = AudioFileClip(soundFName)
imgClip = ImageClip(imgFName).set_duration(soundClip.duration).set_fps(2).set_audio(soundClip)
clips.append(imgClip)
else:
if seq:
print(f"音视和图像文件加载结束,最后一个文件的序号为{seq}")
break
else:
print(f"图像文件{imgClip}或音频文件{soundClip}不存在")
return None
except Exception as e:
print(f"加载音频和图像文件失败:\n{e}\n{traceback.format_exc()}")
return None
print("输出视频文件....")
clip = concatenate_videoclips(clips,'compose')
clip.write_videofile(r"C:\temp\ppt.mp4",threads=8)
print("视频文件已经生成")
return clip
composePPTImgsAndSounds(r'F:\bak\pr\大H\十百千\视频制作\5G在线计费动态授权机制介绍3.9\幻灯片%d.PNG',r'C:\temp\录音文件\p%d.m4a')
三、效果
使用该方式制作的视频,比图形界面合成软件制作的视频效果更流畅、大小更小、制作时间也更短,大小大概是图形界面视频合成软件的不到十分之一,视频输出时间是图形界面合成软件手工输出的四分之一,还省了手工去进行合成剪辑的过程(非熟练人员一般需要1-2个小时),老猿20分钟的视频课,含录音、试听及部分重录时间,整个制作过程不到70分钟(不含代码编写时间),是不是特别好用?
不过注意,老猿上面的案例处理到第18页时就认为课件完结了,要将整个课件处理完,需要合并18页和20页的音频输出到其他音频文件类似的音频文件中。
四、小结
本文介绍了一种ppt视频课件快速制作的方法,通过将ppt输出成一张张图片,然后逐页配音,最后使用Moviepy将其合成输出,课件制作又快又好。由于采用了分页录音的方式,对于讲解不好的地方很快就可以更换,因此比期望一次性录播然后剪辑的效果要好很多,同时输出的视频文件小、输出快。
视频特效处理
一、引言
Moviepy 是一个 Python 的音视频剪辑库,OpenCV 是一个图形处理库,我们知道视频的一帧就是一幅图像,因此在处理视频时可以结合 OpenCV 进行帧处理,将二者结合可以用来进行一些不错的视频特效的处理。老猿在此介绍两个这方面的应用案例供大家参考。
二、给视频添加雪花飘落特效
2.1、实现原理
雪花特效可以给视频增加特殊的效果,要给视频加雪花特效,是基于以下原理来实现的:
每个视频都是由一个个视频帧构成,每个视频帧都是一副静态的图像,通过视频帧的连续显示形成动态视频;
实现视频雪花飘落,就是在视频的每帧图像中添加雪花,并在前后相连的视频帧中变化雪花的位置,形成雪花下飘带横向移动的效果;
雪花的图片本身是一个矩形,矩形内有黑色背景和白色的雪花,在将雪花图片添加到视频帧时,需要确保黑色部分不会遮盖帧图像的内容,只有白色的雪花前景色才可以遮挡帧图像内容。这就需要通过图像的阈值处理确得到雪花图像的二值图,用该二值图及其补图作为掩膜,二值图作为雪花原始图片与自身与运算的掩码来获取雪花图片的前景色,补图作为帧图片雪花对应位置的子图与子图自身与运算的掩膜来获取雪花黑色背景部分对应的帧图像作为背景色;
对视频帧调用雪花融合图像的函数进行动态融合雪花的处理
Moviepy 的 fl_image 是视频剪辑基类 VideoClip 的方法,该方法用于对视频的帧图像进行变换,其参数包括一个对帧图像进行变换的函数 image_func,具体变换由应用实现对图像进行变换处理的一个函数,然后将该函数作为 image_func 的值参传入 fl_image,Moviepy 就会调用该函数完成对视频每帧图像的处理生成新的剪辑
2.2、具体实现
2.2.1、雪花图片
本次实现的案例对应的雪花图片为:
文件名为:f:\pic\snow.jpg。上述图片的雪花是标准的雪花图像,但图像比较大,在视频中直接展示这么大的雪花就很假,老猿经过测试,发现将其缩小到原图像的五分之一以内比较象真正的雪花。
2.2.2、实现流程
2.2.3、关键实现
2.2.3.1、初始化雪花
图片的雪花是固定大小的,而真正的雪花大小是不同的,为了模拟真正的雪花效果,需要有各种不同大小和角度的雪花,为此每片雪花需要根据图片雪花图像进行随机的大小和角度调整。
一帧图像中的雪花数量至少是几十到几百片,如果每次融合图像时,都需要从图片雪花图像进行大小和旋转角度的变换,是非常消耗系统的性能的,影响视频的生成耗时。
为了提升处理性能,老猿只在程序开始初始化时一次批量生产各种不同大小、不同旋转角度的各种雪花,后续程序生成雪花时,直接从批量生成的雪花中取一个作为要生成的雪花,而不用每次从基本的雪花图像开始进行变换。
生成各种雪花形状的示例代码:
# -*- coding: utf-8 -*-
import cv2,random
import numpy as np
from opencvPublic import addImgToLargeImg,readImgFile,rotationImg
snowShapesList = [] #雪花形状列表
snowObjects=[] #图片中要显示的所有雪花对象
def initSnowShapes():
"""
从文件中读入雪花图片,并进行不同尺度的缩小和不同角度的旋转从而生成不同的雪花形状,这些雪花形状保存到全局列表中snowShapesList
"""
global snowShapesList
imgSnow = readImgFile(r'f:\pic\snow.jpg')
imgSnow = cv2.resize(imgSnow, None, fx=0.3, fy=0.3) #图片文件中的雪花比较大,需要缩小才能象自然的雪花形象
minFactor,maxFactor = 50,100 #雪花大小在imgSnow的0.5-1倍之间变化
for factor in range(minFactor,maxFactor,5): #每次增加5%大小
f = factor*0.01
imgSnowSize = cv2.resize(imgSnow, None, fx=f, fy=f)
for ange in range(0,360,5):#雪花0-360之间旋转,每次旋转角度增加5°
imgRotate = rotationImg(imgSnowSize,ange)
snowShapesList.append(imgRotate)
2.2.3.2、产生一排雪花
每帧图像除了保留上帧图像中未飘落出图像范围的雪花外,同时还会从顶部生成一排数量随机的雪花,形成生生不息的雪花。下面是从顶部初始化生成一排雪花的代码:
def generateOneRowSnows(width,count):
"""
产生一排雪花对象,每个雪花随机从snowShapesList取一个、横坐标位置随机、纵坐标初始为0
:param width: 背景图像宽度
:param count: 希望的雪花数
:y:当前行对应的竖直坐标
:return:一个包含产生的多个雪花对象信息的列表,每个列表的元素代表一个雪花对象,雪花对象包含三个信息,在snowShapesList的索引号、初始x坐标、初始y坐标(才生成固定为0)
"""
global snowShapesList
line = []
picCount = len(snowShapesList)
for loop in range(count):
imgId = random.randint(0,picCount-1)
xPos = random.randint(0,width-1)
line.append((imgId,xPos,0))
return line
2.2.3.3、将所有雪花对象融合到背景图像
上帧图像中的雪花在当前帧中需要随机下落一定位置,并在一定幅度内横向漂移,当有雪花落到图像底部之下时,需要释放对应对象以节省资源。
def addSnowEffectToImg(img):
"""
将所有snowObjects中的雪花对象融合放到图像img中,融合时y坐标随机下移一定高度,x坐标左右随机小范围内移动
"""
global snowShapesList,snowObjects
horizontalMaxDistance,verticalMaxDistance = 5,10 #水平方向左右漂移最大值和竖直方向下落最大值
rows,cols = img.shape[:2]
maxObjsPerRow = int(cols/100)
snowObjects += generateOneRowSnows(cols, random.randint(0, maxObjsPerRow))
snowObjectCount = len(snowObjects)
rows,cols = img.shape[0:2]
imgResult = np.array(img)
for index in range(snowObjectCount-1,-1,-1):
imgObj = snowObjects[index] #每个元素为(imgId,x,y)
if imgObj[2]>rows: #如果雪花的起始纵坐标已经超出背景图像的高度(即到达背景图像底部),则该雪花对象需进行失效处理
del(snowObjects[index])
else:
imgSnow = snowShapesList[imgObj[0]]
x,y = imgObj[1:] #取该雪花上次的位置
x = x+random.randint(-1*horizontalMaxDistance,horizontalMaxDistance) #横坐标随机左右移动一定范围
y = y+random.randint(1,verticalMaxDistance) #纵坐标随机下落一定范围
snowObjects[index] = (imgObj[0],x,y) #更新雪花对象信息
imgResult = addImgToLargeImg(imgSnow,imgResult,(x,y),180) #将所有雪花对象图像按照其位置融合到背景图像中
return imgResult #返回融合图像
2.2.3.4、实现视频雪花飘落特效视频合成
下面的代码调用 addSnowEffectToImg 实现对《粉丝记事本》视频的雪花飘落特效:
from moviepy.editor import *
def addVideoSnowEffect(videoFileName,resultFileName):
clip = VideoFileClip(videoFileName)
newclip = clip.fl_image(addSnowEffectToImg, apply_to=['mask'])
newclip.write_videofile(resultFileName)
if __name__ == '__main__':
addVideoSnowEffect(r'f:\video\fansNote.mp4',r'f:\video\fansNote_snow.mp4')
2.2.4、雪花飘落效果
三、制作灯光秀短视频
3.1、视频内容设计
基于多张静态景物叠加特效声光特效可以将静态图片变成有趣的灯光秀视频,老猿为了武汉这个英雄之城解封一周年用 Python 制作了个解封庆祝的灯光秀短视频。
老猿是个没有艺术细胞的人,因此这个视频内容只能说仅能代表是个视频而已,对最终的内容表现大家就不需要过多评价。
在创作该视频前,老猿对视频进行了简单规划,将创作视频分为片头、视频内容和片尾三部分:
-
片头:5 秒时间,展现一幅黄鹤楼的照片,并带上“武汉重启一周年灯光秀”的标题
-
视频内容:全长 35 秒,每隔 2 秒随机展现一张武汉灯光秀景观图,并在视频中附上向上滚动的文字“热烈庆祝武汉重启一周年!”、“武汉万岁!中国万岁!”,并在视频的左下角和右下角用红绿蓝三色画三条向上晃动的线条表示彩色激光
-
片尾:25 秒,每隔 2 秒随机展现武汉的一张风景照,并展现“制片:老猿 Python”等制作信息。
3.2、开发设计
3.2.1、视频图片处理
视频中用到的图片都来源于互联网,为了减少图片加载的时间和统一初始化,在程序中通过全局变量将片头使用图像、视频内容使用图像、片尾使用图像分别使用了三个全局变量进行保存,其中后两者为列表类型。为了确保视频输出,所有图片都调整到了统一大小。
3.2.2、灯光效果处理
在视频内容部分,左下角和右下角发射的彩色激光,采用在背景图片中根据时间动态绘制彩色线条,实现彩色激光晃动照射的效果,为了限制晃动范围,设定了激光终点的 x 值的最小值和最大值。激光终点的位置根据时间动态计算,并在到达 x 值的最小值或最大值时自动回扫。
3.2.3、帧图像的生成
上面介绍的图像处理,全部集中在一个函数中处理,该函数仅带一个参数时间 t,判断时间来决定现在生成的内容是片头、内容还是片尾,然后据此来进行帧图像的生成。生成时,需要判断图像是否切换,因此需要记录上一次切换的时间和切换后的图像,确保未达到切换时间前用上次图像作为帧图像的背景,达到切换时间要求后切换新的图像作为后续帧图像生成的背景。为此在该函数中使用了两个全局变量来记录当前帧图像背景图片和上次切换时间。
3.2.4、输出到视频
为了将视频输出到文件,通过 VideoWriter_fourcc 指定视频输出文件类型,采用 OpenCV 的 VideoWriter 类来进行视频输出,通过 Open 方法指定输出文件,通过 write 方法将一帧帧视频写入。
3.3、具体实现
3.3.1、总流程
-
加载片头、视频内容、片尾需要使用的图像;
-
创建新视频文件
-
按照帧率 24、时长 65 秒,构建 24*65 张帧图像,并逐一输出到视频文件。
3.3.2、全局变量初始化
全局变量主要是视频中需要使用的图片,分成片头使用图片 hhlImg、灯光秀图片列表 lightShowImgList 和片尾风景图片列表 whImgList 。另外 preImg,preTime 用于记录上次切换视频图片的图片和切换时间。
hhlImg = cv2.resize(readImgFile(r'f:\pic\武汉\黄鹤楼.jpg'),(800,600))
lightShowImgList = [cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_桥.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_武汉江边.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥底部.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_一桥远景.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\灯光秀_远桥.jpg'),(800,600))]
whImgList = [cv2.resize(readImgFile(r'f:\pic\武汉\东湖1.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\东湖2.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\东湖樱园樱花.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\武大牌楼.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\武大牌楼远观.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\武大樱花2.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园顶高拍照.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园门洞.jpg'),(800,600)),
cv2.resize(readImgFile(r'f:\pic\武汉\武大樱园入口.jpg'),(800,600)),cv2.resize(readImgFile(r'f:\pic\武汉\武大老图书馆.jpg'),(800,600))]
preImg,preTime = None,0
3.3.3、实现给背景图像添加彩色激光照射效果
lightShowImg 函数实现给背景图像指定点发射彩色激光的特效,激光发射点固定,由参数 lightStartPos 指定,终点随参数 t 在一定范围内变化,终点 x 坐标受参数 minX, maxX 控制,同一个发射源的三激光之间的间距受参数 distance 控制。
def lightShowImg(bg,minX, maxX,distance,lightStartPos,t):
"""
实现在背景图像上添加当前散发彩色激光的处理
:param bg: 背景图像
:param minX:灯光终点的最大x坐标
:param maxX:灯光终点的最小x坐标
:param distance: 不同灯光之间的间距
:param lightStartPos: 灯光发射点
:param t: 时间t
:return: 添加了发射灯光的图像
"""
x = (minX+int(t*200))%(maxX*2) #按时间t计算灯光终点的x坐标,该坐标可以超出背景图像范围
img = np.array(bg)
if x>maxX: #到达最大范围,需要回扫
x = 2*maxX-x
color1,color2,color3 = (255,0,0),(0,255,0),(0,0 ,255 ) #蓝、绿、红三色
cv2.line(img, lightStartPos, (x, 0), color1, 4)
cv2.line(img, lightStartPos, (x + distance, 0), color2, 4)
cv2.line(img, lightStartPos, (x - distance, 0), color3, 4)
return img
3.3.4、帧图片生成
makeframe 函数实现帧图片生成,带一个参数 t 表示当前帧对应的剪辑时间,在函数内根据剪辑时间来判断是生成片头内容、灯光秀内容还是片尾内容生成 t 时刻对应帧图像返回:
-
对于片头,采用黄鹤楼照片作为背景,并在图片中央显示“武汉重启一周年灯光秀”;
-
对于视频内容,则每 2 秒从灯光秀图片队列中随机取一张图片作为当前背景图像,并调用 lightShowImg 增加左下角和右下角的彩色激光效果,同时动态向上滚动显示“热烈庆祝武汉重启一周年”、“武汉万岁!中国万岁!”等标语;
-
对于片尾,则每 2 秒从武汉风景图片队列中随机取一张图片作为当前背景图像,同时动态向上滚动显示制作信息。
def makeframe(t):
#生成t时刻的视频帧图像
global preImg,preTime
if t<5:#5秒片头
img = imgAddText(hhlImg,'武汉重启一周年灯光秀',64,(255,0,0),vRefPos='C')
elif t<40:#5-40秒灯光秀
minX, maxX = 200, 1200 # 灯光横向扫射范围
lightStartPos1 = (0, 600) # 灯光1的发射点坐标设置为左下角
lightStartPos2 = (800, 600) # 灯光2的发射点坐标设置为右下角
if (t-preTime)>2 or preImg is None:
img = np.array(random.choice(lightShowImgList))
preImg,preTime = img,t
else:
img = preImg
img = lightShowImg(img, minX, maxX, 80,lightStartPos1, t)
img = lightShowImg(img, minX-100, maxX+100,48, lightStartPos2, t)
t = int((t-4)*40)%img.shape[0]
img = imgAddText(img,'热烈庆祝武汉重启一周年!',48,(0,0,255),vRefPos=-80-t,)
img = imgAddText(img, '武汉万岁!中国万岁!',48,(255,0,255),vRefPos=-t)
else:#片尾
if (t-preTime)>2 or preImg is None:
img = np.array(random.choice(whImgList))
preImg,preTime = img,t
else:
img = preImg
t = int((t - 39) * 20) % img.shape[0]
img = imgAddText(img,"制片:老猿Python",36,(255,255,255),vRefPos=-120-t)
img = imgAddText(img, "https://www.infoq.cn/u/laoyuanpython/publish",24,(255,255,255),vRefPos= -60-t)
img = imgAddText(img, "2021年4月8日", 24, (255,255,255), vRefPos=-t)
return img
3.3.5、制作视频文件
函数 buildVideoByCV 用于制作视频文件,按指定格式生成一个新的视频文件,然后循环调用 makeframe 生成一帧帧图像写入视频文件中。
def buildVideoByCV():
videoMake = cv2.VideoWriter()
fourcc = cv2.VideoWriter_fourcc(*'MP4V') #https://blog.csdn.net/whudee/article/details/108689420
fps = 12
videoMake.open(r"F:\video\lightShowCV.MP4", fourcc, fps, (800,600))
for t in range(65*fps):
img = makeframe(t*1.0/fps)
videoMake.write(img)
print(f'\r视频制作进度:{(t*100.0)/(66*fps):4.2f}%',end='')
videoMake.release()
上述函数构建后只需要调用 buildVideoByCV 函数即可完成视频制作。
3.3.6、视频效果
小结
介绍了制作视频雪花飘落特效和灯光秀的原理、实现的思想以及流程,并利用 Python+OpenCV+Moviepy 提供了关键的实现代码,可以供大家理解图像融合、图像制作视频、Moviepy 视频变换的完整案例。
证书批量生成
这是一个只有一张幻灯片的ppt文档,可以看到幻灯片里存在着很多文字以及上边的三颗小星星图案。这些元素全都属于ppt中的形状。因为这些形状所包含的内容不同,我们可以根据内容对其加以区分,从而进一步实现“对号入座”的目标。
当然在使用pptx模块之前,我们还是需要安装这个模块。需要注意的是安装的模块名为python-pptx,而在导入时使用的模块名为pptx。
安装完成之后,我们需要导入pptx模块中的Presentation类。这个类用来容纳ppt文档,我们直接以ppt文件的路径作为参数传入Presentation类中,实例化出这个ppt文档。
Ppt文档是由一张一张的幻灯片组成的,我们可以访问slides属性来获取文档里所有的幻灯片:
需要注意的是slides并不是一个元组或列表,而是一个迭代器。当然,这并不影响我们使用索引值来调取相应的单张幻灯片:
注意到两个对象名的区别了吗?
而每张幻灯片又是由一个一个形状组成的,我们可以访问shapes属性来获取这些形状:
同样,shapes也是一个迭代器。我们使用for循环来打印出所有的shape对象:
可以看到,打印出来的对象名字里很多都有placeholder这样的词语,这意味着这些形状是占位符。而我们看到的文字存在于占位符中。因为我们下载的是一个证书的模板,所以占位符在幻灯片中被广泛地使用。当然占位符只是幻灯片形状中的一种,还有就像是模板里边的小星星是图片格式的形状以及很多其他行星状,我们目前不需要太在意它和其他形状之间的区别。
但是到现在我们只能看到各个形状对象所在的内存地址,仍然不能获取到形状的内容啊!别急,现在获取的形状里有的是带有文字的占位符,有的只是不能输入文字的小星星图片。我们目前的“对号入座”方案主要是对文字进行替换,那么我们下一步就是筛选出可以编写文字的形状,可以使用has_text_frame方法:
这种方法筛选出来的shape都可以输入文字的,但并不一定是目前就有文字的。不光是占位符,文本框、形状等都可以输入文字。如果某个shape可以输入文字(即shape.has_text_frame为True),那么我们就可以访问text属性来获取文字内容:
现在我们就成功地获取到文字内容了。我们可以根据我们的需要对其进行修改,只要简单地赋值就可以了:
到这一步就和使用Python自动化生成word差不多了,直接开搞吧
最后,使用save方法将修改后的ppt存档,看看结果: