python 操作excel_Python 操作 Excel

1. Python openpyxl 库介绍

  • 介绍

openpyxl 是 python 操作 Excel 的库,覆盖普通的读写操作、样式设置等功能。支持 2010版本后的 Excel 文件格式。

  • openpyxl 安装

1pip3 install openpyxl  -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
  • openpyxl 基本操作

 1from openpyxl import Workbook
2wb = Workbook()
3
4# grab the active worksheet
5ws = wb.active
6
7# Data can be assigned directly to cells
8ws['A1'] = 42
9
10# Rows can also be appended
11ws.append([1, 2, 3])
12
13# Python types will automatically be converted
14import datetime
15ws['A2'] = datetime.datetime.now()
16
17# Save the file
18wb.save("sample.xlsx")

2. Python 操作 Excel 表格

  • 读取表格

 1import os
2import openpyxl
3from collections import OrderedDict
4
5
6def read_excel(fn, sn=None):
7    """ 8    windows 无法识别中文文件名,第一行是表头标题 9    最终格式是返回一个列表,元素是字典,key:表头 value:值10    :param fn: 文件名11    :param sn:  excel 表名12    :return:13    """
14    if not os.path.isfile(fn):
15        print("Excel File Not Found:{}".format(fn))
16        return []
17    wb = openpyxl.load_workbook(fn)
18    print("Excel Sheets List: {}".format(wb.sheetnames))
19    if not sn:
20        sheet = wb.active
21    else:
22        if sn not in wb.sheetnames:
23            print("Error Sheet Name:{}".format(sn))
24            return []
25        sheet = wb[sn]
26    print("Sheet Name is 【{}】, Max Column Num: {}".format(sheet.title, sheet.max_column))
27    # 删掉无用的空白列或者空白格,减少内存遍历(Ctrl + shift + →【箭头】 删掉)
28    print("Max Row Num: {}".format(sheet.max_row))
29    col_num = 0
30    first = True
31    cols_val = OrderedDict()
32    all_row = []  # 返回所有的行
33    for row in sheet.iter_rows():
34        i = 0
35        if first:  # first row Title
36            for cell in row:
37                col_num += 1
38                if not cell.value:
39                    print("Excel Table Title Empty(column num is {})".format(col_num))
40                    continue
41                cols_val[col_num] = cell.value.strip()
42            first = False
43            print("Excel Table Title: {}".format(cols_val.values()))
44            continue
45        rows_val = []
46        for cell in row:
47            i += 1
48            if i not in cols_val:  # 没有表头的则过滤掉该列
49                continue
50            rows_val.append(cell.value if cell.value is not None else "")
51        if rows_val:
52            all_row.append(OrderedDict(zip(cols_val.values(), rows_val)))
53    print("All Row Num:{}".format(len(all_row)))
54    return all_row
  • 写入表格并设置样式

  1def _fill_excel(sheet, *rows):
