用Python 处理EXCEL表格数据

场景

我本身使用Excel不怎么熟练, 但家人需要经常处理Excel, 就写了一些Python脚本协助处理,

我把其中公用的部分抽了出来, 放在下边, 有用到的可以看看

还有一些js写的处理Excel的小工具, 可直接在浏览器端执行, 没有数据上传可放心使用

功能代码:

引入openpyxl库

注意, 使用了 openpyxl 库, 只识别最新的 'xlsx' 后缀的Excel, 不识别老的xls后缀的文件

from openpyxl import load_workbook
from openpyxl import Workbook

# 下边的代码片段都需要这两个 import

界面GUI, 选择文件和sheet

windows批处理脚本, 用来打开操作菜单

# start.bat
@echo off
chcp 65001
python ./menu.py

 菜单界面

import tkinter as tk
import subprocess

# 创建主窗口
root = tk.Tk()
root.title("功能列表")

# 设置窗口大小
root.geometry("512x256")


btn1 = tk.Button(root, text="考勤", command=lambda: subprocess.run(['python', './1kaoqin.py']))
btn1.grid(row=0, column=0, sticky=tk.W, padx=10, pady=5)

btn2 = tk.Button(root, text="系数分", command=lambda: subprocess.run(['python', './2xishufen.py']))
btn2.grid(row=1, column=0, sticky=tk.W, padx=10, pady=5)

grid布局, 选择文件, sheet, 保存全局变量 

import tkinter as tk
from tkinter import filedialog
from tkinter import ttk

#按钮回调, 弹窗让用户选择文件 
def open_file():
    # 使用filedialog打开文件
    filepath = filedialog.askopenfilename(
        title="选择Excel文件",
        filetypes=(("Excel files", "*.xlsx"), ("all files", "*.*"))
    )
    if not filepath:
        return
    
    var_file_path.set(filepath) # 文件路径, 保存到全局变量中

    # 获取所有sheet的名字, 让用户选择
    wb = load_workbook(filepath)
    sheet_names = wb.sheetnames
    for i,v in enumerate(sheet_names):
        var_sheetname = tk.StringVar(root) # 创建一个StringVar变量来跟踪下拉菜单的当前选择
        checkbox = tk.Checkbutton(root, text=v, variable=var_sheetname, onvalue=v, offvalue='')
        checkbox.grid(row=1, column=i+1)
        checkbox_vars.append(var_sheetname)

    
#选择结果目录
def select_directory():
    directory_path = filedialog.askdirectory()
    var_target_dir.set(directory_path)
    label = tk.Label(root, text=directory_path)
    label.grid(row=3, column=1, sticky=tk.W, padx=10, pady=5)
    

def cal():
    #读取用户选择的文件和sheet名
    filepath = var_file_path.get()
    target_dir = var_target_dir.get()
    target_file = target_dir +'/(新建)季度考勤汇总.xlsx'

    # 读取数据处理的代码, 省略...

    # 数据处理完毕, 在界面上显示"结束"来提醒用户
    label = tk.Label(root, text="结束")# 创建一个标签控件
    label.grid(row=4, column=1, sticky=tk.W, padx=10, pady=5) 


#####################################开始绘制图形界面################################
# 创建主窗口
root = tk.Tk()
root.title("季度考勤汇总(注意:Excel文件后缀需要是‘xlsx’)")

# 设置窗口大小
root.geometry("512x256")

#数据文件
var_file_path = tk.StringVar(root) #定义全局变量, 存放用户选择的文件
btn_src = tk.Button(root, text="选择文件", command=open_file)
btn_src.grid(row=0, column=0, sticky=tk.W, padx=10, pady=5)

#选择sheet
checkbox_vars = [] #存放用户选择的多个sheet
label_src = tk.Label(root, text="选择Sheet名:")# 创建一个标签控件
label_src.grid(row=1, column=0, sticky=tk.E, padx=10, pady=5) # 使用grid布局管理器,并设置sticky参数为W,使控件靠左显示, padx, pady: 设置间距

#选择生成的文件保存的目录
var_target_dir = tk.StringVar(root)
button = tk.Button(root, text="结果输出目录", command=select_directory)
button.grid(row=3, column=0, sticky=tk.W, padx=10, pady=5)

#开始计算按钮
btn_ok = tk.Button(root, text="开始计算", command=cal)
btn_ok.grid(row=4, column=0, sticky=tk.W, padx=10, pady=5)



# 运行主循环
root.mainloop()

 

读取文件数据, 指定起始行和列

#读取文件数据
def read_file_data(filename, sheet_name, start_row=1, start_col=1):
    file_data = [];
    wb = load_workbook(filename=filename, data_only=True) #公式变为数值

    #读取财务sheet的所有数据
    ws = wb[sheet_name]
    for row in ws.iter_rows(min_row=start_row, min_col=start_col):
        row_data = [];
        #print(row)
        for cell in row:
            row_data.append(cell.value)                
        file_data.append(row_data)
    
    return file_data;

保存数据到Excel

