背景:

最近工作中需要核对客户的历史数据,

接近400个产品,需要核对的列有15列,行数有8000+行

肉眼核对简直要吐血

心想着反正在学python呢

人生苦短

何不用python写个脚本

帮助我核对

我省出时间来做些更有意义的事情呢

前提:

我需要核对的两份Excel有以下特点:

  1. 有共同的主键
  2. 两份Excel的结构不尽相同,仅需要核对源文件47列中的15列,这些列在目标文件中都能找到

主要思路:

将两个文件的主键作为键,将要核对的列作为值,保存到字典中

然后再进行比较

实现代码:

import xlrd
import xlwt
import time origin_dict = {} # 初始化,用于保存源文件{key(主键):value(需要核对的列值)}
target_dict = {} # 初始化,用于保存目标文件{key(主键):value(需要核对的列值)} # 放在函数外部声明 会报错 还不晓得原因
# success = 0
# fail = 0 def compare_excel(ori_path,tar_path,col_ori,col_tar):
'''
ori_path:用于存放源文件
tar_path:用于存放目标文件
col_ori:源文件中需要比较的列
col_tar:目标文件中需要比较的列
'''
success = 0 # 核对无差异的个数
fail = 0 # 核对结果有差异的个数
row_res = 0 #要写入的文件的行 # 分别打开源文件与目标文件
wb_ori = xlrd.open_workbook(ori_path)
wb_tar = xlrd.open_workbook(tar_path)
# 新建一个excel,用于存放核对结果
wb_res = xlwt.Workbook() # 分别获取源文件与目标文件的sheet
sheet_ori = wb_ori.sheet_by_index(0)
sheet_tar = wb_tar.sheet_by_index(0)
# 新建一名称为result的sheet页,用于存放核对具体结果
sheet_res = wb_res.add_sheet('result') # 获取源文件中由主键、需核对列组成的键值对,放入字典中
for row_ori in range(1,sheet_ori.nrows):
cell_ori_key = sheet_ori.cell_value(row_ori,0) #因我的源文件的主键位于第0列,故该列未参数化,大家可以视自己实际情况进行优化
cell_ori_value = sheet_ori.cell_value(row_ori,col_ori)
origin_dict[cell_ori_key] = cell_ori_value
# print('源文件获取成功')
# print('源文件如下:%s' % origin_dict) # 获取目标文件中由主键、待核对列组成的键值对,放入字典中
for row_tar in range(1,sheet_tar.nrows):
cell_tar_key = sheet_tar.cell_value(row_tar,0)
cell_tar_value = sheet_tar.cell_value(row_tar,col_tar)
target_dict[cell_tar_key] = cell_tar_value
# print('目标文件获取成功')
# print('目标文件如下:%s' % target_dict) # 核对逻辑
try:
for i in origin_dict.keys(): # 获取源文件字典的键
if target_dict.get(i) == origin_dict.get(i): # 对比两个字典中相同键的值
success += 1 # 值相等,则无差异数+1
sheet_res.write(row_res+1,0,i) # 将键写入结果文件的第0列
sheet_res.write(row_res+1,1,'你俩长一样') #将核对无差异结果写入结果文件的第1列
row_res += 1 # 结果文件行数+1
print('金融产品 %s 核对无差异'% i)
else:
fail +=1 # 值不相等,则有差异数+1
sheet_res.write(row_res+1,0,i)
sheet_res.write(row_res+1,1,'核对有差异:源文件的值为:%s,目标文件的值为:%s' % (origin_dict.get(i),target_dict.get(i))) # #将核对有差异结果写入结果文件的第1列
row_res += 1 # 结果文件行数+1
print('金融产品 %s 核对有差异:源文件的值为:%s,目标文件的值为:%s' % (i,origin_dict.get(i),target_dict.get(i)))
wb_res.save('result.xlsx') # 保存结果文件
print(time.strftime('%Y-%m-%d %H-%M-%S',time.localtime())+'核对完成,共核对 %d 条,其中无差异 %d 条, 有差异 %d条' % (len(origin_dict),success,fail))
except Exception as error:
print(str(error)) compare_excel('C111111.xlsx','O222222.xlsx',3,2) # 核对源文件第4列,目标文件第3列

