Python+Excel+数据——一键通关的快乐ing(V2.0)

一.人生苦短,学点Python

在出差前一周准备的时候,我突然意识到偏离了“一键通关”含义180°,那时候我的代码已经敲到最后数据导出了…无限崩溃_(:з」∠)_不循环而且无理。

二.需求是第一生产动力

1.主线任务:一键通关:读取《调研表》和《SAG数据总表》,导出系统测评表

2.赏金任务:自定义错误类型,字符串各种切割,弄弄表情包

3.修仙任务:整理《SAG数据总表》

4.渡劫任务:模糊算法+随便找个测评表将内容替换进导出的测评表中

三.Just do it——干就完了

1.回顾:

之前说pycharm没有replace功能是我没发现或者用得不是很多所以给忽略了,其实只要右键变量或者函数名->重构->重命名便可以一次性替换一个文件里所有的内容了,但跨文件或者想替换特殊符号?前的字符串应该是行不通的,所以自己写个replace还是有必要的。还有就是if name == ‘main’: 可以用来进行调试或者测试当前文件的功能代码,代码如下,可以自定义测试数据等:

# 当前文件被调用的时候,if里的语句不执行
if __name__ == '__main__':
    readInpath = '../assess_require/调查表.xlsx'
    writeOutpath = '../dataCool/asset/allAsset.py'
    # 执行主函数
    _, _, _ = questionaire(readInpath, writeOutpath)
2.任务:
①.主线:一键通关

代码如下:
文件名:Tool.py

# coding:utf-8

# 系统:导入模块
import re, pprint, sys
from datetime import datetime

# 私有:导入模块
from report_generate import *
from sag_and_assess import *

# 数据源的配置路径包
questionaireDir = './assess_require/调查表.xlsx'
assetDir='./dataCool/asset/allAsset.py'
sagpathDir='./dataCool/base'
reportPathdir='./assess_report'

def Tool_main():
    systemName, sagLevel ,industry= questionaire(questionaireDir,assetDir)
    if out_temp_program(sagLevel):
        assess_report_export(sagpathDir,reportPathdir,systemName,sagLevel,industry)
    else:
        sys.exit('目前测试系统等级不包含5级,请修改\'调查表.xlsx\'内容!')

# func:临时退出函数,判断内容里是否含有'5'
def out_temp_program(list):
    for str in list:
        if re.search('5',str) is not None:
            return False
        else:
            return True


if __name__ == '__main__':
    Tool_main()
    pass
②.主线:读取《调研表》

代码如下:
文件名:sag_and_assess.py

# coding:utf-8
# 抽选说明:依据'资产数量'和'重要程度'进行筛选,不要求用途名称相同的资产按照数量进行命名和排序
# 抽选方式:相同类型至少抽20%,10台以内全部抽选
# 关于数量的例子:
# 实际调查表中
#      资产名称             数量
#   应用系统服务器            10

# 调查表上传报告生成工具前应修改为:
#      资产名称             数量
#   应用系统服务器01          1
#   应用系统服务器02          1
#   应用系统服务器03-10       10

# 代码抽选的数据文件内存储为:
# [应用系统服务器01,应用系统服务器02]

# 导入模块
import sys, os

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from input_aggregate import *
from file_action import *
from print_aggregate import *

# 文件函数的功能介绍
funcName = '资产数据分析模块'

# 定义:资产列表和字典
安全物理环境 = {}
网络设备 = {}
安全设备 = {}
服务器 = {}
终端 = {}
管理软件 = {}
应用 = {}


# main:打开'调查表.xlsx',循序筛选每一个sheet的数据。
# 若'调查表.xlsx'发生更新,后期再由维护人员?手动更新代码即可。
def questionaire(fileReadpath, fileWritepath):
    function_open_print(funcName)
    string = '# coding:utf-8\n\n'
    while True:
        try:
            wbData = file_read_auto(fileReadpath)
            systemName, sagLevel, industryString, industry = essential_information_function(wbData)
            string = engine_room_function(wbData,string)
            string = network_function(string)
            string = network_equipment_function(wbData,string)
            string = safety_equipment_function(wbData,string)
            string = server_function(wbData,string)
            string = terminal_function(wbData,string)
            string = center_function(string)
            string = management_software_function(wbData,string)
            string = application_system_function(wbData,string)
            string = management_function(string)
            file_write_auto(fileWritepath, write_string_combination(string,industryString))
            function_close_print(funcName)
            break
        except Exception as err:
            topString, middleString, _ = string_parentheses(pprint.pformat(err))
            if topString == 'InputError':
                print(middleString)
                pass
            elif topString == 'RequestExit':
                sys.exit(middleString)
            else:
                function_fail()
                sys.exit('一条野生异常需要处理......sag_and_assess_01')
                pass
    print(sagLevel)
    return systemName, sagLevel, industry