2    """ 3    设置 sheet 表的样式和内容 4    :param sheet:  表格 5    :param rows:  内容 6    :return: 7    """
8    border = Border(
9        left=Side(style="thin", color="FF000000"),
10        right=Side(style="thin", color="FF000000"),
11        top=Side(style="thin", color="FF000000"),
12        bottom=Side(style="thin", color="FF000000"),
13        diagonal=Side(style="thin", color="FF000000"),
14        diagonal_direction=0,
15        outline=Side(style="medium", color="FF000000"),
16        vertical=Side(style="thin", color="FF000000"),
17        horizontal=Side(style="thin", color="FF000000")
18    )
19
20    for rn, row in enumerate(rows):
21        sheet.row_dimensions[rn + 1].height = 20
22        if 0 == rn:  # 第一行
23            col_char = ord('A')
24            for cn, col in enumerate(row):
25                cell = sheet.cell(rn + 1, cn + 1)
26                cell.value = col
27                cell.border = border
28                sheet.column_dimensions[chr(col_char)].width = 40
29                col_char += 1
30                cell.fill = PatternFill(fill_type="solid", fgColor="0070C0")
31                cell.font = Font(name="黑体", size=14, italic=False, color="FFFF00", bold=True)
32            continue
33        for cn, col in enumerate(row):
34            cell = sheet.cell(rn + 1, cn + 1)
35            cell.value = col
36            cell.border = border
37            cell.font = Font(name="微软雅黑", size=14, italic=False, color="000000", bold=False)
38    return
39
40
41def make_excels(path=".", prefix="output_default", *multi):
42    """ 43    同时写入多个 sheet 表格,最终只保存一个 excel 文件 44    :param path:  文件保存路径 45    :param prefix:  文件名前缀, 全名是 $prefix_$day.xlsx 46    :param multi: 多个sheet文件的内容数组, each item : 47        { 48            "name": 表名, 49            "rows":[[表头xx, 表头xx, 表头xx], [数据xx, 数据xx, 数据xx],  [数据xx, 数据xx, 数据xx]] 50        } 51    :return: 52    """
53    if not os.path.isdir(path):
54        print("Path :{} Not Found!".format(path))
55        return ''
56    name = u"{}_{}.xlsx".format(os.path.join(path, prefix), time.strftime("%Y-%m-%d"))
57    wb = openpyxl.Workbook()
58    for index, each in enumerate(multi):
59        sheet_name = each["name"]
60        rows = each["rows"]
61        if 0 == index:
62            sheet = wb.active
63            sheet.title = sheet_name
64        else:
65            sheet = wb.create_sheet(sheet_name)
66        _fill_excel(sheet, *rows)
67        wb.save(name)
68    return name
69
70def test_write():
71    rows1 = {
72        "name": "Sheet-A",
73        "rows": [
74            ["发票", "金额", "报销人"],
75            ["NO100001", "100000", "小米"],
76            ["NO100002", "100000", "小名"],
77            ["NO100003", "100000", "小请"],
78            ["NO100004", "100000", "小黄"],
79            ["NO100005", "100000", "小洪"],
80            ["NO100006", "100000", "小来"],
81        ]
82    }
83
84    rows2 = {
85        "name": "Sheet-B",
86        "rows": [
87            ["品种", "价格", "厂家"],
88            ["NO100001", "100000", "小米"],
89            ["NO100002", "100000", "小名"],
90            ["NO100003", "100000", "小请"],
91            ["NO100004", "100000", "小黄"],
92            ["NO100005", "100000", "小洪"],
93            ["NO100006", "100000", "小来"],
94        ]
95    }
96    print(make_excels("d:\\", "price", rows1, rows2))
97
98if __name__ == "__main__":
99    # test_read()
100    test_write()

最终结果如图所示

85a3f86527d72feb94520189d530e2e2.png
样式展示
  • 增量写入表格

即在原表格基础上添加数据,本函数演示的是直接添加到最后面的列

 1def append_excel(fn, titles, rows, sn=None):
2    """ 3    该函数会直接修改 表格内容 4    向已存在的表格里面增加 titles 表头,内容是 rows内容. 按顺序匹配 5    """
6    if not os.path.isfile(fn):
7        print("Excel File Not Found:{}".format(fn))
8        return []
9    if len(titles) <= 0:
10        print("Titles Empty")
11        return
12    wb = openpyxl.load_workbook(fn)
13    print("Excel Sheets List: {}".format(wb.sheetnames))
14    if not sn:
15        sheet = wb.active
16    else:
17        if sn not in wb.sheetnames:
18            print("Error Sheet Name:{}".format(sn))
19            return []
20        sheet = wb[sn]
21    print("Sheet Name is 【{}】, Max Column Num: {}".format(sheet.title, sheet.max_column))
22    # 删掉无用的空白列或者空白格,减少内存遍历(Ctrl + shift + →【箭头】 删掉)
23    print("Max Row Num: {}".format(sheet.max_row))
24    col_num = sheet.max_column + 1
25    for i, title in enumerate(titles):
26        cell = sheet.cell(1, col_num + i)  # 增加表头
27        cell.value = title
28    for rn, row in enumerate(rows):
29        row_index = rn + 2
30        for cn, val in enumerate(row):
31            cell = sheet.cell(row_index, cn + col_num)
32            cell.value = val
33    wb.save(fn)
34    return

