Chapter10 全方位操作Excel
读取Excel文件
使用read_excel插件可以将xls或xlsx文件加载到内存进行处理:
read_excel.py
# coding: utf-8
"""
Docs goes here
"""
from girlfriend.workflow.gfworkflow import Job
from girlfriend.plugin.excel import SheetR
from girlfriend.data.table import TableWrapper
logger = None
logger_level = "info"
class User(object):
def __init__(self, id_, name, clazz, score):
self.id = id_
self.name = name
self.clazz = clazz
self.score = score
def workflow(options):
work_units = (
# read_excel
Job(
name="read_excel",
plugin="read_excel",
args=[
"students.xlsx",
SheetR(
sheetname="students",
record_handler=lambda row: User(*row),
record_filter=None,
result_wrapper=TableWrapper(
u"学生表",
titles=[
"id", u"编号",
"name", u"姓名",
"clazz", u"班级",
"score", u"成绩"
]
),
skip_first_row=True,
variable="students_table"
),
]
),
# print_table
Job(
name="print_table",
plugin="print_table",
args=[
"$students_table",
]
),
)
return work_units
read_excel接受的第一个参数为excel文件路径,接下来的参数都是SheetR对象,每一个SheetR对象代表了一个要读取的Sheet。SheetR的参数如下:
sheetname: Sheet的名称,通过这个名称来查找对应的Sheet,必须项。
record_handler: 接受一个列表,该列表包含一行数据,用该函数对该行进行包装。选填
record_filter: 记录过滤器,接受一个被record_handler包装后的对象 选填
result_wrapper: 最终结果包装器 选填
skip_first_row: 是否要跳过第一行,如果第一行为标题,那么可以将该参数设置为True。选填,默认为False。
variable: 将处理结果保存到上下文的变量名。也可以不指定,read_excel插件最终会将所有SheetR的处理结果保存到一个list当中,你可以通过$read_excel.result来引用。选填。
写入Excel
通过write_excel插件可以将内存中的Table对象导出到xlsx文件。write_excel是对xlsxwriter库的包装,并且暴露了一些接口允许你直接访问xlsxwriter的API。
接下来我们将一组数据保存为excel,并且应用以下样式:
- 表头字体都加粗
- 数据行奇数行背景颜色变灰
write_excel.py:
# coding: utf-8
"""
Docs goes here
"""
from girlfriend.workflow.gfworkflow import Job
from girlfriend.plugin.excel import SheetW, CellStyle
from girlfriend.data.table import Title, ListTable
logger = None
logger_level = "info"
def workflow(options):
work_units = (
# make_data
Job(
name="make_data",
caller=_make_data,
),
# write_excel
Job(
name="write_excel",
plugin="write_excel",
args={
"filepath": "test.xlsx",
"sheets": (
SheetW(
table="channel_table",
sheet_name="channel",
style=[
CellStyle(0, {'bold': True}),
CellStyle(_even_row, {'bg_color': "gray"})
],
sheet_handler=None
),
),
"workbook_handler": None
}
),
)
return work_units
def _make_data(ctx):
ctx["channel_table"] = ListTable(
"channel",
(
Title("name", u"渠道"),
Title("date", u"月份"),
Title("num", u"注册数")
),
[
(u"百度", 1, 100),
(u"百度", 2, 121),
(u"百度", 3, 131),
(u"谷歌", 1, 91),
(u"谷歌", 2, 111),
(u"谷歌", 3, 123)
]
)
def _even_row(row_index, column_index):
return row_index != 0 and row_index % 2 != 0
write_excel接受的第一个参数filepath为输出的Excel文件路径,除了输出到文件系统,还可以输出到一个StringIO对象:
Job(
name="write_excel",
plugin="write_excel",
args={
"filepath": "memory:test",
...
}
)
这样就可以把Excel格式的数据写入到名字为test的上下文变量中。比如当你需要将Excel作为邮件附件发送时,这样做很有用,避免了在其他工作单元中重复的文件读取。剩下的每一个SheetW对象代表一个要写入的Sheet,SheetW的参数如下:
- table: Table对象变量名
- sheet_name: Sheet名称,可选,默认为Table对象的name属性
- style: 样式列表,可选。
- sheet_handler: 这个参数接受一个回调函数,该函数接受一个Workbook对象和一个xlsxwriter.worksheet.Worksheet对象,这样就可以让用户自由使用worksheet对象中的诸多方法来定义更灵活的样式。比如我们要在表格底部画一个柱状图:
draw_chart.py
# coding: utf-8
from girlfriend.workflow.gfworkflow import Job
from girlfriend.plugin.excel import SheetW, CellStyle
from girlfriend.data.table import Title, ListTable
logger = None
logger_level = "info"
def workflow(options):
work_units = (
# make_data
Job(
name="make_data",
caller=_make_data,
),
# write_excel
Job(
name="write_excel",
plugin="write_excel",
args={
"filepath": "test.xlsx",
"sheets": (
SheetW(
table="channel_table",
sheet_name="channel",
style=[
CellStyle(0, {'bold': True}),
CellStyle(_even_row, {'bg_color': "gray"})
],
sheet_handler=_draw_chart
),
),
"workbook_handler": None
}
),
)
return work_units
def _make_data(ctx):
ctx["channel_table"] = ListTable(
"channel",
(
Title("name", u"渠道"),
Title("date", u"月份"),
Title("num", u"注册数")
),
[
(u"百度", 1, 100),
(u"百度", 2, 121),
(u"百度", 3, 131),
(u"谷歌", 1, 91),
(u"谷歌", 2, 111),
(u"谷歌", 3, 123)
]
)
def _even_row(row_index, column_index):
return row_index != 0 and row_index % 2 != 0
def _draw_chart(workbook, sheet):
"""绘制图表
"""
chart = workbook.add_chart({"type": "column"})
chart.add_series({
"categories": "=channel! $B$2: $B$4",
"values": "=channel! $C$2: $C$4",
"name": u"百度"
})
chart.add_series({"values": "=channel! $C$5: $C$7", "name": u"谷歌"})
sheet.insert_chart("A8", chart)
通过在sheet_handler中操控Workbook和Worksheet对象,我们就绘制出了可供数据对比的条形图。更多的绘图API
关于CellStyle
CellStyle类是对Excel样式的抽象,由两个要素组成,一个是选择器,一个是样式字典。通过使用选择器来选择应用样式的行和列,选择器可以是数字索引、用元组表示的范围以及动态决策的函数,样式字典包含了样式名称到属性值的具体样式项,参见 Format 类。
# 选择第0行,也就是标题行
CellStyle(0, {'bold': True})
# 选择第10到20行
CellStyle([(10, 20), None], {'bold': True})
# 选择第10到20行中的前4列
CellStyle([(10, 20), (0, 3)], {'bold': True})
# 通过函数来选择奇数行
CellStyle(_even_row, {'bg_color': "gray"})
...
def _even_row(row_index, column_index):
return row_index != 0 and row_index % 2 != 0