levelListchar = ['一', '二', '三', '四', '五']
levelListnum = ['1','2','3','4','5']
levelDict={'一':'1', '二':'2', '三':'3', '四':'4', '五':'5'}
levelSpecial=['5','五']
levelList=[]


# func:获取基本信息:系统名称、sa等级、通用/扩展
def essential_information_function(wb):
    try:
        assetSh = wb['表1-系统基础信息表']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表1-系统基础信息表)!')
    # C列'定级系统名称'
    systemName = assetSh['C' + '1'].value
    # C列'安全保护等级'
    topString, middleString, _ = string_parentheses(assetSh['C' + '2'].value)
    # 判断:全5级
    if middleString[1] == '5' and middleString[3] == '5':
        raise RequestExit('SA填写错误,没有全5级系统(表1-系统基础信息表)!')
    else:
        # 判断:SXAX长度不为4,不存在S,不存在A,X不为数字字符串
        if len(middleString) != 4 or middleString[0] != 'S' or \
                middleString[2] != 'A' or re.search(r'\D', middleString[1]) is not None or re.search(r'\D',
                                                                                                     middleString[
                                                                                                         3]) is not None:
            raise RequestExit('SA等级填写错误(表1-系统基础信息表)!')
        else:
            # 判断:GX中X不在leveListchar列表中
            if topString[1] not in levelListchar:
                # 判断:GX中X不在leveListnum列表中
                if topString[1] not in levelListnum:
                    raise RequestExit('系统等级错误(表1-系统基础信息表)!')
                else:
                    # 判断:G的X不与SA的X相同
                    if topString[1] != middleString[1] and topString[1] != middleString[3]:
                        raise RequestExit('系统等级和SA等级不符(表1-系统基础信息表)!')
                    else:
                        # 判断:S的X大于A的X
                        if int(middleString[1]) > int(middleString[3]):
                            # 判断:G的X不等于S的X
                            if topString[1] != middleString[1]:
                                raise RequestExit('系统等级是SA等级中最高级一项(表1-系统基础信息表)!')
                            else:
                                levelList.append(middleString[0:2])
                                levelList.append(middleString[2:4])
                                levelList.append(topString)
                        else:
                            # 判断:G的X不等于A的X
                            if topString[1] != middleString[3]:
                                raise RequestExit('系统等级是SA等级中最高级一项(表1-系统基础信息表)!')
                            else:
                                levelList.append(middleString[0:2])
                                levelList.append(middleString[2:4])
                                levelList.append(topString)
            else:
                # 判断:G的X不与SA的X相同
                if levelDict[topString[1]] != middleString[1] and levelDict[topString[1]] != middleString[3]:
                    raise RequestExit('系统等级和SA等级不符(表1-系统基础信息表)!')
                else:
                    # 判断:S的X大于A的X
                    if int(middleString[1]) > int(middleString[3]):
                        # 判断:G的X不等于S的X
                        if levelDict[topString[1]] != middleString[1]:
                            raise RequestExit('系统等级是SA等级中最高级一项(表1-系统基础信息表)!')
                        else:
                            levelList.append(middleString[0:2])
                            levelList.append(middleString[2:4])
                            levelList.append('G'+levelDict[topString[1]])
                    else:
                        # 判断:G的X不等于A的X
                        if levelDict[topString[1]] != middleString[3]:
                            raise RequestExit('系统等级是SA等级中最高级一项(表1-系统基础信息表)!')
                        else:
                            levelList.append(middleString[0:2])
                            levelList.append(middleString[2:4])
                            levelList.append('G'+levelDict[topString[1]])
    # C列'系统形态'
    industry = string_industry(assetSh['C' + '5'].value)
    industryString = string_industry_allasset(industry)
    return systemName, levelList, industryString,industry


# func:处理物理机房数据,不?存在数量
def engine_room_function(wb,string):
    # 找到'表2-物理机房'
    try:
        assetSh = wb['表2-物理机房']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表2-物理机房)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'机房名称'
        name = assetSh['B' + str(row)].value
        # D列'重要程度'
        importance = assetSh['D' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表2-物理机房\' \'的内容为空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            安全物理环境.setdefault(name, 'common')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表2-物理机房\' \'重要程度\'的内容有误。。。。。。')
    return write_string_combination(string, '安全物理环境' +'=' + pprint.pformat(安全物理环境) + '\n')


# func:通信网络、区域边界字符串拼接
def network_function(string):
    return write_string_combination(string,'安全通信网络'+'=' + '{\'安全通信网络\':\'common\'}'+'\n'+'安全区域边界'+'=' + '{\'安全区域边界\':\'common\'}'+'\n')