后续:

代码还有很多优化的空间:

比如说源文件中有的键目标文件中没有,如何提示?

比如说能否一次比较多个列的值

比如扩展成双主键/多主键,该如何比对?

如果你有方法或思路,可以跟我这个小白一起交流

*************************************************************************************************************************************************************************************************

上面说的优化空间,今天解决了多主键的问题

多主键问题解决的关键

是把多主键拼接成一个字符串,然后再作为字典的键

进而比较其值

优化的点还包括:

将核对结果追加写入源文件中

而非新建一个Excel

具体代码如下:

import xlrd
import xlwt
import xlutils
import time
from datetime import datetime
from xlrd import xldate_as_tuple
from xlutils import copy dict_ori = {} # 初始化,用于保存源文件{key(主键):value(需要核对的列值)}
dict_tar = {} # 初始化,用于保存目标文件{key(主键):value(需要核对的列值)} def Excel_Compare(ori_path,tar_path,sheet_index_ori,col_ori,col_tar):
'''
ori_path:源文件地址
tar_path:目标文件地址
sheet_index_ori:源文件中待核对的sheet的索引
col_ori:源文件中待核对的列
col_tar:目标文件中待核对的列
'''
success = 0
fail = 0
space = 0 # 空行个数
row_res = 0
# 分别打开源文件与目标文件
wb_ori = xlrd.open_workbook(ori_path,'w+')
wb_tar = xlrd.open_workbook(tar_path)
# 新建一个excel,用于存放核对结果
# wb_res = xlwt.Workbook()
wb_res = copy.copy(wb_ori) # 在源文件中追加写入 # 分别获取源文件与目标文件的sheet
sheet_ori = wb_ori.sheet_by_index(sheet_index_ori)
sheet_tar = wb_tar.sheet_by_index(0)
# 新建一名称为result的sheet页,用于存放核对具体结果
# sheet_res = wb_res.add_sheet('result')
sheet_res = wb_res.get_sheet(sheet_index_ori) # 在原sheet中追加写入 # 获取源文件中由主键、需核对列组成的键值对,放入字典中
for row_ori in range(1,sheet_ori.nrows):
product_id_ori = sheet_ori.cell_value(row_ori,1)
# print(product_id_ori)
product_name_ori = sheet_ori.cell_value(row_ori,4).split('-')[1] # 源文件中账套名称为:XX-xx形式,因核对时只需要后面的xx,故需要做一下处理
# product_name_ori_ctype = sheet_ori.cell(row_ori,4).ctype
# print(product_name_ori)
# print(product_name_ori_ctype)
# 以下3行代码将从Excel读出的日期数据进行转化并格式化
date_ori_1 = sheet_ori.cell_value(row_ori,11)
date_ori_2 = datetime(*xldate_as_tuple(date_ori_1,0))
date_ori = date_ori_2.strftime('%Y-%m-%d')
# print(date_ori)
key_ori_list = [product_id_ori,product_name_ori,date_ori]
key_ori = '--'.join(key_ori_list) # 关键点,将多主键拼接成字符串
# print(key_ori)
income_ori_1 = sheet_ori.cell_value(row_ori,col_ori)
income_ori = round(float(income_ori_1),2) # 读出来的数据为str类型,需转化为float类型,方便进行处理,注意源文件中不能有空行
# dict_ori = {key_ori:income_ori} # 该方式最终仅保存一次,不是想要的结果
dict_ori[key_ori] = income_ori # 将提取出的关键信息追加保存为字典格式
# print("源文件数据获取成功")
# print(dict_ori) # 获取源文件中由主键、需核对列组成的键值对,放入字典中
for row_tar in range(1,sheet_tar.nrows):
product_id_tar = sheet_tar.cell_value(row_tar,1)
product_name_tar = sheet_tar.cell_value(row_tar,5)
date_tar_1 = sheet_tar.cell_value(row_tar,15)
key_tar_list = [product_id_tar,product_name_tar,date_tar_1]
key_tar = '--'.join(key_tar_list)
income_tar_1 = sheet_tar.cell_value(row_tar,col_tar)
income_tar = round(float(income_tar_1),2)
# income_tar_ctype = sheet_tar.cell(row_tar,19).ctype
# print(income_tar_ctype)
# dict_tar = {key_tar:income_tar}
dict_tar[key_tar] = income_tar
# print("目标文件数据获取成功")
# print(dict_tar) # 核对逻辑
try:
for i in dict_ori.keys():
# print(type(dict_tar.get(i)))
# income_ori_float = float(dict_ori.get(i))
# print(i)
if dict_tar.get(i) == dict_ori.get(i): # 无差异的情况
success += 1
product_id_res = i.split('--')[0]
product_name_res = i.split('--')[1]
date_res = i.split('--')[2]
sheet_res.write(row_res+1,20,product_id_res)
sheet_res.write(row_res+1,21,product_name_res)
sheet_res.write(row_res+1,22,date_res)
sheet_res.write(row_res+1,23,'核对无误')
row_res += 1
print('金融产品:%s,账套:%s,日期:%s的收益数据核对无差异' % (product_id_res,product_name_res,date_res))
elif dict_ori.get(i) == 0.00 and dict_tar.get(i) == None: #有空值的情况
space += 1
product_id_res = i.split('--')[0]
product_name_res = i.split('--')[1]
date_res = i.split('--')[2]
sheet_res.write(row_res+1,20,product_id_res)
sheet_res.write(row_res+1,21,product_name_res)
sheet_res.write(row_res+1,22,date_res)
sheet_res.write(row_res+1,23,'空值')
row_res += 1
print('金融产品:%s,账套:%s,日期:%s的数据为空' % (product_id_res,product_name_res,date_res))
else: # 核对有差异的情况
fail += 1
product_id_res = i.split('--')[0]
product_name_res = i.split('--')[1]
date_res = i.split('--')[2]
sheet_res.write(row_res+1,20,product_id_res)
sheet_res.write(row_res+1,21,product_name_res)
sheet_res.write(row_res+1,22,date_res)
sheet_res.write(row_res+1,23,'数值有差异,源文件收益为:%s,目标文件的收益为:%s'%(dict_ori.get(i),dict_tar.get(i)))
row_res += 1
print('金融产品:%s,账套:%s,日期:%s 的收益数据核对有差异,源文件的收益为%s,目标文件的收益为%s'%(product_id_res,product_name_res,date_res,dict_ori.get(i),dict_tar.get(i)))
except Exception as error:
print(str(error))
wb_res.save(ori_path) # 保存源文件
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'核对完成,共核对%d条,其中,无差异%d条,有差异%d条'%(success+fail,success,fail)) Excel_Compare('CashSequence111.xlsx','CashSequence222.xlsx',3,16,19)

