一、日志模块,logging模块
1)logging模块简单使用,屏幕输出。默认级别30
import logging logging.debug('debug...') # 10 logging.info('info....') #20 logging.warning('可能着火...') #30 logging.error('着火啦快跑') # 40 logging.critical('火越烧越大') #50
2)控制日志输出到文件,但屏幕显示信息会消失。注意,存入文件时是以gbk,所以打开时,也要指定gbk格式
import logging # 控制日志输出 logging.basicConfig( filename='access.log', # 记录在当前目录,生成文件 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 时间 日志的名,如debug,error 级别 模块 # 接收的信息 datefmt='%Y-%m-%d %H:%M:%S %p', # 时间 level=20, ) logging.debug('debug...') # 10 logging.info('info....') #20 logging.warning('可能着火...') #30 logging.error('着火啦快跑') # 40 logging.critical('火越烧越大') #50
3)日志模块调用原理
import logging #logger对象:用来产生日志 logger1=logging.getLogger('银行业务相关') # 日志名是用告诉我们所记录的日志到底是属于哪一类业务相关的信息 #filter对象:过滤日志 #handler对象:控制日志的去向: 文件 或 终端 fh1=logging.FileHandler('a1.log',encoding='utf-8') fh2=logging.FileHandler('a2.log',encoding='utf-8') ch=logging.StreamHandler() #代表的就是终端 # 建立logger对象与handler对象的绑定关系 logger1.addHandler(fh1) logger1.addHandler(fh2) logger1.addHandler(ch) #formmatter对象:定制日志的格式 formatter1=logging.Formatter( fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p' ) formatter2=logging.Formatter( fmt='%(asctime)s ===> %(message)s', ) # 为handler对象绑定日志格式 fh1.setFormatter(formatter1) fh2.setFormatter(formatter2) ch.setFormatter(formatter2) #设置日志级别:两层关卡,第一次是logger,第二层是handler,只有两层都放行,最终日志才会打印 # logger1.setLevel(50) # fh1.setLevel(10) # fh2.setLevel(10) # ch.setLevel(10) logger1.setLevel(10) fh1.setLevel(10) fh2.setLevel(10) ch.setLevel(10) # 调用logger对象产生日志 logger1.debug('这是一条debug日志')
4)引用字典加载日志模块配置
日志配置文件,setting_log.py
import logging # 定义日志文件的保存路径 logfile_path=r'D:oldboyedumanth-02day-02a1.log' # 定义日志格式 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, }, 'filters': {}, 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到终端 'formatter': 'simple' }, #打印到文件的日志, 'default': { 'level': 'DEBUG', 'class': 'logging.FileHandler', # 保存到文件 # logging.handlers.RotatingFileHandler 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 'logger1': { 'handlers': ['default', 'console'], 'level': 'DEBUG', 'propagate': False, }, }, }
升级修改的配置文件,增加日志轮转的功能
'default': { 'level': 'DEBUG', # 'class': 'logging.FileHandler', # 保存到文件 # logging.handlers.RotatingFileHandler 'class': 'logging.handlers.RotatingFileHandler', 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024*1024*5, # 日志文件大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 },
功能调用日志模块配置文件
import logging.config from setting_log import LOGGING_DIC # 导入日志的配置文件 logging.config.dictConfig(LOGGING_DIC) logging1 = logging.getLogger('logger1') logging1.debug('调试日志')
5)升级版,新增配置日志文件,如boss的日志
import logging # 定义日志文件的保存路径 logfile_path=r'D:oldboyedumanth-02day-02a1.log' boss_logfile_path=r'D:oldboyedumanth-02day-02a2.log' # 定义日志格式 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' id_simple_format = '[%(asctime)s] %(message)s' # 给boss的日志,简单明了的日志 # log配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'id_simple': { 'format': id_simple_format } }, 'filters': {}, 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到终端 'formatter': 'simple' }, #打印到文件的日志, 'default': { 'level': 'DEBUG', 'class': 'logging.FileHandler', # 保存到文件 # logging.handlers.RotatingFileHandler 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, # 打印给boss的日志 'boss': { 'level': 'ERROR', 'class': 'logging.FileHandler', # 保存到文件 # logging.handlers.RotatingFileHandler 'formatter': 'id_simple', 'filename': boss_logfile_path, # 日志文件 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': { #logging.getLogger(__name__)拿到的logger配置 'logger1': { 'handlers': ['default', 'console','boss'], 'level': 'DEBUG', 'propagate': False, }, }, }
6)函数调用配置文件输出日志
def get_logger(logger_name): # 获取输入日志的信息 logging.config.dictConfig(settings.LOGGING_DIC) # 导入上面定义的settings配置 logger=logging.getLogger(logger_name) return logger logger=get_logger('logger1') def register(): logger.info('用户%s注册成功' %user) def info(): logger.info('用户%s登录成功' %user)
7)可实现任意log对象的配置,字典的key为空即可
'loggers': { #logging.getLogger(__name__)拿到的logger配置 '': { 'handlers': ['default', 'console'], 'level': 'DEBUG', 'propagate': False, }, },
8)扩展,log的日志格式
可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 #格式 %(name)s:Logger的名字,并非用户名,详细查看 %(levelno)s:数字形式的日志级别 %(levelname)s:文本形式的日志级别 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有 %(filename)s:调用日志输出函数的模块的文件名 %(module)s:调用日志输出函数的模块名 %(funcName)s:调用日志输出函数的函数名 %(lineno)d:调用日志输出函数的语句所在的代码行 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d:线程ID。可能没有 %(threadName)s:线程名。可能没有 %(process)d:进程ID。可能没有 %(message)s:用户输出的消息
二、跨平台序列化存储数据。json和pickle
1)序列化的概念,意义
01 什么是序列化 序列化:把内存中的数据转成一种中间格式(json/pickle),然后存放到硬盘中,永久保存 反序列化:从文件中读出(json/pickle)格式,然后返解成python的数据类型 02 为什么要序列化 1、数据结构持久化 2、跨平台数据交互 03 如何进行序列化,反序列化 json: 缺点: 只能支持部分python的数据类型 优点: 所有的语言都支持json格式 应用: 如果需要考虑跨平台性,则需要用json格式 pickle 缺点: 只有python支持pickle格式 优点: pickle能够支持所有的python数据类型 应用: 如果不需要考虑跨平台性,则可以用pickle格式
2)json支持转换python格式的类型
3)json序列化模块的使用
import json # dic={'name':'egon','age':18,'is_beautiful':True} # #序列化 # res=json.dumps(dic) # 强调,json格式不识别单引号 # # print(res,type(res)) # with open('user.json','w',encoding='utf-8') as f: # f.write(res) # 反序列化 # with open('user.json','r',encoding='utf-8') as f: # res=f.read() # dic=json.loads(res) # print(dic['name']) # 强调,json格式不识别单引号 # with open('user1.json','r',encoding='utf-8') as f: # res=f.read() # # dic=json.loads(res) # print(dic['x']) # #序列化 # dic={'name':'egon','age':18,'is_beautiful':True} # # with open('user2.json','w',encoding='utf-8') as f: # json.dump(dic,f) # 反序列化 with open('user.json','r',encoding='utf-8') as f: dic=json.load(f) print(dic['name'])
4)pickle用法和json一模一样
import json import pickle # 序列化 # pickle可以序列化任意python的数据类型 # print(json.dumps({1,2,3})) # print(pickle.dumps({1,2,3})) # dic={'name':'egon','age':18,'is_beautiful':True} # # res=pickle.dumps(dic) # with open('user3.pkl','wb') as f: # f.write(res) # 反序列化 # with open('user3.pkl','rb') as f: # res=f.read() # # dic=pickle.loads(res) # print(dic['name']) #简单写法 # # 序列化 # dic={'name':'egon','age':18,'is_beautiful':True} # with open('user4.pkl','wb') as f: # pickle.dump(dic,f) # 反序列化 with open('user4.pkl','rb') as f: dic=pickle.load(f) print(dic['name'])
三、hash加密模块
1)hash加密算法的用途
1、只要校验的文本内容一样,那么得到的hash值是相同===>校验文件的完整性 2、只要使用hash算法固定,无论校验的内容有多大,得到的hash值长度都是固定的(与上一条合到一起用) 3、hash不可以逆,即无法通过hash值反解出明文====》将明文转成密文进行传输
2)hash的各种用法
import hashlib # m=hashlib.md5() # 建造了一个hash工厂 # m.update(b'hello') # update接收的数据类型都必须是bytes类型 # m.update(b'world') # update接收的数据类型都必须是bytes类型 # m.update(b'egon') # update接收的数据类型都必须是bytes类型 # #b'helloworldegon' # print(m.hexdigest()) # m1=hashlib.md5() # 建造了一个hash工厂 # m1.update(b'hellowo') # update接收的数据类型都必须是bytes类型 # m1.update(b'rldegon') # update接收的数据类型都必须是bytes类型 # #b'helloworldegon' # print(m1.hexdigest()) # m2=hashlib.md5() # 建造了一个hash工厂 # m2.update(b'hellowo') # update接收的数据类型都必须是bytes类型 # m2.update(b'rldegon') # update接收的数据类型都必须是bytes类型 # m2.update(b'rldegon') # update接收的数据类型都必须是bytes类型 # print(m2.hexdigest()) #用途,验证文件 # import hashlib # m=hashlib.md5() # with open('1.flv','rb') as f: # # for line in f: # # m.update(line) # m.update(f.read()) # print(m.hexdigest()) # 升级加密,密码写在中间 # import hashlib # password='alex3714' # m=hashlib.md5() # m.update('天王盖地虎'.encode('utf-8')) # m.update(password.encode('utf-8')) # m.update('小鸡炖蘑菇'.encode('utf-8')) # pwd_md5=m.hexdigest() # print(pwd_md5) # 查看hash的各个加密方法的难易度 # import hashlib # m0=hashlib.md5() # m0.update('hello'.encode('utf-8')) # print(m0.hexdigest()) # # m1=hashlib.sha256() # m1.update('hello'.encode('utf-8')) # print(m1.hexdigest()) # # m2=hashlib.sha512() # m2.update('hello'.encode('utf-8')) # print(m2.hexdigest()) # 了解 import hmac m=hmac.new('天王盖地虎'.encode('utf-8')) m.update(b'hello') m.update(b'world') print(m.hexdigest())
3)模拟撞库
import hashlib passwds=[ 'alex3714', 'alex1313', 'alex94139413', 'alex123456', '123456alex', 'a123lex', ] def make_passwd_dic(passwds): dic={} for passwd in passwds: m=hashlib.md5() m.update(passwd.encode('utf-8')) dic[passwd]=m.hexdigest() return dic def break_code(cryptograph,passwd_dic): for k,v in passwd_dic.items(): if v == cryptograph: print('密码是===>