# func:处理网络设备数据
def network_equipment_function(wb,string):
    # 找到'表3-网络设备'
    try:
        assetSh = wb['表3-网络设备']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表3-网络设备)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'设备名称'
        name = assetSh['B' + str(row)].value
        # G列'重要程度'
        importance = assetSh['G' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表3-网络设备\' \'的内容为空。。。。。。')
        else:
            pass
        # 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):
                        网络设备.setdefault(name + '0' + str(i), 'common')
                # 如果资产数量超过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:
                            网络设备.setdefault(name + '0' + str(i), 'common')
                        else:
                            网络设备.setdefault(name + str(i), 'common')
            except Exception as e:
                raise RequestExit('数据读取异常,\'表3-网络设备\' \'数量\'的内容有误。。。。。。')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表3-网络设备\' \'数量\'的内容有误。。。。。。')
    return write_string_combination(string, '网络设备' +'=' + pprint.pformat(网络设备) + '\n')


# func:处理安全设备数据
def safety_equipment_function(wb,string):
    # 找到'表4-安全设备'
    try:
        assetSh = wb['表4-安全设备']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表4-安全设备)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'设备名称'
        name = assetSh['B' + str(row)].value
        # G列'重要程度'
        importance = assetSh['G' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表4-安全设备\' \'的内容为空。。。。。。')
        else:
            pass
        # 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):
                        安全设备.setdefault(name + '0' + str(i), 'common')
                # 如果资产数量超过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:
                            安全设备.setdefault(name + '0' + str(i), 'common')
                        else:
                            安全设备.setdefault(name + str(i), 'common')
            except Exception as e:
                raise RequestExit('数据读取异常,\'表4-安全设备\' \'重要程度\'的内容有误。。。。。。')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表4-安全设备\' \'重要程度\'的内容有误。。。。。。')
    return write_string_combination(string,'安全设备' +'=' + pprint.pformat(安全设备) + '\n')


# func:处理服务器或存储设备数据
def server_function(wb,string):
    # 找到'表6-服务器或存储设备'
    try:
        assetSh = wb['表6-服务器或存储设备']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表6-服务器或存储设备)!')
    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
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表6-服务器或存储设备\' \'的内容为空。。。。。。')
        else:
            pass
        # 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):
                        服务器.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:
                            服务器.setdefault(name + '0' + str(i), system)
                        else:
                            服务器.setdefault(name + str(i), system)
            except Exception as e:
                # 调用:退出程序,并打印错误信息
                raise RequestExit('数据读取异常,\'表6-服务器或存储设备\' \'数量\'的内容有误。。。。。。')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表6-服务器或存储设备\' \'数量\'的内容有误。。。。。。')
    return write_string_combination(string,'服务器' +'=' + pprint.pformat(服务器) + '\n')


# func:处理终端或现场设备数据
def terminal_function(wb,string):
    # 找到'表7-终端或现场设备'
    try:
        assetSh = wb['表7-终端或现场设备']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表7-终端或现场设备)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'设备名称'
        name = assetSh['B' + str(row)].value
        # F列'重要程度'
        importance = assetSh['F' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表7-终端或现场设备\' \'的内容为空。。。。。。')
        else:
            pass
        # 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):
                        终端.setdefault(name + '0' + str(i), 'common')
                # 如果资产数量超过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:
                            终端.setdefault(name + '0' + str(j), 'common')
                        else:
                            终端.setdefault(name + str(j), 'common')
            except Exception as e:
                # 调用:退出程序,并打印错误信息
                raise RequestExit('数据读取异常,\'表7-终端或现场设备\' \'数量\'的内容有误。。。。。。')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表7-终端或现场设备\' \'数量\'的内容有误。。。。。。')
    return write_string_combination(string, '终端' +'=' + pprint.pformat(终端) + '\n')


# func:处理系统管理软件或平台数据
def management_software_function(wb,string):
    # 找到'表8-系统管理软件或平台'
    try:
        assetSh = wb['表8-系统管理软件或平台']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表8-系统管理软件或平台)!')
    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 = 'SQL Server'
        elif re.search(r'sql server', name, flags=re.I):
            system = 'SQL server'
        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 name == None and name != importance:
            raise RequestExit('数据读取异常,\'表8-系统管理软件或平台\' \'的内容为空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            管理软件.setdefault(name, system)
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表8-系统管理软件或平台\' \'重要程度\'的内容有误。。。。。。')
    return write_string_combination(string, '管理软件' +'=' + pprint.pformat(管理软件) + '\n')