Python3.7 比较两个Excel文件指定列的值的异同,并将核对结果写入Excel中(含升级版本)的更多相关文章

  1. PHP导出excel文件,第二步先实现自写二维数组加入模板excel文件后导出

    今天主要研究数据加入EXCEL并导出的问题,先不从数据库提取数据导出,自己先写一个二维数组,然后遍历二维数组写入excel模板中导出,首先根据模板excel的内容书写对应的二维数组 $arr=arra ...

  2. 定制Dynamics CRM标准导出功能:不能导出指定列的值

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复239或者20161203可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  3. 自动化可用到的Java读取Excel文件指定的行列数据

    前言 在做接口自动化的时候,通常会遇到数据取用及存放的问题,一般有三种方式可选择 1.数据库存取 2.表格存取 3.项目配置文件存取 这里仅展示下第二种方式表格取数据的 示例 import org.a ...

  4. pandas 读取excel的指定列

    不管对于read_csv还是read_excel,现在都有: usecols : int or list, default None If None then parse all columns, I ...

  5. jqgrid获取选中行指定列的值

    部分js如下: var id = $("#grid-table").jqGrid('getGridParam','selrow');//根据点击行获得点击行的id(id为jsonR ...

  6. Excel文件读写操作1(xls)

    一.Python-Excel常用的库:xlrd(read).xlwt(write).xlutils.openpyxl 1.xlrd  读取Excel文件,支持 .xls 和 .xlsx 格式. 2.x ...

  7. python3:xlrd、xlwt、xlutils处理excel文件

    1.xlrd读取excel 请参考上篇博客https://www.cnblogs.com/shapeL/p/9075843.html 2.xlwt生成excel 安装下载:pip install xl ...

  8. Python使用openpyxl读写excel文件

    Python使用openpyxl读写excel文件 这是一个第三方库,可以处理xlsx格式的Excel文件.pip install openpyxl安装.如果使用Aanconda,应该自带了. 读取E ...

  9. Python使用读写excel文件

    Python使用openpyxl读写excel文件 这是一个第三方库,可以处理xlsx格式的Excel文件.pip install openpyxl安装.如果使用Aanconda,应该自带了. 读取E ...

