年底了,又到了算阿里云费用的时候了
1、导出阿里云的实例费用账单
2、请保证您的当前目录只有一个csv文件
3、目前只支持能分配财务单元的费用统计
4、执行本脚本请传入参数(参数是财务单元)
5、执行结果如下,只有这几列
‘账期’, ‘财务单元’,‘产品明细Code’, ‘产品明细’, ‘消费类型’, ‘账单类型’, ‘实例ID’, ‘实例昵称’, ‘资源组’, ‘实例配置’, ‘实例规格’, ‘私网IP’,
‘应付金额’
# -*- coding: UTF-8 -*-
import csv
import sys,os
from openpyxl import Workbook
from openpyxl.styles import Alignment
from openpyxl.styles import Font
#不支持oss waf ddos 快照统计
class ExcelWrite():
def __init__(self,data,result_file_name,keys):
self.__data = data
self.__titile = self.__data[0]
self.__index_1 = self.__titile.index('账期')# 确定每一列的索引
self.__index_2 = self.__titile.index('财务单元')
self.__index_3 = self.__titile.index('产品明细Code')
self.__index_4 = self.__titile.index('产品明细')
self.__index_5 = self.__titile.index('消费类型')
self.__index_6 = self.__titile.index('账单类型')
self.__index_7 = self.__titile.index('实例ID')
self.__index_8 = self.__titile.index('实例昵称')
self.__index_9 = self.__titile.index('资源组')
self.__index_10 = self.__titile.index('实例配置')
self.__index_11 = self.__titile.index('实例规格')
self.__index_12 = self.__titile.index('私网IP')
self.__index_13 = self.__titile.index('应付金额')
self.__result_file_name = result_file_name
self.__keys = keys #需要查找的财务单元
self.__wb = Workbook()
self.__sheet_pay = self.__wb.active
self.__sheet_pay.title = u'总费用'
#根据产品的code过滤每一种产品 并相应放到__product_data 里面
self.__product = [['ecs','vm'],['rds','rords','bards'],['slb','slbpre'],['yundisk'],['prepaid_kvstore'],['badds'],['dtspre','dtspost'],['bandwidth_package','nat_gw','cbwp'],['ipv6bandwidth','ipv6gateway'],
['elasticsearch','elasticsearchpre'],['cdn'],['mssp'],['eip'],['eci_betav1'],['ons','alikafka_pre'],['ri_pre'],['hbrpost'],['hdm_pre'],['opensearch_post'],['ri'],['mts'],['kms'],['cdi'],['ddos_fl_pre'],['sls'],['live'],['dmsenterprise'],
['cbs_post'],['sas'],['pts','ptsbag'],['arms','arms_app_post'],['1'],['cas'],['cms_post'],['pvtzpost'],['alidns_pre'],['alimail'],['smartag']]
#根据产品生成数据
self.__product_data = [{'ecs':[]}, {'rds':[]}, {'slb':[]}, {'yundisk':[]},
{'prepaid_kvstore':[]}, {'badds':[]}, {'dtspre':[]},
{'bandwidth_package':[]}, {'ipv6bandwidth':[]},
{'elasticsearch':[]}, {'cdn':[]}, {'mssp':[]}, {'eip':[]}, {'eci_betav1':[]},
{'ons':[]}, {'ri_pre':[]}, {'hbrpost':[]}, {'hdm_pre':[]}, {'opensearch_post':[]}, {'ri':[]},
{'mts':[]}, {'kms':[]}, {'cdi':[]}, {'ddos_fl_pre':[]}, {'sls':[]}, {'live':[]}, {'dmsenterprise':[]},
{'cbs_post':[]}, {'sas':[]}, {'pts':[]}, {'arms':[]}, {'1':[]},
{'cas':[]}, {'cms_post':[]}, {'pvtzpost':[]}, {'alidns_pre':[]}, {'alimail':[]}, {'smartag':[]}]
#根据产品生成sheet
self.__product_sheet = [{'ecs':''}, {'rds':''}, {'slb':''}, {'yundisk':''},
{'prepaid_kvstore':''}, {'badds':''}, {'dtspre':''},
{'bandwidth_package':''}, {'ipv6bandwidth':''},
{'elasticsearch':''}, {'cdn':''}, {'mssp':''}, {'eip':''}, {'eci_betav1':''},
{'ons':''}, {'ri_pre':''}, {'hbrpost':''}, {'hdm_pre':''}, {'opensearch_post':''}, {'ri':''},
{'mts':''}, {'kms':''}, {'cdi':''}, {'ddos_fl_pre':''}, {'sls':''}, {'live':''}, {'dmsenterprise':''},
{'cbs_post':''}, {'sas':''}, {'pts':''}, {'arms':''}, {'1':''},
{'cas':''}, {'cms_post':''}, {'pvtzpost':''}, {'alidns_pre':''}, {'alimail':''}, {'smartag':''}]
#根据产品记录总费用
self.__all_pay = [{'ecs':[]}, {'rds':[]}, {'slb':[]}, {'yundisk':[]},
{'prepaid_kvstore':[]}, {'badds':[]}, {'dtspre':[]},
{'bandwidth_package':[]}, {'ipv6bandwidth':[]},
{'elasticsearch':[]}, {'cdn':[]}, {'mssp':[]}, {'eip':[]}, {'eci_betav1':[]},
{'ons':[]}, {'ri_pre':[]}, {'hbrpost':[]}, {'hdm_pre':[]}, {'opensearch_post':[]}, {'ri':[]},
{'mts':[]}, {'kms':[]}, {'cdi':[]}, {'ddos_fl_pre':[]}, {'sls':[]}, {'live':[]}, {'dmsenterprise':[]},
{'cbs_post':[]}, {'sas':[]}, {'pts':[]}, {'arms':[]}, {'1':[]},
{'cas':[]}, {'cms_post':[]}, {'pvtzpost':[]}, {'alidns_pre':[]}, {'alimail':[]}, {'smartag':[]}]
self.remain_data = []
self.__align = Alignment(horizontal='right')#样式右对齐
self.__align_center = Alignment(horizontal='center') # 样式右对齐
self.__font = Font(u'宋体', size=11, bold=True, color='FF0000')#字体红色
#生成账单结果
def create_file(self):
self.remain_data=[]#无法确定费用的数据
for item in self.__data[1:]:
if item[ self.__index_2] in self.__keys:#根据财务单元过滤
for search_key in self.__product:
if item[self.__index_3] in search_key:
for product_data in self.__product_data:
if search_key[0] == list(product_data.keys())[0]:
product_data[search_key[0]].append(item)
else:
self.remain_data.append(item)
for product_data in self.__product_data:
if len(list(product_data.values())[0]) != 0:
for product_sheet in self.__product_sheet:
if list(product_data.keys())[0] == list(product_sheet.keys())[0]:
product_sheet[list(product_sheet.keys())[0]] = self.__wb.create_sheet(list(product_data.keys())[0].upper())
data_ecs_handle = self.__handle_data(product_data) #ecs
self.create_sheet(data_ecs_handle,list(product_data.keys())[0])
else:
#self.__sheet_ecs.cell(row=1, column=1, value='空')
print('THIS {} is empty'.format(list(product_data.keys())[0]))
#self.__create_sum_sheet()
self.__wb.save(self.__result_file_name)
self.__create_remain_csv()
#创建 sheet
def create_sheet(self,data_ecs_handle,tag):#obj是哪一个sheet tag也是表明哪一种云服务
ecs_title = ['账期','财务单元','产品明细Code','产品明细','消费类型','账单类型','实例ID','实例昵称','资源组','实例配置','实例规格','私网IP','应付金额']
col_ecs = 1 #列
row_ecs =1 #行
for product_sheet in self.__product_sheet:
if tag == list(product_sheet.keys())[0]:
obj =product_sheet[tag]
for j in ecs_title:
obj.cell(row=row_ecs,column=col_ecs,value=j)
col_ecs+=1
row_ecs+=1
time_ecs = data_ecs_handle[0][self.__index_1] # 设置初始账期,用来根据账期不同合并单元格,
row_ecs_first = 2 #统计每月账单的开始行,用来算当前月账期的标记
for ecs_item_row in data_ecs_handle:
col_ecs = 1
if ecs_item_row[self.__index_1] != time_ecs:#账期不同时开始合并单元格 计算这个月的费用
obj.merge_cells(start_row=row_ecs, start_column=1, end_row=row_ecs, end_column=12)
obj.cell(row=row_ecs, column=1, value=str(time_ecs)+'月份的费用为')
obj.cell(row=row_ecs, column=1).font = self.__font
obj.cell(row=row_ecs, column=1).alignment = self.__align
sum = 0
for i in range(row_ecs_first, row_ecs):
sum += obj['M' + str(i)].value
sum = round(sum)
print('{}{}月的费用为{}'.format(tag,time_ecs,sum))
obj.cell(row=row_ecs, column=13, value=sum)
obj.cell(row=row_ecs, column=13).font = self.__font
for item in self.__all_pay:
if list(item.keys())[0] == tag:
item[tag].append({time_ecs:sum})
row_ecs_first = row_ecs + 1
time_ecs = ecs_item_row[self.__index_1]
row_ecs += 1
for ecs_item_col in ecs_item_row:#月份相同时 依次填充每一行里面的每一列
obj.cell(row=row_ecs, column=col_ecs, value=ecs_item_col)
col_ecs+=1
row_ecs+=1
obj.merge_cells(start_row=row_ecs, start_column=1, end_row=row_ecs, end_column=12)
obj.cell(row=row_ecs, column=1, value=str(time_ecs) + '月份的费用为')
obj.cell(row=row_ecs, column=1).font = self.__font
obj.cell(row=row_ecs, column=1).alignment = self.__align
sum = 0
for i in range(row_ecs_first, row_ecs):
sum += obj['M' + str(i)].value
sum = round(sum)
print('{} {}月的费用为{}'.format(tag, time_ecs, sum))
obj.cell(row=row_ecs, column=13, value=sum)
obj.cell(row=row_ecs, column=13).font = self.__font
for item in self.__all_pay:
if list(item.keys())[0] == tag:
item[tag].append({time_ecs: sum})
print('the sum pay is {}'.format(self.__all_pay))
def __create_sum_sheet(self):
row = 2 #行
row_for_sum = 3 #填写行的总计 从第三行开始算
self.__sheet_pay.cell(row=row, column=1, value='账期')
col_for_row1 = 2 #第一行的列数 从第二列开始算
for pay in self.__all_pay:
for key,value in list(pay.items()):
if len(value) != 0:#标题
self.__sheet_pay.cell(row=2, column=col_for_row1, value=key)
#每一种云服务列相同,行都是从第二行开始
row = 3
for item in value:
for key1,value1 in list(item.items()):
if not isinstance(self.__sheet_pay.cell(row=row,column=1).value,str) :#第一列的账期不存在时
self.__sheet_pay.cell(row=row, column=1, value=key1)
row_for_sum+=1 #月份增加一次加一行
self.__sheet_pay.cell(row=row, column=col_for_row1, value=value1)
row += 1
#每一种云服务重新换列
col_for_row1+=1
print(row_for_sum,col_for_row1)
#标题
first_month = self.__sheet_pay.cell(row=3,column=1).value
last_month = self.__sheet_pay.cell(row=(row_for_sum-1),column=1).value
self.__sheet_pay.merge_cells(start_row=1, start_column=1, end_row=1, end_column=col_for_row1)
self.__sheet_pay.cell(row=1, column=1, value=first_month+'到'+last_month+'的总费用')
self.__sheet_pay.cell(row=1, column=1).font = self.__font
self.__sheet_pay.cell(row=1, column=1).alignment = self.__align_center
#行列的合计
self.__sheet_pay.cell(row=row_for_sum, column=1, value='合计')
self.__sheet_pay.cell(row=2, column=col_for_row1, value='合计')
self.__sheet_pay.cell(row=2, column=col_for_row1).font = self.__font
self.__sheet_pay.cell(row=row_for_sum, column=1).font = self.__font
#算每一列的总和
for col_pay in range(2,col_for_row1):
sum_for_the_whole_col = 0
for row_pay in range(3,row_for_sum):
sum_for_the_whole_col+=self.__sheet_pay.cell(row=row_pay,column=col_pay).value
self.__sheet_pay.cell(row=row_for_sum, column=col_pay, value=sum_for_the_whole_col)
self.__sheet_pay.cell(row=row_for_sum, column=col_pay).font = self.__font
#算每一行的总和
for row_pay in range(3,(row_for_sum+1)):
sum_for_the_whole_row = 0
for col_pay in range(2, col_for_row1):
sum_for_the_whole_row += self.__sheet_pay.cell(row=row_pay, column=col_pay).value
self.__sheet_pay.cell(row=row_pay, column=col_for_row1, value=sum_for_the_whole_row)
self.__sheet_pay.cell(row=row_pay, column=col_for_row1).font = self.__font
def __create_remain_csv(self):
print('现在生成remain.csv文件,这是没有匹配到的数据 ')
path = "remain.csv"
with open(path, 'w', encoding='UTF-8') as f:
f_csv = csv.writer(f)
f_csv.writerow(self.__data[0])
f_csv.writerows(self.remain_data)
#根据sheet的每一列提取数
def __handle_data(self,data_ecs):
data_ecs_handle=[]
for item in list(data_ecs.values())[0]:
item_data = []
item_data.append(item[self.__index_1])
item_data.append(item[self.__index_2])
item_data.append(item[self.__index_3])
item_data.append(item[self.__index_4])
item_data.append(item[self.__index_5])
item_data.append(item[self.__index_6])
item_data.append(item[self.__index_7])
item_data.append(item[self.__index_8])
item_data.append(item[self.__index_9])
item_data.append(item[self.__index_10])
item_data.append(item[self.__index_11])
item_data.append(item[self.__index_12])
item_data.append(float(item[self.__index_13]))
data_ecs_handle.append(item_data)
return data_ecs_handle
#读取csv文件
def get_data(file,title):
data = []
try:
with open(file,'r', encoding='UTF-8-sig') as csvfile:
csv_reader = csv.reader(csvfile)
for row in csv_reader:
data.append(row)
except:
print('您的文件读取格式不对')
sys.exit(1)
#判断要的每一列数据是否存在
print('titel is {}'.format(data[0]))
for item in title:
if item not in data[0]:
print('this {} content is not exist'.format(item))
sys.exit(1)
return data
def get_arg():
if len(sys.argv) == 1 :
print("只需要一个参数,请输入财务单元例如 浙江新闻app 天目云")
sys.exit(1)
path = os.getcwd()
dirs = os.listdir(path)
csv = 0
file= ''
for dir in dirs:
if csv > 1:
print('您的当前目录不止一个csv文件')
sys.exit(1)
if os.path.splitext(dir)[1] == '.csv':
file = dir
csv+=1
return [sys.argv[1:],file]
if __name__ == '__main__':
title = ['账期', '财务单元','产品明细Code', '产品明细', '消费类型', '账单类型', '实例ID', '实例昵称', '资源组', '实例配置', '实例规格', '私网IP',
'应付金额'] # 需要的每项数据
args = get_arg()
data = get_data(args[1],title) #读取csv文件获取数据
result_file_name =args[0][0]+'.xls' # 统计生成的账单文件
obj = ExcelWrite(data,result_file_name,args[0])
obj.create_file()