# func:处理业务应用系统或平台数据
def application_system_function(wb,string):
    # 找到'表9-业务应用系统或平台'
    try:
        assetSh = wb['表9-业务应用系统或平台']
    except Exception as err:
        raise RequestExit('sheet名字不正确(表9-业务应用系统或平台)!')
    for row in range(2, assetSh.max_row + 1):
        # B列'机房名称'
        name = assetSh['B' + str(row)].value
        # F列'重要程度'
        importance = assetSh['F' + str(row)].value
        if name == None and name != importance:
            raise RequestExit('数据读取异常,\'表9-业务应用系统或平台\' \'的内容为空。。。。。。')
        else:
            pass
        if importance == '非常重要' or importance == '重要':
            应用.setdefault(name, 'common')
        # or 过滤?空行数据
        elif importance == '一般' or name == importance:
            continue
        else:
            raise RequestExit('数据读取异常,\'表9-业务应用系统或平台\' \'重要程度\'的内容有误。。。。。。')
    return write_string_combination(string,'应用' +'=' + pprint.pformat(应用) + '\n')


# func:安全管理中心字符串拼接
def center_function(string):
    return write_string_combination(string,'安全管理中心'+'=' + '{\'安全管理中心\':\'common\'}'+'\n')


# func:安全管理 字符串拼接
def management_function(string):
    return write_string_combination(string,'安全管理制度'+'=' + '{\'安全管理制度\':\'common\'}'+'\n'+'安全管理机构'+'=' + '{\'安全管理机构\':\'common\'}'+'\n'+'安全管理人员'+'=' + '{\'安全管理人员\':\'common\'}'+'\n'+'\n'+'安全建设管理'+'=' + '{\'安全建设管理\':\'common\'}'+'\n'+'安全运维管理'+'=' + '{\'安全运维管理\':\'common\'}'+'\n')


# func:资产名称和内容整合
def write_string_combination(string,addString):
    string += addString
    return string


# 当前文件被调用的时候,if里的语句不执行
if __name__ == '__main__':
    readInpath = '../assess_require/调查表.xlsx'
    writeOutpath = '../dataCool/asset/allAsset.py'
    # 执行主函数
    _, _, _ = questionaire(readInpath, writeOutpath)

文件名:file_action.py

# coding:utf-8



import openpyxl,pprint,sys,os

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from pyclass.exception_class import *
from input_aggregate import input_control_file_path
from string_processing import *
from print_aggregate import *


# func:手动读取文件
def file_read_manual(counter,time):
    try:
        questionaire_file_path_read()
        filePath = input_control_file_path(counter, time)
        wbData = openpyxl.load_workbook(filePath)
        function_read_ok()
        return wbData
    except Exception as err:
        topString, middleString, _ = string_parentheses(pprint.pformat(err))
        print(middleString)
        if topString == 'RequestExit':
            sys.exit(middleString)
        else:
            function_fail()
            raise InputError('路径有问题,文件读取失败!')


# func:自动读取文件
def file_read_auto(filepath):
    try:
        wbData = openpyxl.load_workbook(filepath)
        function_read_ok()
        return wbData
    except Exception as err:
        topString, middleString, _ = string_parentheses(pprint.pformat(err))
        print(middleString)
        if topString == 'RequestExit':
            sys.exit(middleString)
        else:
            function_fail()
            raise RequestExit('路径有问题,文件读取失败!')


# func:手动打开一个文本进行数据的保存,可以存为py文件
def file_write_manual(counter,time,string):
    try:
        filePath = input_control_file_path(counter, time)
        print(filePath)
        outFile = open(filePath, 'w', encoding='utf-8')
        outFile.write(string)
        function_write_ok()
    except Exception as err:
        topString, middleString, _ = string_parentheses(pprint.pformat(err))
        if topString == 'RequestExit':
            sys.exit(middleString)
        else:
            function_fail()
            raise InputError('路径有问题,文件写入失败!')


# func:传参自动打开一个文本进行数据的保存,可以存为py文件
def file_write_auto(filepath,string):
    try:
        outFile = open(filepath, 'w', encoding='utf-8')
        outFile.write(string)
        function_write_ok()
    except Exception as err:
        topString, middleString, _ = string_parentheses(pprint.pformat(err))
        if topString == 'RequestExit':
            sys.exit(middleString)
        else:
            function_fail()
            raise RequestExit('路径有问题,文件写入失败!')
③.主线:读取《SAG数据总表》

代码如下:
文件名:report_generate.py

# coding:utf-8


# 导入模块
import sys, os, openpyxl, pprint

from openpyxl.utils import get_column_letter

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from file_action import *
from dataCool.asset.allAsset import *
from configuration.questionaire_basic import *
from configuration.sagfile_title import *

funcName='·测评表导出模块'
# 字典:存放要创建的sheet的名称和SAG数据总表(bate版).xlsx中对应的sheet的名称
realDict={}


