更新了部分文档
parent
8497458763
commit
2834e5b053
|
@ -43,19 +43,15 @@ file.close()
|
|||
除了使用文件对象的`read`方法读取文件之外,还可以使用`for-in`循环逐行读取或者用`readlines`方法将文件按行读取到一个列表容器中,代码如下所示。
|
||||
|
||||
```Python
|
||||
import time
|
||||
|
||||
file = open('致橡树.txt', 'r', encoding='utf-8')
|
||||
for line in file:
|
||||
print(line, end='')
|
||||
time.sleep(0.5)
|
||||
file.close()
|
||||
|
||||
file = open('致橡树.txt', 'r', encoding='utf-8')
|
||||
lines = file.readlines()
|
||||
for line in lines:
|
||||
print(line, end='')
|
||||
time.sleep(0.5)
|
||||
file.close()
|
||||
```
|
||||
|
||||
|
@ -69,16 +65,6 @@ file.write('\n时间:1977年3月')
|
|||
file.close()
|
||||
```
|
||||
|
||||
也可以使用下面的代码来完成相同的操作。
|
||||
|
||||
```Python
|
||||
lines = ['标题:《致橡树》', '作者:舒婷', '时间:1977年3月']
|
||||
file = open('致橡树.txt', 'a', encoding='utf-8')
|
||||
for line in lines:
|
||||
file.write(f'\n{line}')
|
||||
file.close()
|
||||
```
|
||||
|
||||
### 异常处理机制
|
||||
|
||||
请注意上面的代码,如果`open`函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码具有健壮性和容错性,我们可以**使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理**。Python中和异常相关的关键字有五个,分别是`try`、`except`、`else`、`finally`和`raise`,我们先看看下面的代码,再来为大家介绍这些关键字的用法。
|
||||
|
@ -170,7 +156,7 @@ BaseException
|
|||
+-- ResourceWarning
|
||||
```
|
||||
|
||||
从上面的继承结构可以看出,Python中所有的异常都是`BaseException`的子类型,它有四个直接的子类,分别是:`SystemExit`、`KeyboardInterrupt`、`GeneratorExit`和`Exception`。其中,`SystemExit`表示解释器请求退出,`KeyboardInterrupt`是用户中断程序执行(按下`Ctrl+c`),`GeneratorExit`表示生成器发生异常通知退出。值得一提的是`Exception`类,它是常规异常类型的父类型,很多的异常都是直接或间接的继承自`Exception`类。如果Python内置的异常类型不能满足应用程序的需要,我们可以自定义异常类型,而自定义的异常类型也应该直接或间接继承自`Exception`类,当然还可以根据需要重写或添加方法。
|
||||
从上面的继承结构可以看出,Python中所有的异常都是`BaseException`的子类型,它有四个直接的子类,分别是:`SystemExit`、`KeyboardInterrupt`、`GeneratorExit`和`Exception`。其中,`SystemExit`表示解释器请求退出,`KeyboardInterrupt`是用户中断程序执行(按下`Ctrl+c`),`GeneratorExit`表示生成器发生异常通知退出,不理解这些异常没有关系,继续学习就好了。值得一提的是`Exception`类,它是常规异常类型的父类型,很多的异常都是直接或间接的继承自`Exception`类。如果Python内置的异常类型不能满足应用程序的需要,我们可以自定义异常类型,而自定义的异常类型也应该直接或间接继承自`Exception`类,当然还可以根据需要重写或添加方法。
|
||||
|
||||
在Python中,可以使用`raise`关键字来引发异常(抛出异常对象),而调用者可以通过`try...except...`结构来捕获并处理异常。例如在函数中,当函数的执行条件不满足时,可以使用抛出异常的方式来告知调用者问题的所在,而调用者可以通过捕获处理异常来使得代码从异常中恢复,定义异常和抛出异常的代码如下所示。
|
||||
|
||||
|
@ -204,7 +190,9 @@ while flag:
|
|||
|
||||
### 上下文语法
|
||||
|
||||
对于`open`函数返回的文件对象,还可以使用`with`上下文语法在文件操作完成后自动执行文件对象的`close`方法,这样可以让代码变得更加简单,因为不需要再写`finally`代码块来执行关闭文件释放资源的操作。需要提醒大家的是,并不是所有的对象都可以放在`with`上下文语法中,只有符合**上下文管理器协议**(有`__enter__`和`__exit__`魔术方法)的对象才能使用这种语法,Python标准库中的`contextlib`模块也提供了对`with`上下文语法的支持,后面再为大家进行讲解。
|
||||
对于`open`函数返回的文件对象,还可以使用`with`上下文语法在文件操作完成后自动执行文件对象的`close`方法,这样可以让代码变得更加简单优雅,因为不需要再写`finally`代码块来执行关闭文件释放资源的操作。需要提醒大家的是,并不是所有的对象都可以放在`with`上下文语法中,只有符合**上下文管理器协议**(有`__enter__`和`__exit__`魔术方法)的对象才能使用这种语法,Python标准库中的`contextlib`模块也提供了对`with`上下文语法的支持,后面再为大家进行讲解。
|
||||
|
||||
用`with`上下文语法改写后的代码如下所示。
|
||||
|
||||
```Python
|
||||
try:
|
||||
|
|
|
@ -192,7 +192,7 @@ if resp.status_code == 200:
|
|||
print('-' * 60)
|
||||
```
|
||||
|
||||
> **注意**:上面代码中的APIKey需要换成自己在天行数据网站申请的APIKey,同时还要申请开通国内新闻的接口才能获取到JSON格式的数据。这个网站上还有很多非常有意思的网络API接口,例如:垃圾分类、美女图片、周公解梦等等,大家可以仿照上面的代码来调用这些接口。
|
||||
> **注意**:上面代码中的APIKey需要换成自己在天行数据网站申请的APIKey,同时还要申请开通国内新闻的接口才能获取到JSON格式的数据。这个网站上还有很多非常有意思的网络API接口,例如:垃圾分类、舔狗日记、周公解梦等等,大家可以仿照上面的代码来调用这些接口。
|
||||
|
||||
### 简单的总结
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ CSV文件有以下特点:
|
|||
3. 每条记录被分隔符(如逗号、分号、制表符等)分隔为字段(列);
|
||||
4. 每条记录都有同样的字段序列。
|
||||
|
||||
CSV文件可以使用文本编辑器或类似于Excel电子表格这类工具打开和编辑,当使用Excel这类电子表格打开CSV文件时,你甚至感觉不到CSV和Excel文件的区别。很多数据库系统都支持将数据导出到CSV文件中,当然也支持从CSV文件中读入数据保存到数据库中,这些内容并不是我们这里讨论的重点。
|
||||
CSV文件可以使用文本编辑器或类似于Excel电子表格这类工具打开和编辑,当使用Excel这类电子表格打开CSV文件时,你甚至感觉不到CSV和Excel文件的区别。很多数据库系统都支持将数据导出到CSV文件中,当然也支持从CSV文件中读入数据保存到数据库中,这些内容并不是现在要讨论的重点。
|
||||
|
||||
### 将数据写入CSV文件
|
||||
|
||||
|
@ -25,19 +25,40 @@ with open('scores.csv', 'w') as file:
|
|||
writer = csv.writer(file)
|
||||
writer.writerow(['姓名', '语文', '数学', '英语'])
|
||||
names = ['关羽', '张飞', '赵云', '马超', '黄忠']
|
||||
for i in range(5):
|
||||
verbal = random.randint(50, 100)
|
||||
math = random.randint(40, 100)
|
||||
english = random.randint(30, 100)
|
||||
writer.writerow([names[i], verbal, math, english])
|
||||
for name in names:
|
||||
scores = [random.randrange(50, 101) for _ in range(3)]
|
||||
scores.insert(0, name)
|
||||
writer.writerow(scores)
|
||||
```
|
||||
|
||||
需要说明的是上面的`writer`函数,该函数除了传入要写入数据的文件对象外,还可以`dialect`参数,它表示CSV文件的方言,默认值是`excel`。除此之外,还可以通过`delimiter`、`quotechar`、`quoting`参数来指定分隔符(默认是逗号)、包围值的字符(默认是双引号)以及包围的方式。其中,包围值的字符主要用于当字段中有特殊符号时,通过添加包围值的字符可以避免二义性。大家可以尝试将上面第5行代码修改为下面的代码,看看生成的CSV文件到底有什么区别。
|
||||
生成的CSV文件的内容。
|
||||
|
||||
```
|
||||
姓名,语文,数学,英语
|
||||
关羽,98,86,61
|
||||
张飞,86,58,80
|
||||
赵云,95,73,70
|
||||
马超,83,97,55
|
||||
黄忠,61,54,87
|
||||
```
|
||||
|
||||
需要说明的是上面的`writer`函数,除了传入要写入数据的文件对象外,还可以`dialect`参数,它表示CSV文件的方言,默认值是`excel`。除此之外,还可以通过`delimiter`、`quotechar`、`quoting`参数来指定分隔符(默认是逗号)、包围值的字符(默认是双引号)以及包围的方式。其中,包围值的字符主要用于当字段中有特殊符号时,通过添加包围值的字符可以避免二义性。大家可以尝试将上面第5行代码修改为下面的代码,然后查看生成的CSV文件。
|
||||
|
||||
```Python
|
||||
writer = csv.writer(file, delimiter='|', quoting=csv.QUOTE_ALL)
|
||||
```
|
||||
|
||||
生成的CSV文件的内容。
|
||||
|
||||
```
|
||||
"姓名"|"语文"|"数学"|"英语"
|
||||
"关羽"|"88"|"64"|"65"
|
||||
"张飞"|"76"|"93"|"79"
|
||||
"赵云"|"78"|"55"|"76"
|
||||
"马超"|"72"|"77"|"68"
|
||||
"黄忠"|"70"|"72"|"51"
|
||||
```
|
||||
|
||||
### 从CSV文件读取数据
|
||||
|
||||
如果要读取刚才创建的CSV文件,可以使用下面的代码,通过`csv`模块的`reader`函数可以创建出`csvreader`对象,该对象是一个迭代器,可以通过`next`函数或`for-in`循环读取到文件中的数据。
|
||||
|
@ -47,9 +68,9 @@ import csv
|
|||
|
||||
with open('scores.csv', 'r') as file:
|
||||
reader = csv.reader(file, delimiter='|')
|
||||
for line in reader:
|
||||
for data_list in reader:
|
||||
print(reader.line_num, end='\t')
|
||||
for elem in line:
|
||||
for elem in data_list:
|
||||
print(elem, end='\t')
|
||||
print()
|
||||
```
|
||||
|
@ -58,4 +79,4 @@ with open('scores.csv', 'r') as file:
|
|||
|
||||
### 简单的总结
|
||||
|
||||
将来如果大家使用Python做数据分析,很有可能会用到名为`pandas`的三方库,它是Python数据分析的神器之一。`pandas`中封装了名为`read_csv`和`to_csv`的函数用来读写CSV文件,其中`read_CSV`会将读取到的数据变成一个`DataFrame`对象,而这个对象就是`pandas`库中最重要的类,它封装了一系列的方法用于对数据进行处理(清洗、转换、聚合等);而`to_csv`会将`DataFrame`对象中的数据写入CSV文件,完成数据的持久化。
|
||||
将来如果大家使用Python做数据分析,很有可能会用到名为`pandas`的三方库,它是Python数据分析的神器之一。`pandas`中封装了名为`read_csv`和`to_csv`的函数用来读写CSV文件,其中`read_CSV`会将读取到的数据变成一个`DataFrame`对象,而`DataFrame`就是`pandas`库中最重要的类型,它封装了一系列用于数据处理的方法(清洗、转换、聚合等);而`to_csv`会将`DataFrame`对象中的数据写入CSV文件,完成数据的持久化。`read_csv`函数和`to_csv`函数远远比原生的`csvreader`和`csvwriter`强大。
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
## 第24课:用Python读写Excel文件-1
|
||||
|
||||
### Excel简介
|
||||
|
||||
Excel是Microsoft(微软)为使用Windows和macOS操作系统开发的一款电子表格软件。Excel凭借其直观的界面、出色的计算功能和图表工具,再加上成功的市场营销,一直以来都是最为流行的个人计算机数据处理软件。当然,Excel也有很多竞品,例如Google Sheets、LibreOffice Calc、Numbers等,这些竞品基本上也能够兼容Excel,至少能够读写较新版本的Excel文件,当然这些不是我们讨论的重点。掌握用Python程序操作Excel文件,可以让日常办公自动化的工作更加轻松愉快,而且在很多商业项目中,导入导出Excel文件都是特别常见的功能。
|
||||
|
||||
Python操作Excel需要三方库的支持,如果要兼容Excel 2007以前的版本,也就是`xls`格式的Excel文件,可以使用三方库`xlrd`和`xlwt`,前者用于读Excel文件,后者用于写Excel文件。如果使用较新版本的Excel,即操作`xlsx`格式的Excel文件,可以使用`openpyxl`库,当然这个库不仅仅可以操作Excel,还可以操作其他基于Office Open XML的电子表格文件。
|
||||
|
||||
本章我们先讲解基于`xlwt`和`xlrd`操作Excel文件,大家可以先使用下面的命令安装这两个三方库以及配合使用的工具模块`xlutils`。
|
||||
|
||||
```Bash
|
||||
pip install xlwt xlrd xlutils
|
||||
```
|
||||
|
||||
### 读Excel文件
|
||||
|
||||
例如在当前文件夹下有一个名为“阿里巴巴2020年股票数据.xls”的Excel文件,如果想读取并显示该文件的内容,可以通过如下所示的代码来完成。
|
||||
|
||||
```Python
|
||||
import xlrd
|
||||
|
||||
# 使用xlrd模块的open_workbook函数打开指定Excel文件并获得Book对象(工作簿)
|
||||
wb = xlrd.open_workbook('阿里巴巴2020年股票数据.xls')
|
||||
# 通过Book对象的sheet_names方法可以获取所有表单名称
|
||||
sheetnames = wb.sheet_names()
|
||||
print(sheetnames)
|
||||
# 通过指定的表单名称获取Sheet对象(工作表)
|
||||
sheet = wb.sheet_by_name(sheetnames[0])
|
||||
# 通过Sheet对象的nrows和ncols属性获取表单的行数和列数
|
||||
print(sheet.nrows, sheet.ncols)
|
||||
for row in range(sheet.nrows):
|
||||
for col in range(sheet.ncols):
|
||||
# 通过Sheet对象的cell方法获取指定Cell对象(单元格)
|
||||
# 通过Cell对象的value属性获取单元格中的值
|
||||
value = sheet.cell(row, col).value
|
||||
# 对除首行外的其他行进行数据格式化处理
|
||||
if row > 0:
|
||||
# 第1列的xldate类型先转成元组再格式化为“年月日”的格式
|
||||
if col == 0:
|
||||
# xldate_as_tuple函数的第二个参数只有0和1两个取值
|
||||
# 其中0代表以1900-01-01为基准的日期,1代表以1904-01-01为基准的日期
|
||||
value = xlrd.xldate_as_tuple(value, 0)
|
||||
value = f'{value[0]}年{value[1]:>02d}月{value[2]:>02d}日'
|
||||
# 其他列的number类型处理成小数点后保留两位有效数字的浮点数
|
||||
else:
|
||||
value = f'{value:.2f}'
|
||||
print(value, end='\t')
|
||||
print()
|
||||
# 获取最后一个单元格的数据类型
|
||||
# 0 - 空值,1 - 字符串,2 - 数字,3 - 日期,4 - 布尔,5 - 错误
|
||||
last_cell_type = sheet.cell_type(sheet.nrows - 1, sheet.ncols - 1)
|
||||
print(last_cell_type)
|
||||
# 获取第一行的值(列表)
|
||||
print(sheet.row_values(0))
|
||||
# 获取指定行指定列范围的数据(列表)
|
||||
# 第一个参数代表行索引,第二个和第三个参数代表列的开始(含)和结束(不含)索引
|
||||
print(sheet.row_slice(3, 0, 5))
|
||||
```
|
||||
|
||||
相信通过上面的代码,大家已经了解到了如何读取一个Excel文件,如果想知道更多关于`xlrd`模块的知识,可以阅读它的[官方文档](https://xlrd.readthedocs.io/en/latest/)。
|
||||
|
||||
### 写Excel文件
|
||||
|
||||
写入Excel文件可以通过`xlwt` 模块的`Workbook`类创建工作簿对象,通过工作簿对象的`add_sheet`方法可以添加工作表,通过工作表对象的`write`方法可以向指定单元格中写入数据,最后通过工作簿对象的`save`方法将工作簿写入到指定的文件或内存中。下面的代码实现了将`5`个学生`3`门课程的考试成绩写入Excel文件的操作。
|
||||
|
||||
```Python
|
||||
import random
|
||||
|
||||
import xlwt
|
||||
|
||||
student_names = ['关羽', '张飞', '赵云', '马超', '黄忠']
|
||||
scores = [[random.randrange(50, 101) for _ in range(3)] for _ in range(5)]
|
||||
# 创建工作簿对象(Workbook)
|
||||
wb = xlwt.Workbook()
|
||||
# 创建工作表对象(Worksheet)
|
||||
sheet = wb.add_sheet('一年级二班')
|
||||
# 添加表头数据
|
||||
titles = ('姓名', '语文', '数学', '英语')
|
||||
for index, title in enumerate(titles):
|
||||
sheet.write(0, index, title)
|
||||
# 将学生姓名和考试成绩写入单元格
|
||||
for row in range(len(scores)):
|
||||
sheet.write(row + 1, 0, student_names[row])
|
||||
for col in range(len(scores[row])):
|
||||
sheet.write(row + 1, col + 1, scores[row][col])
|
||||
# 保存Excel工作簿
|
||||
wb.save('考试成绩表.xls')
|
||||
```
|
||||
|
||||
#### 调整单元格样式
|
||||
|
||||
在写Excel文件时,我们还可以为单元格设置样式,主要包括字体(Font)、对齐方式(Alignment)、边框(Border)和背景(Background)的设置,`xlwt`对这几项设置都封装了对应的类来支持。要设置单元格样式需要首先创建一个`XFStyle`对象,再通过该对象的属性对字体、对齐方式、边框等进行设定,例如在上面的例子中,如果希望将表头单元格的背景色修改为黄色,可以按照如下的方式进行操作。
|
||||
|
||||
```Python
|
||||
header_style = xlwt.XFStyle()
|
||||
pattern = xlwt.Pattern()
|
||||
pattern.pattern = xlwt.Pattern.SOLID_PATTERN
|
||||
# 0 - 黑色、1 - 白色、2 - 红色、3 - 绿色、4 - 蓝色、5 - 黄色、6 - 粉色、7 - 青色
|
||||
pattern.pattern_fore_colour = 5
|
||||
header_style.pattern = pattern
|
||||
titles = ('姓名', '语文', '数学', '英语')
|
||||
for index, title in enumerate(titles):
|
||||
sheet.write(0, index, title, header_style)
|
||||
```
|
||||
|
||||
如果希望为表头设置指定的字体,可以使用`Font`类并添加如下所示的代码。
|
||||
|
||||
```Python
|
||||
font = xlwt.Font()
|
||||
# 字体名称
|
||||
font.name = '华文楷体'
|
||||
# 字体大小(20是基准单位,18表示18px)
|
||||
font.height = 20 * 18
|
||||
# 是否使用粗体
|
||||
font.bold = True
|
||||
# 是否使用斜体
|
||||
font.italic = False
|
||||
# 字体颜色
|
||||
font.colour_index = 1
|
||||
header_style.font = font
|
||||
```
|
||||
|
||||
> **注意**:上面代码中指定的字体名(`font.name`)应当是本地系统有的字体,例如在我的电脑上有名为“华文楷体”的字体。
|
||||
|
||||
如果希望表头垂直居中对齐,可以使用下面的代码进行设置。
|
||||
|
||||
```Python
|
||||
align = xlwt.Alignment()
|
||||
# 垂直方向的对齐方式
|
||||
align.vert = xlwt.Alignment.VERT_CENTER
|
||||
# 水平方向的对齐方式
|
||||
align.horz = xlwt.Alignment.HORZ_CENTER
|
||||
header_style.alignment = align
|
||||
```
|
||||
|
||||
如果希望给表头加上黄色的虚线边框,可以使用下面的代码来设置。
|
||||
|
||||
```Python
|
||||
borders = xlwt.Borders()
|
||||
props = (
|
||||
('top', 'top_colour'), ('right', 'right_colour'),
|
||||
('bottom', 'bottom_colour'), ('left', 'left_colour')
|
||||
)
|
||||
# 通过循环对四个方向的边框样式及颜色进行设定
|
||||
for position, color in props:
|
||||
# 使用setattr内置函数动态给对象指定的属性赋值
|
||||
setattr(borders, position, xlwt.Borders.DASHED)
|
||||
setattr(borders, color, 5)
|
||||
header_style.borders = borders
|
||||
```
|
||||
|
||||
如果要调整单元格的宽度(列宽)和表头的高度(行高),可以按照下面的代码进行操作。
|
||||
|
||||
```Python
|
||||
# 设置行高为40px
|
||||
sheet.row(0).set_style(xlwt.easyxf(f'font:height {20 * 40}'))
|
||||
titles = ('姓名', '语文', '数学', '英语')
|
||||
for index, title in enumerate(titles):
|
||||
# 设置列宽为200px
|
||||
sheet.col(index).width = 20 * 200
|
||||
# 设置单元格的数据和样式
|
||||
sheet.write(0, index, title, header_style)
|
||||
```
|
||||
|
||||
#### 公式计算
|
||||
|
||||
对于前面打开的“阿里巴巴2020年股票数据.xls”文件,如果要统计全年收盘价(Close字段)的平均值以及全年交易量(Volume字段)的总和,可以使用Excel的公式计算即可。我们可以先使用`xlrd`读取Excel文件夹,然后通过`xlutils`三方库提供的`copy`函数将读取到的Excel文件转成`Workbook`对象进行写操作,在调用`write`方法时,可以将一个`Formula`对象写入单元格。
|
||||
|
||||
实现公式计算的代码如下所示。
|
||||
|
||||
```Python
|
||||
import xlrd
|
||||
import xlwt
|
||||
from xlutils.copy import copy
|
||||
|
||||
wb_for_read = xlrd.open_workbook('阿里巴巴2020年股票数据.xls')
|
||||
sheet1 = wb_for_read.sheet_by_index(0)
|
||||
nrows, ncols = sheet1.nrows, sheet1.ncols
|
||||
wb_for_write = copy(wb_for_read)
|
||||
sheet2 = wb_for_write.get_sheet(0)
|
||||
sheet2.write(nrows, 4, xlwt.Formula(f'average(E2:E{nrows})'))
|
||||
sheet2.write(nrows, 6, xlwt.Formula(f'sum(G2:G{nrows})'))
|
||||
wb_for_write.save('阿里巴巴2020年股票数据汇总.xls')
|
||||
```
|
||||
|
||||
> **说明**:上面的代码有一些小瑕疵,有兴趣的读者可以自行探索如何解决。
|
||||
|
||||
### 简单的总结
|
||||
|
||||
掌握了Python程序操作Excel的方法,可以解决日常办公中很多繁琐的处理Excel电子表格工作,最常见就是将多个数据格式相同的Excel文件合并到一个文件以及从多个Excel文件或表单中提取指定的数据。当然,如果要对表格数据进行处理,使用Python数据分析神器之一的`pandas`库可能更为方便。
|
|
@ -0,0 +1,180 @@
|
|||
## 第25课:用Python读写Excel文件-2
|
||||
|
||||
### Excel简介
|
||||
|
||||
Excel是Microsoft(微软)为使用Windows和macOS操作系统开发的一款电子表格软件。Excel凭借其直观的界面、出色的计算功能和图表工具,再加上成功的市场营销,一直以来都是最为流行的个人计算机数据处理软件。当然,Excel也有很多竞品,例如Google Sheets、LibreOffice Calc、Numbers等,这些竞品基本上也能够兼容Excel,至少能够读写较新版本的Excel文件,当然这些不是我们讨论的重点。掌握用Python程序操作Excel文件,可以让日常办公自动化的工作更加轻松愉快,而且在很多商业项目中,导入导出Excel文件都是特别常见的功能。
|
||||
|
||||
本章我们继续讲解基于另一个三方库`openpyxl`如何进行Excel文件操作,首先需要先安装它。
|
||||
|
||||
```Bash
|
||||
pip install openpyxl
|
||||
```
|
||||
|
||||
`openpyxl`的优点在于,当我们打开一个Excel文件后,既可以对它进行读操作,又可以对它进行写操作,而且在操作的便捷性上是优于`xlwt`和`xlrd`的。此外,如果要进行样式编辑和公式计算,使用`openpyxl`也远比上一个章节我们讲解的方式更为简单,而且`openpyxl`还支持数据透视和插入图表等操作,功能非常强大。有一点需要再次强调,`openpyxl`并不支持操作Office 2007以前版本的Excel文件。
|
||||
|
||||
### 读取Excel文件
|
||||
|
||||
例如在当前文件夹下有一个名为“阿里巴巴2020年股票数据.xlsx”的Excel文件,如果想读取并显示该文件的内容,可以通过如下所示的代码来完成。
|
||||
|
||||
```Python
|
||||
import datetime
|
||||
|
||||
import openpyxl
|
||||
|
||||
# 加载一个工作簿 ---> Workbook
|
||||
wb = openpyxl.load_workbook('阿里巴巴2020年股票数据.xlsx')
|
||||
# 获取工作表的名字
|
||||
print(wb.sheetnames)
|
||||
# 获取工作表 ---> Worksheet
|
||||
sheet = wb.worksheets[0]
|
||||
# 获得单元格的范围
|
||||
print(sheet.dimensions)
|
||||
# 获得行数和列数
|
||||
print(sheet.max_row, sheet.max_column)
|
||||
|
||||
# 获取指定单元格的值
|
||||
print(sheet.cell(3, 3).value)
|
||||
print(sheet['C3'].value)
|
||||
print(sheet['G255'].value)
|
||||
|
||||
# 获取多个单元格(嵌套元组)
|
||||
print(sheet['A2:C5'])
|
||||
|
||||
# 读取所有单元格的数据
|
||||
for row_ch in range(2, sheet.max_row + 1):
|
||||
for col_ch in 'ABCDEFG':
|
||||
value = sheet[f'{col_ch}{row_ch}'].value
|
||||
if type(value) == datetime.datetime:
|
||||
print(value.strftime('%Y年%m月%d日'), end='\t')
|
||||
elif type(value) == int:
|
||||
print(f'{value:<10d}', end='\t')
|
||||
elif type(value) == float:
|
||||
print(f'{value:.4f}', end='\t')
|
||||
else:
|
||||
print(value, end='\t')
|
||||
print()
|
||||
```
|
||||
|
||||
需要提醒大家一点,`openpyxl`获取指定的单元格有两种方式,一种是通过`cell`方法,需要注意,该方法的行索引和列索引都是从`1`开始的,这是为了照顾用惯了Excel的人的习惯;另一种是通过索引运算,通过指定单元格的坐标,例如`C3`、`G255`,也可以取得对应的单元格,再通过单元格对象的`value`属性,就可以获取到单元格的值。通过上面的代码,相信大家还注意到了,可以通过类似`sheet['A2:C5']`或`sheet['A2':'C5']`这样的切片操作获取多个单元格,该操作将返回嵌套的元组,相当于获取到了多行多列。
|
||||
|
||||
### 写Excel文件
|
||||
|
||||
下面我们使用`openpyxl`来进行写Excel操作。
|
||||
|
||||
```Python
|
||||
import random
|
||||
|
||||
import openpyxl
|
||||
|
||||
# 第一步:创建工作簿(Workbook)
|
||||
wb = openpyxl.Workbook()
|
||||
|
||||
# 第二步:添加工作表(Worksheet)
|
||||
sheet = wb.active
|
||||
sheet.title = '期末成绩'
|
||||
|
||||
titles = ('姓名', '语文', '数学', '英语')
|
||||
for col_index, title in enumerate(titles):
|
||||
sheet.cell(1, col_index + 1, title)
|
||||
|
||||
names = ('关羽', '张飞', '赵云', '马超', '黄忠')
|
||||
for row_index, name in enumerate(names):
|
||||
sheet.cell(row_index + 2, 1, name)
|
||||
for col_index in range(2, 5):
|
||||
sheet.cell(row_index + 2, col_index, random.randrange(50, 101))
|
||||
|
||||
# 第四步:保存工作簿
|
||||
wb.save('考试成绩表.xlsx')
|
||||
```
|
||||
|
||||
#### 调整样式和公式计算
|
||||
|
||||
在使用`openpyxl`操作Excel时,如果要调整单元格的样式,可以直接通过单元格对象(`Cell`对象)的属性进行操作。单元格对象的属性包括字体(`font`)、对齐(`alignment`)、边框(`border`)等,具体的可以参考`openpyxl`的[官方文档](https://openpyxl.readthedocs.io/en/stable/index.html)。在使用`openpyxl`时,如果需要做公式计算,可以完全按照Excel中的操作方式来进行,具体的代码如下所示。
|
||||
|
||||
```Python
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font, Alignment, Border, Side
|
||||
|
||||
# 对齐方式
|
||||
alignment = Alignment(horizontal='center', vertical='center')
|
||||
# 边框线条
|
||||
side = Side(color='ff7f50', style='mediumDashed')
|
||||
|
||||
wb = openpyxl.load_workbook('考试成绩表.xlsx')
|
||||
sheet = wb.worksheets[0]
|
||||
|
||||
# 调整行高和列宽
|
||||
sheet.row_dimensions[1].height = 30
|
||||
sheet.column_dimensions['E'].width = 120
|
||||
|
||||
sheet['E1'] = '平均分'
|
||||
# 设置字体
|
||||
sheet.cell(1, 5).font = Font(size=18, bold=True, color='ff1493', name='华文楷体')
|
||||
# 设置对齐方式
|
||||
sheet.cell(1, 5).alignment = alignment
|
||||
# 设置单元格边框
|
||||
sheet.cell(1, 5).border = Border(left=side, top=side, right=side, bottom=side)
|
||||
for i in range(2, 7):
|
||||
# 公式计算每个学生的平均分
|
||||
sheet[f'E{i}'] = f'=average(B{i}:D{i})'
|
||||
sheet.cell(i, 5).font = Font(size=12, color='4169e1', italic=True)
|
||||
sheet.cell(i, 5).alignment = alignment
|
||||
|
||||
wb.save('考试成绩表.xlsx')
|
||||
```
|
||||
|
||||
### 生成统计图表
|
||||
|
||||
通过`openpyxl`库,可以直接向Excel中插入统计图表,具体的做法跟在Excel中插入图表大体一致。我们可以创建指定类型的图表对象,然后通过该对象的属性对图表进行设置。当然,最为重要的是为图表绑定数据,即横轴代表什么,纵轴代表什么,具体的数值是多少。最后,可以将图表对象添加到表单中,具体的代码如下所示。
|
||||
|
||||
```Python
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.chart import BarChart, Reference
|
||||
|
||||
wb = Workbook(write_only=True)
|
||||
sheet = wb.create_sheet()
|
||||
|
||||
rows = [
|
||||
('类别', '销售A组', '销售B组'),
|
||||
('手机', 40, 30),
|
||||
('平板', 50, 60),
|
||||
('笔记本', 80, 70),
|
||||
('外围设备', 20, 10),
|
||||
]
|
||||
|
||||
# 向表单中添加行
|
||||
for row in rows:
|
||||
sheet.append(row)
|
||||
|
||||
# 创建图表对象
|
||||
chart = BarChart()
|
||||
chart.type = 'col'
|
||||
chart.style = 10
|
||||
# 设置图表的标题
|
||||
chart.title = '销售统计图'
|
||||
# 设置图表纵轴的标题
|
||||
chart.y_axis.title = '销量'
|
||||
# 设置图表横轴的标题
|
||||
chart.x_axis.title = '商品类别'
|
||||
# 设置数据的范围
|
||||
data = Reference(sheet, min_col=2, min_row=1, max_row=5, max_col=3)
|
||||
# 设置分类的范围
|
||||
cats = Reference(sheet, min_col=1, min_row=2, max_row=5)
|
||||
# 给图表添加数据
|
||||
chart.add_data(data, titles_from_data=True)
|
||||
# 给图表设置分类
|
||||
chart.set_categories(cats)
|
||||
chart.shape = 4
|
||||
# 将图表添加到表单指定的单元格中
|
||||
sheet.add_chart(chart, 'A10')
|
||||
|
||||
wb.save('demo.xlsx')
|
||||
```
|
||||
|
||||
运行上面的代码,打开生成的Excel文件,效果如下图所示。
|
||||
|
||||
<img src="https://gitee.com/jackfrued/mypic/raw/master/20210819235009.png" alt="image-20210819235009026" width="75%">
|
||||
|
||||
### 简单的总结
|
||||
|
||||
掌握了Python程序操作Excel的方法,可以解决日常办公中很多繁琐的处理Excel电子表格工作,最常见就是将多个数据格式相同的Excel文件合并到一个文件以及从多个Excel文件或表单中提取指定的数据。如果数据体量较大或者处理数据的方式比较复杂,我们还是推荐大家使用Python数据分析神器之一的`pandas`库。
|
|
@ -0,0 +1,240 @@
|
|||
## 第26课:用Python操作Word和PowerPoint
|
||||
|
||||
在日常工作中,有很多简单重复的劳动其实完全可以交给Python程序,比如根据样板文件(模板文件)批量的生成很多个Word文件或PowerPoint文件。Word是微软公司开发的文字处理程序,相信大家都不陌生,日常办公中很多正式的文档都是用Word进行撰写和编辑的,目前使用的Word文件后缀名一般为`.docx`。PowerPoint是微软公司开发的演示文稿程序,是微软的Office系列软件中的一员,被商业人士、教师、学生等群体广泛使用,通常也将其称之为“幻灯片”。在Python中,可以使用名为`python-docx` 的三方库来操作Word,可以使用名为`python-pptx`的三方库来生成PowerPoint。
|
||||
|
||||
### 操作Word文档
|
||||
|
||||
我们可以先通过下面的命令来安装`python-docx`三方库。
|
||||
|
||||
```bash
|
||||
pip install python-docx
|
||||
```
|
||||
|
||||
按照[官方文档](https://python-docx.readthedocs.io/en/latest/)的介绍,我们可以使用如下所示的代码来生成一个简单的Word文档。
|
||||
|
||||
```Python
|
||||
from docx import Document
|
||||
from docx.shared import Cm, Pt
|
||||
|
||||
from docx.document import Document as Doc
|
||||
|
||||
# 创建代表Word文档的Doc对象
|
||||
document = Document() # type: Doc
|
||||
# 添加大标题
|
||||
document.add_heading('快快乐乐学Python', 0)
|
||||
# 添加段落
|
||||
p = document.add_paragraph('Python是一门非常流行的编程语言,它')
|
||||
run = p.add_run('简单')
|
||||
run.bold = True
|
||||
run.font.size = Pt(18)
|
||||
p.add_run('而且')
|
||||
run = p.add_run('优雅')
|
||||
run.font.size = Pt(18)
|
||||
run.underline = True
|
||||
p.add_run('。')
|
||||
|
||||
# 添加一级标题
|
||||
document.add_heading('Heading, level 1', level=1)
|
||||
# 添加带样式的段落
|
||||
document.add_paragraph('Intense quote', style='Intense Quote')
|
||||
# 添加无序列表
|
||||
document.add_paragraph(
|
||||
'first item in unordered list', style='List Bullet'
|
||||
)
|
||||
document.add_paragraph(
|
||||
'second item in ordered list', style='List Bullet'
|
||||
)
|
||||
# 添加有序列表
|
||||
document.add_paragraph(
|
||||
'first item in ordered list', style='List Number'
|
||||
)
|
||||
document.add_paragraph(
|
||||
'second item in ordered list', style='List Number'
|
||||
)
|
||||
|
||||
# 添加图片(注意路径和图片必须要存在)
|
||||
document.add_picture('resources/guido.jpg', width=Cm(5.2))
|
||||
|
||||
# 添加分节符
|
||||
document.add_section()
|
||||
|
||||
records = (
|
||||
('骆昊', '男', '1995-5-5'),
|
||||
('孙美丽', '女', '1992-2-2')
|
||||
)
|
||||
# 添加表格
|
||||
table = document.add_table(rows=1, cols=3)
|
||||
table.style = 'Dark List'
|
||||
hdr_cells = table.rows[0].cells
|
||||
hdr_cells[0].text = '姓名'
|
||||
hdr_cells[1].text = '性别'
|
||||
hdr_cells[2].text = '出生日期'
|
||||
# 为表格添加行
|
||||
for name, sex, birthday in records:
|
||||
row_cells = table.add_row().cells
|
||||
row_cells[0].text = name
|
||||
row_cells[1].text = sex
|
||||
row_cells[2].text = birthday
|
||||
|
||||
# 添加分页符
|
||||
document.add_page_break()
|
||||
|
||||
# 保存文档
|
||||
document.save('demo.docx')
|
||||
```
|
||||
|
||||
执行上面的代码,打开生成的Word文档,效果如下图所示。
|
||||
|
||||
<img src="https://gitee.com/jackfrued/mypic/raw/master/20210820002742.png" alt="image-20210820002742341" width="40%"> <img src="https://gitee.com/jackfrued/mypic/raw/master/20210820002843.png" alt="image-20210820002843696" width="40%">
|
||||
|
||||
对于一个已经存在的Word文件,我们可以通过下面的代码去遍历它所有的段落并获取对应的内容。
|
||||
|
||||
```Python
|
||||
from docx import Document
|
||||
from docx.document import Document as Doc
|
||||
|
||||
doc = Document('resources/离职证明.docx') # type: Doc
|
||||
for no, p in enumerate(doc.paragraphs):
|
||||
print(no, p.text)
|
||||
```
|
||||
|
||||
> **提示**:如果需要上面代码中的Word文件,可以通过下面的百度云盘地址进行获取。
|
||||
|
||||
读取到的内容如下所示。
|
||||
|
||||
```
|
||||
0
|
||||
1 离 职 证 明
|
||||
2
|
||||
3 兹证明 王大锤 ,身份证号码: 100200199512120001 ,于 2018 年 8 月 7 日至 2020 年 6 月 28 日在我单位 开发部 部门担任 Java开发工程师 职务,在职期间无不良表现。因 个人 原因,于 2020 年 6 月 28 日起终止解除劳动合同。现已结清财务相关费用,办理完解除劳动关系相关手续,双方不存在任何劳动争议。
|
||||
4
|
||||
5 特此证明!
|
||||
6
|
||||
7
|
||||
8 公司名称(盖章):成都风车车科技有限公司
|
||||
9 2020 年 6 月 28 日
|
||||
```
|
||||
|
||||
讲到这里,相信很多读者已经想到了,我们可以把上面的离职证明制作成一个模板文件,把姓名、身份证号、入职和离职日期等信息用占位符代替,这样通过对占位符的替换,就可以根据实际需要写入对应的信息,这样就可以批量的生成Word文档。
|
||||
|
||||
按照上面的思路,我们首先编辑一个离职证明的模板文件,如下图所示。
|
||||
|
||||
<img src="https://gitee.com/jackfrued/mypic/raw/master/20210820004223.png" alt="image-20210820004223731" width="75%" style="border:1px solid black"/>
|
||||
|
||||
接下来我们读取该文件,将占位符替换为真实信息,就可以生成一个新的Word文档,如下所示。
|
||||
|
||||
```Python
|
||||
from docx import Document
|
||||
from docx.document import Document as Doc
|
||||
|
||||
# 将真实信息用字典的方式保存在列表中
|
||||
employees = [
|
||||
{
|
||||
'name': '骆昊',
|
||||
'id': '100200198011280001',
|
||||
'sdate': '2008年3月1日',
|
||||
'edate': '2012年2月29日',
|
||||
'department': '产品研发',
|
||||
'position': '架构师',
|
||||
'company': '成都华为技术有限公司'
|
||||
},
|
||||
{
|
||||
'name': '王大锤',
|
||||
'id': '510210199012125566',
|
||||
'sdate': '2019年1月1日',
|
||||
'edate': '2021年4月30日',
|
||||
'department': '产品研发',
|
||||
'position': 'Python开发工程师',
|
||||
'company': '成都谷道科技有限公司'
|
||||
},
|
||||
{
|
||||
'name': '李元芳',
|
||||
'id': '2102101995103221599',
|
||||
'sdate': '2020年5月10日',
|
||||
'edate': '2021年3月5日',
|
||||
'department': '产品研发',
|
||||
'position': 'Java开发工程师',
|
||||
'company': '同城企业管理集团有限公司'
|
||||
},
|
||||
]
|
||||
# 对列表进行循环遍历,批量生成Word文档
|
||||
for emp_dict in employees:
|
||||
# 读取离职证明模板文件
|
||||
doc = Document('resources/离职证明模板.docx') # type: Doc
|
||||
# 循环遍历所有段落寻找占位符
|
||||
for p in doc.paragraphs:
|
||||
if '{' not in p.text:
|
||||
continue
|
||||
# 不能直接修改段落内容,否则会丢失样式
|
||||
# 所以需要对段落中的元素进行遍历并进行查找替换
|
||||
for run in p.runs:
|
||||
if '{' not in run.text:
|
||||
continue
|
||||
# 将占位符换成实际内容
|
||||
start, end = run.text.find('{'), run.text.find('}')
|
||||
key, place_holder = run.text[start + 1:end], run.text[start:end + 1]
|
||||
run.text = run.text.replace(place_holder, emp_dict[key])
|
||||
# 每个人对应保存一个Word文档
|
||||
doc.save(f'{emp_dict["name"]}离职证明.docx')
|
||||
```
|
||||
|
||||
执行上面的代码,会在当前路径下生成三个Word文档,如下图所示。
|
||||
|
||||
<img src="https://gitee.com/jackfrued/mypic/raw/master/20210820004825.png" alt="image-20210820004825183" width="50%">
|
||||
|
||||
### 生成PowerPoint
|
||||
|
||||
首先我们需要安装名为`python-pptx`的三方库,命令如下所示。
|
||||
|
||||
```Bash
|
||||
pip install python-pptx
|
||||
```
|
||||
|
||||
用Python操作PowerPoint的内容,因为实际应用场景不算很多,我不打算在这里进行赘述,有兴趣的读者可以自行阅读`python-pptx`的[官方文档](https://python-pptx.readthedocs.io/en/latest/),下面仅展示一段来自于官方文档的代码。
|
||||
|
||||
```Python
|
||||
from pptx import Presentation
|
||||
|
||||
# 创建幻灯片对象
|
||||
pres = Presentation()
|
||||
|
||||
# 选择母版添加一页
|
||||
title_slide_layout = pres.slide_layouts[0]
|
||||
slide = pres.slides.add_slide(title_slide_layout)
|
||||
# 获取标题栏和副标题栏
|
||||
title = slide.shapes.title
|
||||
subtitle = slide.placeholders[1]
|
||||
# 编辑标题和副标题
|
||||
title.text = "Welcome to Python"
|
||||
subtitle.text = "Life is short, I use Python"
|
||||
|
||||
# 选择母版添加一页
|
||||
bullet_slide_layout = pres.slide_layouts[1]
|
||||
slide = pres.slides.add_slide(bullet_slide_layout)
|
||||
# 获取页面上所有形状
|
||||
shapes = slide.shapes
|
||||
# 获取标题和主体
|
||||
title_shape = shapes.title
|
||||
body_shape = shapes.placeholders[1]
|
||||
# 编辑标题
|
||||
title_shape.text = 'Introduction'
|
||||
# 编辑主体内容
|
||||
tf = body_shape.text_frame
|
||||
tf.text = 'History of Python'
|
||||
# 添加一个一级段落
|
||||
p = tf.add_paragraph()
|
||||
p.text = 'X\'max 1989'
|
||||
p.level = 1
|
||||
# 添加一个二级段落
|
||||
p = tf.add_paragraph()
|
||||
p.text = 'Guido began to write interpreter for Python.'
|
||||
p.level = 2
|
||||
|
||||
# 保存幻灯片
|
||||
pres.save('test.pptx')
|
||||
```
|
||||
|
||||
运行上面的代码,生成的PowerPoint文件如下图所示。
|
||||
|
||||
<img src="https://gitee.com/jackfrued/mypic/raw/master/20210820010306.png" alt="image-20210820010306008" width="75%" />
|
||||
|
Loading…
Reference in New Issue