随机推荐

  1. 【Java 基础】Java Map中的Value值如何做到可以为任意类型的值

    Occasionally the average developer runs into a situation where he has to map values of arbitrary typ ...

  2. 使用.NET 6开发TodoList应用(3)——引入第三方日志库

    需求 在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选 ...

  3. 用 Go 实现一个 LRU cache

    前言 早在几年前写过关于 LRU cache 的文章: https://crossoverjie.top/2018/04/07/algorithm/LRU-cache/ 当时是用 Java 实现的,最 ...

  4. C# 脚本

    有些情况下,需要在程序运行期间动态执行C#代码,比如,将某些经常改变的算法保存在配置文件中,在运行期间从配置文件中读取并执行运算.这时可以使用C#脚本来完成这些工作. 使用C#脚本需要引用库Micro ...

  5. odoo14 继承改写原生模块的视图优先级问题

    需要类似这样的改写方法: 1.更改id名,方便下方引用!!! 2.使用原生模块的"model"!!! 3.添加字段priority!!!(越小越大) 4.form 和 kanban ...

  6. myeclipse 给类与方法添加注解模板方法

    myeclipse 给类与方法添加注解模板方法 步骤1:点击myeclipse 界面的[Window]菜单 步骤2:点击下拉菜单的[Preferences]选项 步骤3:展开左边菜单的[java]选项 ...

  7. IDEA常用设置及插件

    设置 1.设置打开后不直接进入项目 IDEA默认打开时会直接进入上次打开的目录,有的时候加载很长时间,但这个时候可能我们并不是要打开这个项目,这里有一个设置,在如图的位置,去掉勾选,即可设置打开后不直 ...

  8. SpringBoot整合knife4j框架(可生成离线接口文档),并设置接口请求头token默认值

    功能和swagger类似 官网地址:https://doc.xiaominfo.com/knife4j/ 这个框架可以设置返回字段的描述 引入依赖 <dependency> <gro ...

  9. MacOS设置终端代理

    前言 国内的开发者或多或少都会因为网络而烦恼,因为一些特殊原因有时候网络不好的时候需要使用代理才能完成对应的操作.原来我一直都是使用斐讯路由器然后刷了梅林的固件,直接在路由器层面设置转发代理,把一些国 ...

  10. 一个在线MP4提取mp3的网站

    网址 https://airmore.cn/extract-audio-online