# function:主函数入口
def assess_report_export(sagpathdir,reportpathdir,systemname,saglist,industry):
    function_open_print(systemname+funcName)
    filePath = sagpathdir + '/' + 'SAG数据总表(bate版)' + '.xlsx'
    reportpath = reportpathdir + '/' + systemname + '测评总表' + '.xlsx'
    while True:
        try:
            wbData = workbook_read(filePath)
            sheetList = sheet_title_list(wbData)
            for str in industry:
                make_sheet(allAesset_industryList[str], realDict,sheetList)
            # print(realDict)
            write_report(reportpath,wbData,realDict,saglist)
            break
        except Exception as err:
            topString, middleString, _ = string_parentheses(pprint.pformat(err))
            if topString == 'InputError':
                print(middleString)
            elif topString == 'RequestExit':
                sys.exit(middleString)
            else:
                function_fail()
                sys.exit('一条野生异常需要处理......report_generate_01')
    function_close_print(systemname+funcName)


# func:获取要创建的sheet的名称和SAG数据总表(bate版).xlsx中对应的sheet的名称
def make_sheet(sheetTerm,realDict,sheetList):
    for str in sheetTerm:
        for k,v in eval(str).items():
            realDict.setdefault(k,string_list_match(v,string_list_match(str,sheetList)))


def write_report(reportpath, wbdata,realdict, saglist):
    try:
        value=''
        wb = openpyxl.Workbook()
        # print(realdict)
        for k,v in realDict.items():
            for i in range(len(realdict),-1,-1):
                shReport = wb.create_sheet(index=i, title=k)
                # 返回标识属性所在的坐标,dataConfirm为sagfile_title.py中的参数
                locationKeylist = cell_location(wbdata[v[0]], dataConfirm)
                # 返回建表所需的表头坐标,sagFiletitlecommon为sagfile_title.py中的参数
                locationTitlelist = cell_location(wbdata[v[0]], sagFiletitlecommon)
                # locationKeylist[1]为属性标识
                colstr = get_column_letter(locationKeylist[1][1])
                # 确认标识属性和sag真是等级对应的row横坐标
                rowNew = 1
                for row in range(1,wbdata[v[0]].max_row+1):
                    if rowNew == 1:
                        for col in range(1,len(sagFiletitlecommon)+1):
                            shReport.cell(row=rowNew, column=col, value=sagFiletitlecommon[int(col)-1])
                        rowNew += 1
                    else:
                        pass
                    colNew = 1
                    for sag in saglist:
                        sagNum=int(sag[1])+5
                        if sag in wbdata[v[0]][colstr+str(row)].value:
                            for list in locationTitlelist:
                                colString = get_column_letter(list[1])
                                if int(locationKeylist[0][1]) == int(list[1]):
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=str(sagNum)+'.'+wbdata[v[0]][colString+str(row)].value)
                                    colNew += 1
                                elif int(locationKeylist[1][1]) == int(list[1]):
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=sag)
                                    colNew += 1
                                elif int(locationKeylist[2][1]) == int(list[1]):
                                    if wbdata[v[0]][colString + str(row)].value != None:
                                        shReport.cell(row=rowNew, column=colNew,
                                                      value='高')
                                        colNew += 1
                                    else:
                                        pass
                                else:
                                    shReport.cell(row=rowNew, column=colNew,
                                                  value=wbdata[v[0]][colString + str(row)].value)
                                    colNew +=1
                            rowNew += 1
                        else:
                            pass
                # 中断跳出:这里将 i 作为页数,所以必须退出才能对应
                break
            # 中断跳出:单个页面调试
            # break
        wb.remove(wb['Sheet'])
        wb.save(reportpath)
    except Exception as err:
        raise RequestExit('write_report函数内部错误!')


# func:根据内容反求Excel的坐标
def cell_location(sheet,list):
    tempList=[]
    valueList=[]
    for i in range(len(list)):
        for row in range(1, sheet.max_row + 1):
            for col in range(1, sheet.max_column + 1):
                colStr = get_column_letter(col)
                if sheet[colStr + str(row)].value == list[i]:
                    tempList.append(row)
                    tempList.append(col)
                    valueList.append(tempList)
                    tempList = []
                else:
                    pass
    if len(valueList)!=len(list):
        content_sag_print()
        raise RequestExit('传参的数据或数据文件的数据内容不匹配!')
    else:
        pass
    return valueList


#func:读取Excel工作簿
def workbook_read(filepath):
    try:
        wbData = openpyxl.load_workbook(filepath)
        return wbData
    except Exception as err:
        function_fail()
        raise RequestExit('代码路径有误或文件不存在!')


# func:获取Excel的所有sheet名称
def sheet_title_list(wbdata):
    shList=[]
    for sheet in wbdata:
        shList.append(sheet.title)
    return shList


# func:传函数作为参数
def func_recall(func):
    return func()


if __name__ == '__main__':
    sagpathDir = '../dataCool/base'
    reportpathdir = '../assess_report'
    sagList=['S2','A3','G3']
    assess_report_export(sagpathDir,reportpathdir,'使完feel倍儿爽系统',sagList,['传统IT系统','移动互联'])
④.主线:配置数据

