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,并且应用以下样式:

  1. 表头字体都加粗
  2. 数据行奇数行背景颜色变灰

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的参数如下:

  1. table: Table对象变量名
  2. sheet_name: Sheet名称,可选,默认为Table对象的name属性
  3. style: 样式列表,可选。
  4. 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

results matching ""

    No results matching ""