人生如砖,岁月来搬
一.人生苦短,学点Python
在编写完从Excel中抽取关键数据的时候,突然想到每家公司在对数据筛选要求上的不尽相同,于是乎又手写了另一个脚本作为plan-B,这回不仅在开头申明了用法说明和举例解释,还写了Readme提前补充一下,但固定的数据源是不存在的,如果只是算法的变量取值有变那倒还好说,就怕数据源的名词也有变,挨个同步岂不是要疯…
二.需求是第一生产动力
1.主线任务:数据抽取存放到新建文件中
2.赏金任务:写个replace(),通过该函数将文件中所有相同的【名词】进行替换;
3.修仙任务:对input()进行限制,如10分钟内连续输入5次则退出;
4.渡劫任务:实现输入的自动补全。
三.Just do it——干就完了
1.主线任务:抽取数据(plan-A)的代码
# coding:utf-8
# 抽选说明:依据'资产数量'和'重要程度'进行筛选,不要求用途名称相同的资产按照数量进行命名和排序
# 抽选方式:相同类型至少抽20%,10台以内全部抽选
# 关于数量的例子:
# 实际调查表中
# 资产名称 数量
# 应用系统服务器 10
# 调查表上传报告生成工具前应修改为:
# 资产名称 数量
# 应用系统服务器01 1
# 应用系统服务器02 1
# 应用系统服务器03-20 10
# 代码抽选的数据文件内存储为:
# [应用系统服务器01,应用系统服务器02]
# 导入模块
import sys
import openpyxl
import pprint
import re
# 定义:资产列表和字典
engine_Room_data = []
network_Equipment_data = []
aqData = []
fwqData = {}
zdData = []
glrjData = {}
application_System_data = []
# main:打开'调查表.xlsx',循序筛选每一个sheet的数据。
# 若'调查表.xlsx'发生更新,后期再由维护人员?手动更新代码即可。
def questionaire_main():
#处理所有调用函数报错的情况
try:
wbData = file_read()
engine_room_Function(wbData)
network_equipment_Function(wbData)
safety_equipment_Function(wbData)
server_Function(wbData)
terminal_Function(wbData)
management_software_Function(wbData)
application_system_Function(wbData)
file_write()
except SystemExit as err:
#将错误类型格式化成字符串
message = pprint.pformat(err)
if message == 'SystemExit(3)':
sys.exit('文件读取失败!')
elif message == 'SystemExit(4)':
sys.exit('文件写入失败!')
elif message == 'SystemExit(5)':
sys.exit('sheet名字不正确(表2-物理机房)!')
elif message == 'SystemExit(6)':
sys.exit('sheet名字不正确(表3-网络设备)!')
elif message == 'SystemExit(7)':
sys.exit('sheet名字不正确(表4-安全设备)!')
elif message == 'SystemExit(8)':
sys.exit('sheet名字不正确(表6-服务器或存储设备)!')
elif message == 'SystemExit(9)':
sys.exit('sheet名字不正确(表7-终端或现场设备)!')
elif message == 'SystemExit(10)':
sys.exit('sheet名字不正确(表8-系统管理软件或平台)!')
elif message == 'SystemExit(11)':
sys.exit('sheet名字不正确(表9-业务应用系统或平台)!')
elif message == 'SystemExit(12)':
sys.exit('数据读取异常,\'表2-物理机房\' \'重要程度\'的内容有误。。。。。。')
elif message == 'SystemExit(13)':
sys.exit('数据读取异常,\'表3-网络设备\' \'数量\'的内容有误。。。。。。')
elif message == 'SystemExit(14)':
sys.exit('数据读取异常,\'表4-安全设备\' \'重要程度\'的内容有误。。。。。。')
elif message == 'SystemExit(15)':
sys.exit('数据读取异常,\'表6-服务器或存储设备\' \'数量\'的内容有误。。。。。。')
elif message == 'SystemExit(16)':
sys.exit('数据读取异常,\'表7-终端或现场设备\' \'数量\'的内容有误。。。。。。')
elif message == 'SystemExit(17)':
sys.exit('数据读取异常,\'表8-系统管理软件或平台\' \'重要程度\'的内容有误。。。。。。')
elif message == 'SystemExit(18)':
sys.exit('数据读取异常,\'表9-业务应用系统或平台\' \'重要程度\'的内容有误。。。。。。')
sys.exit('***已结束***')
# func:读取文件
def file_read():
try:
wbData = openpyxl.load_workbook('../assess-require/调查表.xlsx')
return wbData
except Exception as e:
sys.exit(3)
# func:保存文件
def file_write():
try:
outFile = open('../dataCool/asset/allAsset.py', 'w', encoding='utf-8')
# 调用:用pprint格式化数据加拼接,并写入文件中
outFile.write('\nengine_Room_data=' + pprint.pformat(engine_Room_data)+'\nnetwork_Equipment_data=' + pprint.pformat(network_Equipment_data)+'\naqData=' + pprint.pformat(aqData)+'\nfwqData=' + pprint.pformat(fwqData)+'\nfwqData=' + pprint.pformat(fwqData)+'\nzdData=' + pprint.pformat(zdData)+'\nglrjData=' + pprint.pformat(glrjData)+'\napplication_System_data=' + pprint.pformat(application_System_data))
except Exception as e:
sys.exit(4)
# func:处理物理机房数据,不?存在数量
def engine_room_Function(wb):
# 找到'表2-物理机房'
try:
assetSh = wb['表2-物理机房']
except Exception as err:
sys.exit(5)
for row in range(2, assetSh.max_row + 1):
# B列'机房名称'
name = assetSh['B' + str(row)].value
# D列'重要程度'
importance = assetSh['D' + str(row)].value
if importance == '关键' or importance == '重要':
engine_Room_data.append(name)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(12)
# func:处理网络设备数据
def network_equipment_Function(wb):
# 找到'表3-网络设备'
try:
assetSh = wb['表3-网络设备']
except Exception as err:
sys.exit(6)
for row in range(2, assetSh.max_row + 1):
# B列'设备名称'
name = assetSh['B' + str(row)].value
# G列'重要程度'
importance = assetSh['G' + str(row)].value
# I列'数量'
amount = assetSh['I' + str(row)].value
if importance == '关键' or importance == '重要':
# 处理非数字类型字符的异常
try:
# 如果资产数量10台以内
if int(amount) < 10:
for i in range(1, int(amount) + 1):
network_Equipment_data.append(name + '0' + str(i))
# 如果资产数量超过10
elif int(amount) > 10:
i = 0
if int(amount) % 5 != 0:
i = int(amount) // 5 + 1
for j in range(1, i + 1):
# 调用:追加'设备名称',至少抽?20%
if i < 10:
network_Equipment_data.append(name + '0' + str(i))
else:
network_Equipment_data.append(name + str(i))
except Exception as e:
# 调用:退出程序,并打印错误信息
sys.exit(13)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
print(importance)
sys.exit('数据读取异常,\'表3-网络设备\' \'重要程度\'的内容有误。。。。。。')
# func:处理安全设备数据
def safety_equipment_Function(wb):
# 找到'表4-安全设备'
try:
assetSh = wb['表4-安全设备']
except Exception as err:
sys.exit(7)
for row in range(2, assetSh.max_row + 1):
# B列'设备名称'
name = assetSh['B' + str(row)].value
# G列'重要程度'
importance = assetSh['G' + str(row)].value
# I列'数量'
amount = assetSh['I' + str(row)].value
if importance == '关键' or importance == '重要':
# 处理非数字类型字符的异常
try:
# 如果资产数量10台以内
if int(amount) < 10:
for i in range(1, int(amount) + 1):
aqData.append(name + '0'+str(i))
# 如果资产数量超过10
elif int(amount) > 10:
i=0
if int(amount)%5 != 0:
i=int(amount)//5+1
for j in range(1,i+1):
# 调用:追加'设备名称',至少抽?20%
if i <10:
aqData.append(name + '0'+str(i))
else:
aqData.append(name + str(i))
except Exception as e:
# 调用:退出程序,并打印错误信息
sys.exit(14)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(14)
# func:处理服务器或存储设备数据
def server_Function(wb):
# 找到'表6-服务器或存储设备'
try:
assetSh = wb['表6-服务器或存储设备']
except Exception as err:
sys.exit(8)
for row in range(2, assetSh.max_row + 1):
# B列'设备名称'
name = assetSh['B' + str(row)].value
# E列'操作系统'
if re.search(r'windows',assetSh['E' + str(row)].value,flags=re.I):
system='windows'
elif re.search(r'linux',assetSh['E' + str(row)].value,flags=re.I):
system='linux'
elif re.search(r'centos',assetSh['E' + str(row)].value,flags=re.I):
system='linux'
elif re.search(r'redhat',assetSh['E' + str(row)].value,flags=re.I):
system='linux'
elif re.search(r'麒麟',assetSh['E' + str(row)].value,flags=re.I):
system='linux'
elif re.search(r'ubuntu', assetSh['E' + str(row)].value, flags=re.I):
system = 'linux'
elif re.search(r'suse', assetSh['E' + str(row)].value, flags=re.I):
system = 'linux'
elif re.search(r'debain', assetSh['E' + str(row)].value, flags=re.I):
system = 'linux'
elif re.search(r'aix',assetSh['E' + str(row)].value,flags=re.I):
system='aix'
else:
system = 'common-system'
# H列'重要程度'
importance = assetSh['H' + str(row)].value
# I列'数量'
amount = assetSh['I' + str(row)].value
if importance == '关键' or importance == '重要':
# 处理非数字类型字符的异常
try:
# 如果资产数量10台以内
if int(amount) < 10:
for i in range(1, int(amount) + 1):
fwqData.setdefault(name + '0' + str(i),system)
# 如果资产数量超过10
elif int(amount) > 10:
i = 0
if int(amount) % 5 != 0:
i = int(amount) // 5 + 1
for j in range(1, i + 1):
# 调用:追加'设备名称',至少抽?20%
if i < 10:
fwqData.setdefault(name + '0' + str(i),system)
else:
fwqData.setdefault(name + str(i),system)
except Exception as e:
# 调用:退出程序,并打印错误信息
sys.exit(15)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(15)
# func:处理终端或现场设备数据
def terminal_Function(wb):
# 找到'表7-终端或现场设备'
try:
assetSh = wb['表7-终端或现场设备']
except Exception as err:
sys.exit(9)
for row in range(2, assetSh.max_row + 1):
# B列'设备名称'
name = assetSh['B' + str(row)].value
# F列'重要程度'
importance = assetSh['F' + str(row)].value
# G列'数量'
amount = assetSh['G' + str(row)].value
if importance == '关键' or importance == '重要':
# 处理非数字类型字符的异常
try:
# 如果资产数量10台以内
if int(amount) < 10:
for i in range(1, int(amount) + 1):
zdData.append(name + '0' + str(i))
# 如果资产数量超过10
elif int(amount) > 10:
i = 0
if int(amount) % 5 != 0:
i = int(amount) // 5 + 1
for j in range(1, i + 1):
# 调用:追加'设备名称',至少抽?20%
if i < 10:
zdData.append(name + '0' + str(j))
else:
zdData.append(name + str(j))
except Exception as e:
# 调用:退出程序,并打印错误信息
sys.exit(16)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(16)
# func:处理系统管理软件或平台数据
def management_software_Function(wb):
# 找到'表8-系统管理软件或平台'
try:
assetSh = wb['表8-系统管理软件或平台']
except Exception as err:
sys.exit(10)
for row in range(2, assetSh.max_row + 1):
# B列'机房名称'
name = assetSh['B' + str(row)].value
# 软件系统
# 数据库
if re.search(r'mysql',name,flags=re.I):
system='mysql'
elif re.search(r'sqlserver',name,flags=re.I):
system = 'sqlserver'
elif re.search(r'sql server',name,flags=re.I):
system = 'sqlserver'
elif re.search(r'oracle',name,flags=re.I):
system = 'oracle'
elif re.search(r'sqlite',name,flags=re.I):
system = 'sqlite'
elif re.search(r'postgresql',name,flags=re.I):
system = 'postgresql'
elif re.search(r'mariadb',name,flags=re.I):
system = 'mariadb'
elif re.search(r'mongodb',name,flags=re.I):
system = 'mongodb'
elif re.search(r'redis',name,flags=re.I):
system = 'redis'
# 中间件
elif re.search(r'iis',name,flags=re.I):
system = 'iis'
elif re.search(r'tomcat',name,flags=re.I):
system = 'tomcat'
elif re.search(r'weblogic',name,flags=re.I):
system = 'weblogic'
elif re.search(r'jetty',name,flags=re.I):
system = 'jetty'
elif re.search(r'jboss',name,flags=re.I):
system = 'jboss'
elif re.search(r'webshphere',name,flags=re.I):
system = 'websphere'
elif re.search(r'mq',name,flags=re.I):
system = 'mq'
else:
system='common-system'
# F列'重要程度'
importance = assetSh['F' + str(row)].value
if importance == '关键' or importance == '重要':
glrjData.setdefault(name,system)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(17)
# func:处理业务应用系统或平台数据
def application_system_Function(wb):
# 找到'表9-业务应用系统或平台'
try:
assetSh = wb['表9-业务应用系统或平台']
except Exception as err:
sys.exit(11)
for row in range(2, assetSh.max_row + 1):
# B列'机房名称'
name = assetSh['B' + str(row)].value
# F列'重要程度'
importance = assetSh['F' + str(row)].value
if importance == '关键' or importance == '重要':
application_System_data.append(name)
# or 过滤?空行数据
elif importance == '一般' or name == importance:
continue
else:
sys.exit(18)
# 当前文件被调用的时候,if里的语句不执行
if __name__ == '__main__':
# 执行主函数
questionaire_main()
0.知识点zero:
‘/’ 这个除取浮点,’//’ 这个除采取商。
1.知识点one:
try:
except SystemExit as err:可以用来接 sys.exit()的中断,返回在 err = SystemExit(),所以格式化一下就可以拿到括号里的值来判断错误类型了,或者和我上面一样偷懒。
2.知识点two:
if __name__ == '__main__':
questionaire_main()
此文件如果被当做模块引用,则 if 作用域下的所有内容都不被使用。
3.数据有误的话,如下所示:
在数据那一列我改写为了 ‘非数字’类型字符 ‘ss’
报错如下:
无错执行结果如下:
数据文件结果如下:
小结:
最大行数遍历的时候会遇到空行,所以筛选时应过滤一下。plan-B不贴了,只是把 ‘重要程度’ 和 ‘是否抽选’ 作为筛选条件进行互换了。
2.赏金任务:替换数据(replace.py)的代码
# coding:utf-8
# 使用注意:除非你要替换的内容为唯一内容,不涉及基础代码,不然替换会导致原代码异常,如拼写异常等情况发生。
import sys
import os
import pprint
import time
from datetime import datetime
# 从sys.path下找到包的路径
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from configuration.OS_func_Limited import input_limited
from configuration.common_configure import outPut
# func:主函数-替换操作(如将'../temp/test.py'中的'c'替换为'i')
def main():
print(' \n\n替换须谨慎! 内容确保唯一!')
flag = 0
flagOut = 0
timeOut = datetime.now()
while flag == flagOut:
if flag == 0:
print('请输入文件路径:')
if (datetime.now() - timeOut).seconds >= int(outPut['time_out']):
timeOut = datetime.now()
flag=0
flagOut=0
try:
#用 input_limited()将input()封装了一下
pathFile,count_max = input_limited(flag, timeOut)
replace(pathFile)
except SystemExit as err:
message = pprint.pformat(err)
if message == 'SystemExit(3)':
sys.exit('连续错误输入,已退出......')
elif message == 'SystemExit(4)':
if flag < int(count_max) - 1:
print('文件路径错误或权限不够!')
print('请输入文件路径:')
elif message == 'SystemExit(5)':
sys.exit('文件读取失败,已退出......')
elif message == 'SystemExit(6)':
sys.exit('文件写入失败,已退出......')
flag += 1
flagOut += 1
sys.exit('***已结束***')
# func:替换函数
def replace(file):
flag = 0
flagOut = 0
while flag == flagOut:
content = read_file(file)
oldContent = input('请输入原始内容:')
newContent = input('请输入新内容:')
contentNew = content.replace(oldContent, newContent)
flagOut += 1
if contentNew == content:
print('替换失败,输入内容有误!')
flag = replace_judge(flag,flagOut)
else:
rewrite_file(file, contentNew)
flag = replace_judge(flag, flagOut)
# func:替换函数-内容判断、输入超时和次数
def replace_judge(flag,flagOut):
print('是否还需要替换? (是/否)')
judge = '否'
flagGo = 0
timeOut = datetime.now()
while judge == '否':
if (datetime.now() - timeOut).seconds >= int(outPut['time_out']):
timeOut = datetime.now()
flagGo = 0
judge ,count_max= input_limited(flagGo, timeOut)
if judge == '是':
flag=flagOut
return flag
elif judge == '否':
judge = 'out'
return flag
else:
judge = '否'
flagGo += 1
if flagGo < int(count_max):
print('请输入 是 或 否!')
# func:读文件函数
def read_file(file):
try:
fileOpen = open(file, encoding='UTF-8')
except Exception as e:
sys.exit(4)
try:
read_all = fileOpen.read()
except Exception as e:
sys.exit(5)
return read_all
# func:写文件函数
def rewrite_file(file, data):
try:
fileOpen = open(file, 'w', encoding='UTF-8')
print('***写入成功***')
except Exception as e:
sys.exit(4)
try:
fileOpen.write(data)
except Exception as e:
sys.exit(6)
# 外部调用此文件则不执行if下的语句
if __name__ == '__main__':
main()
0.知识点zero:
核心就用到了 open(),read(),write(),这里例子网上一大堆我就不赘述了。
1.知识点one:
# 从sys.path下找到包的路径
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from configuration.OS_func_Limited import input_limited
from configuration.common_configure import outPut
有价值的就这个——sys.path.append(os.path.dirname(os.path.dirname(file))),它这个貌似是解析二级路径的,然后你可以从当前程序的路径退到外层一级路径,在外层路径同级下的其他目录文件里找自己的包模块,至于二级以上深度的我还测试过,是不是再嵌套写==os.pathdirname()==这里mark一下。
2.知识点two:
datatime模块,datatime.now()——返回当前时间, ().seconds——可以做运算,返回值取不大于原值的最大整数(即忽略了小数)
小结:
input_limited()可实现输入次数和连续时间的部分控制功能。
3.修仙任务:控制输入(OS_func_Limited.py和common_configure.py)的代码
请结合赏金任务replace.py的代码来看
OS_func_Limited.py:
# coding:utf-8
import sys
import re
import time
from datetime import datetime
# 导入配置文件
from common_configure import outPut
# func:input()限制函数
# 3:输入次数超过5次,连续时间为10分钟
def input_limited(counter, data):
D_Value = (datetime.now() - data).seconds
count_max=outPut['count_input']
if int(D_Value) < int(outPut['time_out']) and counter < int(outPut['count_input']):
value = input()
else:
sys.exit(3)
return value,count_max
common_configure.py:
# coding:utf-8
# unit of time_out is second.
outPut={
'count_input':'5',
'time_out':'60',
}
小结:
没啥好说的,除了系统函数,都是一些逻辑判断的组合,咱们直接上图吧
~~~ ︿( ̄︶ ̄)︿ ~~~
小结:
之前代码里出现了一个bug,content = read_file(file)没有放进while 循环里,导致了无论你多少次的read()和write(),程序只记最后一次结束前的替换值,因为在文件未被关闭或缓冲区未刷新时,输入的字符串存储在缓冲区中未写入文件。
3.渡劫任务:自动补全
嗯,这个坑先放一放,不然主线要做不完了(理由)。我在度娘那里实在是没捞到什么干货,怎么搜,给的都是自动补全如何配置或者代码自动补全功能等,我也是服了,包括后面退而求其次搜索如何获取键盘按键对应的值,也是无脑寻章摘句,tk()暂时是用不上了,如果走到后面用到GUI可以试一试,但图形界面还要手写确实太累,只好退而再求其次搜索如何获取所有路径。。。。。。忘了补全什么了吧,我只是懒的打file-path,后来加循环判断是否还需要替换就是应对这个问题的(狡辩)。