代码如下:
文件名:questionaire_basic.py

# coding:utf-8

# 整合调查表:表1-系统基础信息表的内容
industryList = ['传统IT系统','云计算','移动互联','物联网','工业控制系统','大数据','其他']
judgeIndustry = [' □传',' □云',' □移',' □物',' □工',' □大',' □其']
manageDict={'安全管理制度':'安全管理制度'+'=' + '{\'安全管理制度\':\'common\'}'+'\n','安全管理机构':'安全管理机构'+'=' + '{\'安全管理机构\':\'common\'}'+'\n','安全管理人员':'安全管理人员'+'=' + '{\'安全管理人员\':\'commom\'}'+'\n','安全建设管理':'安全建设管理'+'=' + '{\'安全建设管理\':\'common\'}'+'\n'+'安全运维管理'+'=' + '{\'安全运维管理\':\'common\'}'+'\n'}
industryDict={'云计算':'云计算'+'=' + '{\'云计算\':\'common\'}','移动互联':'移动互联'+'=' + '{\'移动互联\':\'common\'}','物联网':'物联网'+'=' + '{\'物联网\':\'common\'}','工业控制系统':'工业控制系统'+'=' + '{\'工业控制系统\':\'common\'}','大数据':'大数据'+'=' + '{\'大数据\':\'common\'}','其他':'其他'+'=' + '{\'其他\':\'common\'}'}
industryDictnull={'云计算':'云计算'+'=' + '{\'云计算\':\'null\'}','移动互联':'移动互联'+'=' + '{\'移动互联\':\'null\'}','物联网':'物联网'+'=' + '{\'物联网\':\'null\'}','工业控制系统':'工业控制系统'+'=' + '{\'工业控制系统\':\'null\'}','大数据':'大数据'+'=' + '{\'大数据\':\'null\'}','其他':'其他'+'=' + '{\'其他\':\'null\'}'}

# 整合:allAsset.py的数据和industryList:
allAesset_industryList={'传统IT系统':['安全物理环境','安全通信网络','安全区域边界','网络设备','安全设备','服务器','终端','管理软件','应用','安全管理中心','安全管理制度','安全管理机构','安全管理人员','安全建设管理','安全运维管理'],'云计算':['云计算'],'移动互联':['移动互联'],'物联网':['物联网'],'工业控制系统':['工业控制系统'],'大数据':['大数据'],'其他':['其他']}

文件名:sagfile_title.py

# coding:utf-8

sagFiletitlebasic=['通用/扩展','技术/管理','安全层面','安全控制点','标准编号','属性标识','测评指标','测评对象','测评实施内容','单元判定','测评方法','结果记录','符合程度','高风险等级','高风险判定内容','高风险补偿措施','整改建议']

sagFiletitlecommon=['安全层面','安全控制点','标准编号','属性标识','测评指标','测评对象','测评方法','结果记录','符合程度','高风险等级']

dataConfirm=['标准编号','属性标识','高风险等级']
①.赏金:自定义错误类型字符串各种切割,弄弄表情包

代码如下:
文件名:exception_class.py

# coding:utf-8


# 类:input输入错误的错误类型
class InputError(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)


# 类:请求退出的错误类型
class RequestExit(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)


# 类:库函数执行出错的错误类型
class LibaryRuningError(Exception):
    def __init__(self, message):
        self.message = message

    def fail_information(self):
        print(self.message)
②.赏金:字符串各种切割

代码如下:
文件名:string_processing.py

# coding:utf-8


import inspect,re,sys,os,math
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from configuration.questionaire_basic import *
from pyclass.exception_class import *


# func:取出字符串中最外层圆括号(英文括号)内的字符串
# 例子:
# 传入:  ssa,n//2h1e)()as.sad>f,,qwmcma()wkql(laksdkl))))aa
# 返回:  ssa,n//2h1e  ()as.sad>f,,qwmcma()wkql(laksdkl)))  aa
def string_parentheses(string):
    num = []
    startString = ''
    middleString = ''
    endingString = ''
    for i in range(len(string)):
        if string[i] == '(' or string[i] == ')' or string[i] == '(' or string[i] == ')':
            num.append(i)
    for i in range(0, num[0]):
        startString = startString + string[i]
    for i in range(num[0] + 1, num[len(num) - 1]):
        middleString = middleString + string[i]
    for i in range(num[len(num) - 1] + 1, len(string)):
        endingString = endingString + string[i]
    return startString, middleString, endingString


# func:判断' □'和它后面的字符与是否在传入的字符串中,最终返回通用/扩展项
# 例子:
# 传入:  √□传统IT系统 □云计算 ■移动互联 R物联网 □工业控制系统 □大数据 □其他
# 返回:  传统IT系统 移动互联网 物联网
def string_industry(string):
    counter = 0
    realList = []
    for str in judgeIndustry:
        if re.search(str, string, flags=re.I) is None:
            realList.append(industryList[counter])
        else:
            pass
        counter += 1
    if counter == 0 or re.search(' □传', string, flags=re.I) is not None:
        raise RequestExit('文件内容有误,请核实!')
    else:
        pass
    return realList