`

3. Excel 操作案例

  • 案例场景

将2个表格的某一列进行匹配,最后将表2的数据加到表1的后面

1d2049444ea8a2d689b378337b0caeb4.png
案例表1
faa26e5d1be1b1133bdb908556835740.png
案例表2
1385e91575c347e86696ddb41511dde0.png
匹配后的结果
  • 实现方法

 1def match(t1_fn, t2_fn, attr, t2_titles, t1_sn=None, t2_sn=None):
2    """ 3    获取t1 t2的数据并根据 attr 来匹配2个表格该字段相同的数据。 4    最终将 表2的 t2_titles 列表对应的数据添加到 表1 后面 5    :param t1_fn: 6    :param t2_fn: 7    :param attr: 8    :param t2_titles:  表格2 添加到 t1 后面的字段列表(按照顺序) 9    :param t1_sn10    :param t2_sn11    :return:12    """
13    result = []
14    t1_data = read_excel(t1_fn, sn=t1_sn)
15    t2_data = read_excel(t2_fn, sn=t2_sn)
16    if len(t1_data) <= 0 or len(t2_data) <= 0:
17        print("Empty Sheet")
18        return result
19    if len(t2_titles) <= 0:
20        print("Please Input Titles with Table-2")
21        return result
22    t1_map = {}
23    for num, each in enumerate(t1_data):
24        if attr not in each:
25            print("Attribute {} not Found in the {} row of Table-1".format(attr, num + 1))
26            return result
27        val = each[attr]
28        t1_map.setdefault(val, [])
29        t1_map[val].append(num + 1)  # 以匹配的属性值为key,行数为 value,可能有多行
30
31    new_rows = {}  # 存储t1行号需要增加的值
32    max_row_num = len(t1_data)  # t1最大的行号
33    for num, each in enumerate(t2_data):
34        if attr not in each:
35            print("Attribute {} not Found in the {} row of Table-2".format(attr, num + 1))
36            return result
37        val = each[attr]
38        if val not in t1_map:
39            print("The Match Value {} not Found in Table-1".format(val))
40            continue
41        new_row_data = [each.get(t, '') for t in t2_titles]  # 字段不存在使用空字符串
42        for row_num in t1_map[val]:
43            new_rows[row_num] = new_row_data  # 根据行号存储,第1行就是1,第2行就是2
44    for row_num in range(1, max_row_num):
45        if row_num not in new_rows:
46            result.append([""] * len(t2_titles))  # 没匹配到的以空替换
47        else:
48            result.append(new_rows[row_num])
49    return result
50
51def test_match():
52    t1_file_path = "D:\\table-1.xlsx"
53    t2_file_path = "D:\\table-2.xlsx"
54    titles = ["净利润", "订单日期"]
55    rows = match(t1_file_path, t2_file_path, u"订单号", titles, "Sheet4", "Sheet")
56    append_excel(t1_file_path, titles, rows, "Sheet4")

4. 关于 python 版本说明

  • 本文代码 Python 版本

python3.8

  • 如何支持 python2.7

A. 将 print 函数更换成关键字 print

1# print("Max Row Num: {}".format(sheet.max_row))
2print "Max Row Num: {}".format(sheet.max_row)

B. 支持中文操作需要增加以下代码

1reload(sys)
2sys.setdefaultencoding("utf-8")

C. 支持中文匹配需要将所有字符串变成 unicode 字符串

1cols_val[col_num] = unicode(cell.value)
2titles = [u"净利润", u"订单日期"]

本文完。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值