#保存新文件, 1个sheet
# file_data: 二维数组
def save_new_file(file_data, filepath):
    # 创建一个工作簿对象
    wb = Workbook()
    sheet = wb.active
    for row in file_data:
        sheet.append(row)

    # 保存工作簿到文件
    wb.save(filepath)
    return True;


#保存新文件, 多个sheet 
# file_data 是三维数组
def save_file(file_data, filepath):
    wb = Workbook()
    for sheet_name in file_data:
        wb.create_sheet(sheet_name)
        for row in file_data[sheet_name]:
            wb[sheet_name].append(row)

    wb.remove(wb['Sheet'])
    wb.save(filepath)
    return True;

 判断数组中某个下标是否存在(不是每一行的每一列都有数据)

#判断数组中某个下标是否存在
def list_exists(my_list, index, default=0):
    try:
        # 尝试访问下标
        tmp = my_list[index]
    except IndexError:
        # 如果引发IndexError,说明下标不存在
        return default
    else:
        # 如果没有异常,说明下标存在
        return tmp

#判断字典中某个下标是否存在    
def dic_exists(dic, k, default):
    if k in dic:
        return dic[k]
    else:
        return default

#创建指定长度的数组 (用于行数据对齐, 否则合并文件的时候, 数据会错位)
def create_arr(len, val=0):
    return [val] * len

转为浮点数(有的单元格没有值, 读出来的数据可能是 None)

#转为浮点数    
def change_float(data, default=0):
    try:
        data = float(data)
        return data
    except ValueError:
        return default
    except TypeError:
        return default

 数组转为对象(有些Excel中存放的是权重信息, 为了方便程序使用, 将读出来的list改为dic)

#数组合并为对象
def combin_arr_to_obj(arr_key, arr_value):
    obj = {}
    for index,value in enumerate(arr_key):
        obj[value] = arr_value[index];
    return obj

#将一维数组转为对象
def arr_column(arr, f1, f2):
    rs = {}
    for row in arr:
        rs[row[f1]] = row[f2]
    return rs

合并两个文件 (两个Excel中都存在一列,比如工号, 按工号将两个Excel合并起来)

# 合并两个文件
# data1:文件1的数据, field1:字段编号(a/b/c..)
def merge_file_by_field(data1, field1, data2, field2):
    map = {}
    for row in data2:
        v = row[field2]
        map[v] = row

    length = len(data2[0])
    empty_list = [''] * length
    
    rs = []
    for row in data1:
        v = row[field1]
        #echo(v)
        if v in map:
            row.extend(map[v])
            rs.append(row)
        else:
            row.extend(empty_list)
            rs.append(row)
    return rs

抽出某几列(有时候删列比较麻烦, 可以输入a,b,c...等列编号, 抽取出需要的列生成新文件)

#抽出某几列
def pick_cols(data, arr_idx):
    rs = [];
    for row in data:
        tmp = []
        for id in arr_idx:
            tmp.append[row[id]]
        rs.append(tmp)
    return rs

分组相加 (比如表格中有同一个人的不同项目得分, 要把这个人的得分相加汇总)

def group_add(data, f1, f2):
    rs = {}
    first_row = data.pop(0) #默认第一行是标题
    title= [first_row[f1], first_row[f2]]
    
    for row in data:
        v1 = row[f1]
        v2 = float(row[f2])
        if v1 in rs:
            rs[v1] = rs[v1] + v2
        else:
            rs[v1] = v2
    
    file_data = []
    file_data.append(title)
    for k in rs:
        file_data.append([k, rs[k]])
    
    return file_data

统计一维数组中元素出现的次数 (统计某列中相同的数据出现的次数)

# 计算出现次数
def group_count(data, f1, f2, new_field='出现次数'):
    group = {}

    # 默认第一行是标题
    first_row = data.pop(0)
    title= [first_row[f1], first_row[f2], new_field]
    
    #按照f1分组
    for row in data:
        v1 = row[f1]
        v2 = row[f2].strip()
        if v1 not in group:
            group[v1] = []
        group[v1].append(v2)
        
    #计算出现次数
    count = {}
    for k in group:
        count[k] = arr_item_count(group[k])

    #整理最终格式
    file_data = []
    file_data.append(title) #标题
    for k in count:
        for k1 in count[k]:
            file_data.append([k, k1, count[k][k1]]) #拆分成行
    
    return file_data

#统计一维数组中元素出现的次数
def arr_item_count(arr):
    count = {}
    for v in arr:
        if v in count:
            count[v] = count[v] + 1
        else:
            count[v] = 1
    return count

 用行中的某一列数据作为字典数据的键 (可用于合并两个文件)

# 用行中的某一列的值作为key
# arr: 所有行数据 f: 列编码 keep: f列的数据是否还保存在后边的数组中 
def arr_map(arr, f, keep=False):
    rs = {}
    if keep:
        for row in arr:
            rs[row[f]] = row
    else:
        for row in arr:
            k = row.pop(f)
            rs[k] = row
    return rs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值