# func:扩展项字符串组合,传调configuration包中的questionaire_basic文件中的数据industryDict
def string_industry_allasset(industrylist):
    industryString = ''
    for str in industrylist:
        if str == '传统IT系统':
            pass
        else:
            industryString += industryDict[str]
            industryString += '\n'
    return industryString



# func:遍历判断字符串中是否存在空格
# 返回:bool类型
def string_have_empty(string):
    for i in range(len(string)):
        if string[i-1] == ' ':
            return True
    return False


# func:字符串模糊匹配
# 概述:字符串模糊匹配的问题研究:单个字符在顺序上的偏移或者不符。
# 举例:如sql server 和 sqlserver ,空格匹配不到,而后续的字符整体向前偏移了1个精度。
# 总结:单个字符或者连续及散点的字符进行匹配的概率即为匹配精度,而单个字符或者连续字符的规律性偏移程度为偏移精度,两者既可独立,也可连续存在。
# 举例:如sql seaver 和 sqlserver,空格不存在,se是偏移的,a所在及其后续的匹配中都不存在。
# 简单算法设计:采用反减的方式进行匹配,匹配字符长度至少是字符串长度的一半,匹配成功之后根据字符串取半的长度和匹配循环计数器进行计算求出精度,精度符合要求则返回相应值
# 特殊匹配:散点匹配,即取sql seaver 中随机的任意字符和sqlserver进行精度和偏移的匹配再求概率,或者取字符串区间中任意字符进行匹配,对精度要求更高,这里仅做参考。
# 传入:匹配字符串,库源字符串
# 输出:匹配成功字符列表(列表嵌套),匹配精度(计算方法:)
def string_vague_match(subject,object):
    counter=0
    tempList = []
    matchList = []
    while True:
        if len(subject)>counter:
            coordinateList=section_subtraction(len(subject),counter)
            for i in range(len(coordinateList)):
                if re.search(subject[coordinateList[i][0]:coordinateList[i][1]],object,flags=re.I) is not None:
                    tempList.append(subject[coordinateList[i][0]:coordinateList[i][1]])
                else:
                    pass
            if len(tempList) != 0:
                matchList.append(tempList)
            else:
                pass
            tempList=[]
            counter += 1
        else:
            # raise InputError('调查表数据有误'+'('+subject+')'+'请修改调查表保存继续或直接退出!')
            pass
            break
    accuracyCount=len(matchList)/len(subject)*100
    return matchList,accuracyCount


# func:在列表中匹配字符串,相同返回列表中完整的字符串列表
def string_list_match(string,list):
    realList=[]
    for i in range(len(list)):
        if re.search(string,list[i],flags=re.I) is not None:
            realList.append(list[i])
        else:
            pass
    if len(realList) == 0:
        raise RequestExit('请检查\'调查表.xlsx\'中资产的型号是否和\'SAG数据总表(bate版).xlsx\'的sheet名称对应上!')
    else:
        return realList


# func:求字符串区间坐标
# 例子:’subject‘,坐标[2,3]的值为'b',长度为字符串长,区间定长为1
# 传入:字符串长度,区间定长
# 返回:符合区间的坐标列表(列表嵌套的:[[0,1],[0,2]......])
def section_subtraction(length,fixedlength):
    combinationList=[]
    valueList=[]
    for x in range(int(length)+1):
        for y in range(int(length)+1):
            if int(fixedlength) == 0:
                combinationList.append(int(fixedlength))
                combinationList.append(int(length))
                valueList.append(combinationList)
                return valueList
            elif x<=y and abs(x-y) == int(fixedlength):
                combinationList.append(x)
                combinationList.append(y)
                valueList.append(combinationList)
                combinationList=[]
            else:
                pass
    return valueList


#func:变量名转换成字符串,tips:函数名在search函数中作为字符串,次函数的调用只能赋值一次,连续回调只返回第一个变量名
def varname_to_string(p):
    for line in inspect.getframeinfo(inspect.currentframe().f_back)[3]:
        m = re.search(r'\bvarname_to_string\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)', line)
        if m:
            return m.group(1)

def test_code():
    if string_have_empty(' sss s'):
        print('have')
    else:
        print('no')


# print(string_parentheses('ssa,n//2h1e)()as.sad>f,,qwmcma()wkql(laksdkl))))aa'))
if __name__ == '__main__':
    subject = 'sql seaver'
    object = 'sqlserver'
    print(string_vague_match(subject,object))
    pass
③.赏金:弄弄表情包

代码如下:
文件名:print_aggregate.py

