最近工作中使用Python进行了大量的自动化工具的开发,剖除业务逻辑,记录一些要点。
持续更新, 一些pythonic技巧容易遗忘~
文件及路径相关操作
-
涉及模块: os模块 shutil模块
import os import shutil
-
常用接口
os.getcwd() # 当前Python脚本工作的目录路径 os.path.abspath(path) # 获取path路径的绝对路径 os.chdir(path) # 切换路径到path os.listdir() # 返回指定目录下的所有文件和目录名 os.remove() # 删除文件 os.removedirs(r“c:\python”) # 删除目录 os.path.isdir() # 检查是否是一个目录 os.path.exists() # 检查路径是否存在 os.rename() # 文件重命名 os.path.split('/home/code/test.txt') # 拆分一个路径的目录名和文件名,eg结果:('/home/code', 'test.txt') os.path.dirname() # 获取路径名 os.path.join() # 用于路径拼接,将多个路径组合后返回路径字符串 os.makedir()/os.makedirs() #创建单级目录 / 创建多级目录(递归) os.chmod() # 修改文件权限 os.path.getsize() # 获取文件大小 os.system() # 运行shell命令 os.getenv() 与os.putenv() # 读取或设置环境变量 fp = open("test.txt", w) #直接打开一个文件,如果文件不存在则创建文件 fp.read(size) # size为读取的长度,以byte为单位 fp.readlines([size]) # 把文件每一行作为一个list的一个成员,并返回这个list fp.write(str) # 把str写到文件中,write()并不会在str后加上一个换行符 fp.writelines(seq) # 多行一次性写入 shutil.copyfile("oldfile","newfile") # 拷贝文件:oldfile和newfile都只能是文件 shutil.copytree("olddir","newdir") # 拷贝文件夹:olddir和newdir都只能是目录,且newdir必须不存在
-
常规操作
-
路径遍历
# 遍历路径文件并过滤文件名 for dirpath, dirnames, filenames in os.walk(path): for name in filenames: if name.endswith('.dat'): print(name) # 通过递归遍历所有文件并返回list def autotool_fileScan_childpath(path, allFiles): file_list = os.listdir(path) for file in file_list: cur_path = os.path.join(path, file) if os.path.isdir(cur_path): autotool_fileScan_childpath(cur_path, allFiles) else: allFiles.append(file) return allFiles
-
正则表达式
-
相比于各类模糊匹配算法,正则表达式是最通用的字符串匹配方法,常用于:
- 日志等各类文本搜索
- 文件目录/文件名过滤
- 用户输入检查
- …
-
优点:万能,目前没有遇到无法适应的场景
-
缺点:效率问题,对于大数据量的匹配,建议模糊匹配+正则匹配进行二级梯度搭配,如动辄几个G的日志文件可以先find关键字过滤,然后正则精确匹配
-
示例:文件名过滤
-
文件名格式如下:
-
代码:
class Reg(object): def __init__(self): self.match = None self.pattern = None def reg_match(self, string): if self.pattern: self.match = self.pattern.match(string) return self.match class BMPReg(Reg): def __init__(self): Reg.__init__(self) self.pattern = re.compile(r'^(?P<timestamp>\S+?)_(?P<retry>\w{6})_(?P<result>\S+)_(?P<fake_result>(nlf|liv))_(\d+)_e-(\S+).dat$') def timestamp(self): print('timestamp:' + self.match.group('timestamp')) return self.match.group('timestamp') def retry(self): print('retry:' + self.match.group('retry')) return self.match.group('retry') def result(self): print('result:' + self.match.group('result')) return self.match.group('result') def fake_result(self): print('fake_result:' + self.match.group('fake_result')) return self.match.group('fake_result')
-
数据格式转换
-
自动化工具中数据转换往往是重要的一环,涉及文件名搜索,格式转换,加解密等
-
示例1:csv转bin
def csv2bin(self, filename): out_filename = filename[0:len(filename) - 4] + '.raw' temp_name = self.convertfilename(out_filename.split('/')[-1]) if temp_name: out_filename = out_filename.replace(out_filename.split('/')[-1], temp_name) c = open(out_filename, 'wb') reader = csv.reader(open(filename, 'r')) for row in reader: for data in row: b = struct.pack('i', int(data)) c.write(b) c.close() os.remove(filename)
-
示例2:bmp转bin
def bmp2bin(self, filename): out_filename = filename[0:len(filename) - 4] + '.raw' temp_name = self.convertfilename(out_filename.split('/')[-1]) if temp_name: out_filename = out_filename.replace(out_filename.split('/')[-1], temp_name) if out_filename: im = Image.open(filename) img = np.array(im) open(out_filename, "wb").write(img) os.remove(filename)
-
示例3:dict转json存储
-
dict构造多级{key, value},利用json库能直接生成嵌套json格式的字符串,key: { value }
def updateDict(self, root): self.dict.setdefault('version', 1) self.dict.setdefault('suffix', {}).setdefault('bmp_path', 'bm/Sa/%s') self.dict.setdefault('suffix', {}).setdefault('raw_path', 'Ra/Sa/%s'') def saveDictToJson(self, path_root): json_data = json.dumps(self.dict, sort_keys=False, indent=4, separators=(',', ':')) jfile = open(path_root + '/' + save_json_file_name, 'w') jfile.write(json_data) jfile.close()
-
数据分析神器Pandas
-
盘点pandas中常用的方法
df.head(n) # 查看数据的前n行 df.tail(n) # 查看数据的后n行 df.shape() # 查看数据的形状 df.info() # 查看数据索引,类型,内存信息 df.describe() # 查看数据汇总统计信息 df['colname'].value_counts(dropna=False) # 查看某一列的统计值 df['colname'].unique() # 查看某一列不重复值 df['user_id'] # 查看某一列 df[['user_id', 'item_id']] # 查看多列 df.iloc[0, 0] # 定位某行某列的的值,按索引 df.at['rowname']['colname'] # 定位某行某列的值,按行列名 df.sort_values(by='colname', ascending=True) # 按照colname列升序排序 df.append() / df.concat() / df.merge() # 数据合并
-
示例1:从dict按列构造dataframe
self.auth_analysis_dataframe = pd.DataFrame.from_dict(data=self.auth_analysis_dict, orient='index') self.auth_analysis_dataframe = self.auth_analysis_dataframe.reindex(index=index_names) self.auth_analysis_dataframe.columns = column_names # 重命名里
-
示例2:从dict按行构造dataframe,并添加求和的列
self.analysis_dataframe_out = pd.DataFrame(out_dict, columns=out_columns, index=out_index) # add total time self.analysis_dataframe_out['total'] = self.analysis_dataframe_out.apply(lambda x: x.sum(), axis=1)
-
示例3:按列遍历dataframe,convert ‘0’ to ‘<1 ms’
time_convert_excep = ['timestamp', 'retry_index', 'idle_check_times'] for col in dataframe.columns: time_convert_filter = col not in time_convert_excep and row[col] == '0' if time_convert_filter: row[col] = '<1 ms' else: pass
-
示例4:深拷贝一个dataframe,按行遍历并删除一些行
df = copy.deepcopy(dataframe) for index, row in df.iterrows(): if row['retry_index'] != 0 or row['result'] != 'fail': df.drop(labels=index, inplace=True)
-
示例5:dataframe某一列“fusion”数据格式为“a1;a2;a3”,将该列拆分并按原序拼接到dataframe,删除该列
dataframe_handle = pd.concat( [dataframe_handle, dataframe_handle['fusion'].str.split(';', expand=True)],axis=1) del dataframe_handle['fusion']
-
示例6:dataframe根据某一列的值分组拆分成多个子dataframe,存放到sub_df_list中
# 按'bright'拆分dataframe
sub_df_list = []
bright_list = df['bright'].unique()
for bright in bright_list:
temp_df = df[df['bright'].isin([bright])]
sub_df = temp_df.reset_index(drop=True)
sub_df_list.append(sub_df)
数据报表
-
第三方excel库
import openpyxl as xl
-
操作excel表前建议用pandas的dataframe整理和处理数据,然后从dataframe创建表格
-
示例:自己封装的excel相关工具类,简化后的版本
class ExcelDisplayUtil: @staticmethod def create_sheet(excel_filename): # create an excel file workbook = xl.Workbook() # get the first active sheet sheet = workbook.active sheet.title = excel_filename dt = datetime.now() excel_filename += '_' + dt.strftime('%y-%m-%d %I:%M:%S') + '.xlsx' workbook.save(excel_filename) return excel_filename @staticmethod def sheet_set_title_format(sheet): # set title row font sheet.row_dimensions[1].font = Font(name=u'宋体', size=12, bold=True) # set row width sheet.row_dimensions[1].height = 40 @staticmethod def sheet_set_content_format(sheet): # set font maxContentRow = len(sheet.row_dimensions) for i in range(2, maxContentRow): row = sheet.row_dimensions[i] row.font = Font(name=u'宋体', size=10) # begin to set adaptive col width col_width = [] # get max width of each col i = 0 for col in sheet.columns: for j in range(len(col)): if j == 0: col_width.append(len(str(col[j].value))) else: if col_width[i] < len(str(col[j].value)): col_width[i] = len(str(col[j].value)) i = i + 1 # set col width for i in range(len(col_width)): col_letter = xl.utils.get_column_letter(i + 1) if col_width[i] > 150: sheet.column_dimensions[col_letter].width = 150 elif col_width[i] > 5: sheet.column_dimensions[col_letter].width = col_width[i] + 2 @staticmethod def sheet_load_dataframe(excel_filename, sheet_name, df): writer = pd.ExcelWriter(excel_filename, engine='openpyxl') book = xl.load_workbook(writer.path) writer.book = book df.to_excel(excel_writer=writer, sheet_name=sheet_name) writer.save() writer.close() @staticmethod def sheet_load_dataframe_double(excel_filename, sheet_name1, df1, sheet_name2, df2): writer = pd.ExcelWriter(excel_filename, engine='openpyxl') if not os.path.exists(excel_filename): df1.to_excel(excel_writer=writer, sheet_name=sheet_name1) else: book = xl.load_workbook(writer.path) writer.book = book df2.to_excel(excel_writer=writer, sheet_name=sheet_name2) writer.save() writer.close()
-