zoukankan      html  css  js  c++  java
  • 提取excel表数据成json格式的以及对图片重命名

    开发那边的需求



    1、功夫熊猫以及阿狸布塔故事集都是属于剧集的。意思就是有很多集,这里称他们为tv
    最下面这几行第一列没名字的都是单集的,这里称它们为mv
    需要统计所有工作表里面的数据把tv放一个大的json里面
    把mv放一个大的json里面


    2、需要检索图片名列。然后检测文件夹里面是否有对应的图片。
    同时把图片提取首字母并生成新文件名
    比如
    功夫熊猫.jpg 会变成 tv_gfxm.jpg
    必备古诗.jpg 会变成 mv_gfxm.jpg

    下面是最终效果图
    这是单个mv的数据和字段

    下面是一个tv

    功能实现


     这里没使用到uuid。本来想把它当做一个key的。后面发现不需要

    # -*- coding: utf-8 -*-
    import xlrd
    import uuid
    import re,time,json,shutil,os
    
    #临时存放所有单集
    mv_list=[]
    #临时存放剧集,后面调用format_tv方法存成tv_dict
    tv_list=[]
    
    #tv_dict是所有剧集,key是首字母缩写,值是列表,列表每个元素是剧集的一行
    tv_dict={}
    
    #图片集合,后期用来给图片重命名使用
    pic_list=[]
    
    exec_log=open('执行日志.log','a',encoding='utf-8')# 追加模式
    error_log=open('错误日志.log','a',encoding='utf-8')# 追加模式
    #获取excel表中需要提取的视频文件名列表,返回值是个excel句柄
    def OpenExcel(excel_file):
        try:
            dataHandle = xlrd.open_workbook(excel_file)
            return dataHandle
        except Exception as ex:
            print(str(ex))
            error_log.write('打开excel表失败,可能---'+excel_file+'---并不存在
    ')
            error_log.close()
            exit(1)
    
    #读取excel数据
    def ReadExcel(excel_file):
        workbook=OpenExcel(excel_file)
        exec_log.write("正在读取excel表内容")
        print('打印所有sheet:', workbook.sheet_names())
        #工作表个数
        sheet_name_list=workbook.sheet_names()
        sheet_count=len(workbook.sheet_names())
        print("excel表sheet个数:",sheet_count)
        exec_log.write("准备循环excel每个工作表..
    ")
        for i in range(sheet_count):
            current_sheet = workbook.sheet_by_index(i)  # sheet索引从0开始
            rows_num = current_sheet.nrows
            cols_num = current_sheet.ncols
            print("当前sheet的名字是:%s  行数:%s   列数:%s:"%(sheet_name_list[i],rows_num,cols_num))
            print("#####################################################")
            for r in range(1,rows_num):
                # 一行数据的实体
                entity_dict = {}
                for c in range(0,cols_num):
                    cell_value=get_value_and_get_int(current_sheet,r,c)
                    #这里如果单元格内容为空或者是None的话,再次判断是是否属于合并单元格
                    if (cell_value is None or cell_value == ''):
                        cell_value = (get_merged_cells_value(current_sheet, r, c))
                    the_key = 'colnum' + str(c + 1)
                    entity_dict[the_key] = cell_value
                #第7列判断是否有空格
                if entity_dict["colnum7"] is None or entity_dict['colnum7'] == '':
                    error_log.write("遇到图片所在列为空值的情况,无法对空值处理,格式异常位置为,3秒后退出
    ")
                    exec_log.write("当前sheet的名字是:%s  行数:%s "%(sheet_name_list[i],r))
                    exec_log.close()
                    print("遇到图片所在列为空值的情况,无法对空值处理,格式异常位置为,3秒后退出")
                    print("当前sheet的名字是:%s  行数:%s "%(sheet_name_list[i],r))
                    time.sleep(3)
                    exit(1)
                #第7列去掉空格,因为要把图片转成首字母
                entity_dict["colnum7"].replace(' ','')
                if entity_dict['colnum1'] is None or entity_dict['colnum1'] == '':
                    mv_list.append(entity_dict)
                else:
                    tv_list.append(entity_dict)
        exec_log.write("循环所有工作表完毕,已经追加到单集列表和剧集列表..暂未生成图片列
    ")
    
    
    #处理单元格值中的int类型,因为xlrd模块会把int自动转成了float,再改回去
    def get_value_and_get_int(sheet,r,c):
        cell_value = sheet.row_values(r)[c]
        # 这由于xlrd会把int类型自动转存float,这里做一个处理,把它再转回int类型
        cell_type = sheet.cell(r,c).ctype  # 表格的数据类型
        if cell_type == 2 and cell_value % 1 == 0.0:  # ctype为2且为浮点
            cell_value = int(cell_value)  # 浮点转成整型
        return cell_value
    
    #找到所有合并单元格的坐标(上下左右)
    def get_merged_cells(sheet):
        """
        获取所有的合并单元格,格式如下:
        [(4, 5, 2, 4), (5, 6, 2, 4), (1, 4, 3, 4)]
        (4, 5, 2, 4) 的含义为:行 从下标4开始,到下标5(不包含)  列 从下标2开始,到下标4(不包含),为合并单元格
        :param sheet:
        :return:
        """
        return sheet.merged_cells
    
    # 获取单元格的值
    def get_merged_cells_value(sheet, row_index, col_index):
        """
        先判断给定的单元格,是否属于合并单元格;
        如果是合并单元格,就返回合并单元格的内容
        :return:
        """
        merged = get_merged_cells(sheet)
        for (rlow, rhigh, clow, chigh) in merged:
            if (row_index >= rlow and row_index < rhigh) and (col_index >= clow and col_index < chigh) :
                cell_value = sheet.cell_value(rlow, clow)
                # print('该单元格[%d,%d]属于合并单元格,值为[%s]' % (row_index, col_index, cell_value))
                return cell_value
                # print(cell_value)
        # return None
    
    
    def getUUID():
        return uuid.uuid1().hex
    
    #去除标点符号
    def remove_punctuation(str):
        new_str=re.sub('[^wu4e00-u9fff]+', '',str)
        return new_str
    
    #获取单个汉字的首字母
    def single_get_first(unicode1):
        str1 = unicode1.encode('gbk')
        try:
            ord(str1)
            return str1
        except:
            asc = str1[0] * 256 + str1[1] - 65536
            if asc >= -20319 and asc <= -20284:
                return 'a'
            if asc >= -20283 and asc <= -19776:
                return 'b'
            if asc >= -19775 and asc <= -19219:
                return 'c'
            if asc >= -19218 and asc <= -18711:
                return 'd'
            if asc >= -18710 and asc <= -18527:
                return 'e'
            if asc >= -18526 and asc <= -18240:
                return 'f'
            if asc >= -18239 and asc <= -17923:
                return 'g'
            if asc >= -17922 and asc <= -17418:
                return 'h'
            if asc >= -17417 and asc <= -16475:
                return 'j'
            if asc >= -16474 and asc <= -16213:
                return 'k'
            if asc >= -16212 and asc <= -15641:
                return 'l'
            if asc >= -15640 and asc <= -15166:
                return 'm'
            if asc >= -15165 and asc <= -14923:
                return 'n'
            if asc >= -14922 and asc <= -14915:
                return 'o'
            if asc >= -14914 and asc <= -14631:
                return 'p'
            if asc >= -14630 and asc <= -14150:
                return 'q'
            if asc >= -14149 and asc <= -14091:
                return 'r'
            if asc >= -14090 and asc <= -13119:
                return 's'
            if asc >= -13118 and asc <= -12839:
                return 't'
            if asc >= -12838 and asc <= -12557:
                return 'w'
            if asc >= -12556 and asc <= -11848:
                return 'x'
            if asc >= -11847 and asc <= -11056:
                return 'y'
            if asc >= -11055 and asc <= -10247:
                return 'z'
            return ''
    
    #获取每个汉字每个首字母并返回英文首字母字符串
    def getPinyin(str):
        if str==None:
            return None
        str_list = list(str)
        charLst = []
        for item in str_list:
            charLst.append(single_get_first(item))
        return  ''.join(charLst)
    
    #拷贝文件
    def copy_file(source_file,target_file):
        if os.path.exists(source_file) and not os.path.exists(target_file):
            shutil.copy(source_file,target_file)
        else:
            error_log.write("下面路径文件不存在: %s
    "%(source_file))
            print("下面路径文件不存在: %s"%(source_file))
            time.sleep(0.1)
    
    #处理图片列表[[pic1,tar1],[pic2,tar2],去重并且调用拷贝文件方式拷贝为新文件
    def copy_file_from_list(pic_list):
        #对列表去重,这里无法使用set,因为set无法对子元素为列表的元素做hash
        new_pic_list=[]
        for item in pic_list:
            if item not in new_pic_list:
               new_pic_list.append(item)
        for item in new_pic_list:
            copy_file(item[0],item[1])
    
    
    
    
    
    
    
    #给单集新增加一列key,值是图片列的英文首字母加上路径名拼接字符串,比如"excel_pic_dir/mv_hj.jpg" 这种格式
    def add_pic_col_for_mv(mv_list):
        exec_log.write("给单集列表生成图片路径列excel_pic_dir/mv_hj.jpg 这种格式
    ")
        for item in mv_list:
            #格式化汉字字符串,去掉特殊符号
            temp_str=remove_punctuation(item['colnum7'])
            #获取首字母字符串
            temp_letter=getPinyin(temp_str)
            # print(item['colnum7'])
            # temp_letter=getPinyin(temp_letter)
            # temp_letter=getPinyin(item['colnum7'])
            # print(temp_letter)
            #拼接为图片路径,一个放到图片集合中给后面重命名使用,一份直接增加到excel行字典中
            source_file="excel_pic_dir/"+temp_str+".jpg"
            target_file="excel_pic_dir/mv_"+temp_letter+".jpg"
            pic_list.append([source_file,target_file])
            # copy_file(source_file,target_file)
            item["pic_path"]=target_file
        exec_log.write("给单集列表生成图片路径列完毕
    ")
    
    
    
    #给剧集新增加一列key,值是图片列的英文首字母加上路径名拼接字符串,比如"excel_pic_dir/tv_hj.jpg" 这种格式
    def add_pic_col_for_tv(tv_list):
        exec_log.write("给剧集列表生成图片路径列excel_pic_dir/mv_hj.jpg 这种格式
    ")
        for item in tv_list:
            #格式化汉字字符串,去掉特殊符号
            temp_str=remove_punctuation(item['colnum7'])
            #获取首字母字符串
            temp_letter=getPinyin(temp_str)
            #拼接为图片路径
            source_file="excel_pic_dir/"+temp_str+".jpg"
            target_file="excel_pic_dir/tv_"+temp_letter+".jpg"
            #拼接为图片路径,一个放到图片集合中给后面重命名使用,一份直接增加到excel行字典中
            pic_list.append([source_file,target_file])
            # copy_file(source_file,target_file)
            # temp_path="excel_pic_dir/tv_"+temp_letter+".jpg"
            item["pic_path"]=target_file
        exec_log.write("给剧集列表生成图片路径列完毕
    ")
    
    
    #把剧集的都放在一个字典中,key是剧集首字母,value是剧集列表
    def format_tv(tv_list):
        # tv_dict={}
        exec_log.write("把剧集的都放在一个大字典中,key是剧集首字母,value是剧集列表
    ")
        for tv_item in tv_list:
            #先获取字符串,去掉标点符号
            temp_str=remove_punctuation(tv_item['colnum1'])
            #获取首字母字符串
            temp_key=getPinyin(temp_str)
            if temp_key in tv_dict:
                tv_dict[temp_key].append(tv_item)
            else:
                tv_dict[temp_key]=[]
                tv_dict[temp_key].append(tv_item)
        exec_log.write("把剧集的都放在一个大字典中完毕
    ")
    
    if __name__ == "__main__":
        ReadExcel("001.xlsx")
        # print(mv_list[0])
        add_pic_col_for_mv(mv_list)
        add_pic_col_for_tv(tv_list)
        format_tv(tv_list)
        copy_file_from_list(pic_list)
        print("单集个数:",len(mv_list))
        print("剧集套数:",len(tv_dict))
    
    # print(mv_list[0])
    # for k,v in tv_dict.items():
    #     print(k,v)
    #     break
    
    
    #获取单集最终字典列表
    programMovieList=[]
    for item in mv_list:
        new_item={}
        new_item["programName"]=item["colnum3"]
        new_item["programYear"]=""
        new_item["programType"]=""
        new_item["programDirector"]=""
        new_item["programActor"]=""
        new_item["programPoster"]=item["pic_path"]
        new_item["programIntroduce"]=item["colnum5"]
        new_item["sitnum"]=0
        new_item["code"]=item["colnum2"]
        new_item["cpCode"]=item["colnum6"]
        programMovieList.append(new_item)
    exec_log.write("单集最终字典列表获取完毕
    ")
    
    exec_log.write("开始dump---单集---数据到json文件中
    ")
    with open('mv.json', 'w',encoding='utf-8') as f_mv:
        json.dump(programMovieList, f_mv,ensure_ascii=False,sort_keys=True, indent=4)
    exec_log.write("dump---单集---数据完毕
    ")
    print("dump---单集---数据完毕..")
    time.sleep(2)
    
    
    def get_seriesList(item_list):
        seriesList=[]
        for item in item_list:
            new_item={}
            new_item["programName"]=item["colnum3"]
            new_item["code"]=item["colnum2"]
            seriesList.append(new_item)
        return seriesList
    #获取剧集最终字典列表
    programTvList=[]
    for item in tv_dict:
        new_item={}
        # print(item)
        new_item["programName"]=tv_dict[item][0]["colnum1"]
        new_item["programYear"]=""
        new_item["programType"]=""
        new_item["programDirector"]=""
        new_item["programActor"]=""
        new_item["programPoster"]=tv_dict[item][0]["pic_path"]
        new_item["programIntroduce"]=tv_dict[item][0]["colnum5"]
        new_item["sitnum"]=len(tv_dict[item])
        new_item["cpCode"]=tv_dict[item][0]["colnum6"]
        new_item["recommend"]=""
        new_item["seriesList"]=get_seriesList(tv_dict[item])
        programTvList.append(new_item)
        # for k,v in new_item.items():
        #     print("""+k+""",v)
    #indent参数是缩进的意思,它可以使得数据存储的格式变得更加优雅。
        # with open('data.json', 'w',encoding='utf-8') as f:
        #     json.dump(new_item, f,sort_keys=True, indent=4)
    exec_log.write("开始dump---剧集---数据到json文件中
    ")
    with open('tv.json', 'w',encoding='utf-8') as f_tv:
        json.dump(programTvList, f_tv,ensure_ascii=False,sort_keys=True, indent=4)
    exec_log.write("dump---剧集---数据完毕
    ")
    print("dump---剧集---数据完毕..")
    print("程序执行完毕,2秒后退出..")
    error_log.close()
    exec_log.close()
    time.sleep(2)
    

      

     最后打包成exe交给开发那边

    把使用说明告诉开发即可

     

     

     运行结果

     

  • 相关阅读:
    MySql创建库 Challenge
    未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值的解决办法.
    小总结:用反射机制创建的分配数据分配器
    工厂模式的反思
    单机安装“完整”SharePoint 2010
    作业调度框架 Quartz.NET 2.0 StepByStep(2)
    UI线程同步
    每日见闻(一)
    作业调度框架 Quartz.NET 2.0 StepByStep
    基础算法(ACwing)
  • 原文地址:https://www.cnblogs.com/nmap/p/10474142.html
Copyright © 2011-2022 走看看