# coding:utf-8

import sys,os

sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from pyclass.exception_class import *


# sug:将表情入库并分类,最后随机数打印
# tips:如果表情符号非utf-8,则会报错


def function_open_print(func):
    print('\n~ ̄▽ ̄~[-.-] ')
    print('***' + func + '功能启动***')


def function_read_ok():
    print('\n<( ̄︶ ̄)↗[Go!]')
    print('***读取成功***')


def function_write_ok():
    print('\n<( ̄︶ ̄)↗[Go!]')
    print('***写入成功***')


def function_close_print(func):
    print('\n(°ー°〃)')
    print('***' + func + '功能结束***')

def function_fail():
    print('\n(〇o〇;)')
    # print('***失败了***')


def questionaire_file_path_read():
    print('\n︿( ̄︶ ̄)︿')
    print('请输入\'调查表\'文件的相对路径:             (exit退出)')


def questionaire_file_path_write():
    print('\n(ˉ▽ˉ;)')
    print('请输入\'资产表\'文件的相对路径:             (exit退出)')


def sag_glevel_print():
    print('\no(# ̄▽ ̄)==G')
    print('请输入系统安全(G)等级:             (exit退出)')


def sag_salevel_print():
    print('\no(# ̄▽ ̄)==SA')
    print('请输入系统安全(SA)等级(连续数字):             (exit退出)')


def sheet_title_print():
    print('\n~o ̄▽ ̄~o')
    print('请输入你要的*测评层面*,内容参考如上(支持关键字搜索,以中文逗号分隔):             (exit退出)')


def sheet_header_print():
    print('\n~o ̄▽ ̄~o')
    print('请输入你要的*制表内容*,内容参考如上(支持关键字搜索,以中文逗号分隔):             (exit退出)')


def input_again_print():
    print('\n~o ̄▽ ̄~o')
    print('请重新*输入内容*(支持关键字搜索,以中文逗号分隔):             (exit退出)')


def content_filter_print():
    print('\n⊙_⊙')
    print('内容有误,过滤后内容如上所示:')


def filt_state_open_print():
    print('\n⊙_⊙')
    print('保存的文件处于打开状态,请保存关闭重新输入:')


def content_sag_print():
    print('\n⊙_⊙')
    print('数据源表头缺损,请保存修改完数据源文件后,按任意键重新输入!')


def pass_or_exit_print():
    print('\n= ̄ω ̄=')
    print('继续则输出上述过滤内容:         (y)')
    print('或重新选择测评层面:            (n)')
    print('退出:                      (exit)')


def report_out_print():
    print('\n (=^ω^=)')
    print('===制作完成===')


def count_2_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('选择对象内容为空,请重新选择!02')
    else:
        pass
    for i in list:
        if flag < 2:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')


def count_3_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('选择对象内容为空,请重新选择!03')
    else:
        pass
    for i in list:
        if flag < 2:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')


def count_4_control_list_print(list):
    flag=0
    if len(list)==0:
        raise InputError('选择对象内容为空,请重新选择!04')
    else:
        pass
    for i in list:
        if flag < 4:
            flag+=1
            print(i,end='\t\t')
        else:
            flag=0
            print(i,end='\n')



if __name__ == '__main__':
    function_read_ok()
①.修仙:整理《SAG数据总表》

在这里插入图片描述
在这里插入图片描述
简单分析:结构就是表头+内容没什么,主要是后面对数据读取的判断因素,这里将标准编号(1.1.1)、属性标识(G1G2G3G4…)、高风险等级(G1G2…)(这里有个瑕疵:前面属性未A的我也标成G了,这里要统一,因为代码里没有算法做判断)作为程序里判断数据是否应该抽取的逻辑依据,总表的内容可以增加,在数据配置文件中也可固定需要导出的内容项。

①.渡劫任务:模糊算法和测评表数据的转移

考虑到实际情况调研表的内容现场填写如果出现笔误,比如SQL Server 敲成了SQL sever、Windows敲成了windos怎么办,这里我在代码里固定了专属名称的格式,如果数据不符会则报错,但更智能的方法是可以设计出一种模糊算法,将错误的内容标准化,这样后面书面的质量也得到了提高。
至于测评表之间的数据迁移问题,当然是搁到下章啦︿( ̄︶ ̄)︿

3.细节截图:
①.目前还没有5级系统,所以下面增加5级的判断:

在这里插入图片描述
在这里插入图片描述

②.S4A1G4等级的系统运行截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

③.资产抽选说明(服务器):

在这里插入图片描述
在这里插入图片描述

④.项目工程的目录结构说明:

在这里插入图片描述

⑤.questionaire_basic.py介绍:

在这里插入图片描述
在这里插入图片描述

⑥.sag_and_assess.py介绍:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

⑦.小细节:

在这里插入图片描述

文章结语:小满

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值