logging模块 (日志模块),configparser模块(软件配置文件操作模块)hashlib模块(哈希模块)
logging模块
logging.debug<logging.info<logging.warning<logging.error<logging.critical
以上是日志的级别,为啥要有级别呢?因为我们在处理日志的时候不会说将所有的内容都操作,而是可能只操作某个级别的内容,所有这就很有必要在日志中分级别了
import logging logging.debug('level debug') logging.info('level info') logging.warning('level warning') logging.error('level error') logging.critical('level critical') 结果 WARNING:root:level warning ERROR:root:level error CRITICAL:root:level critical 如果不对logging的参数进行配置,则会有默认的参数,比如这里,默认是级别大于等于 warning 的才会操作,并且是默认 stream(意思是在屏幕里输出,还有一个模式是 file 意思是 将内容写入日志文件当中) 内容的格式是 级别:用户:内容 (这里用户没有给参数,默认是根用户) import logging logging.basicConfig( //对logging的参数进行调整的方法 level=logging.DEBUG, //调整操作等级,默认是大于等于 warning filename='logger.log', //改变流操作为文件操作 (用basicConfig方法无法做到即是流操作用文件操作,也就是无法既在屏幕输出又写进文件里) filemode='w', //改变文件的写模式,默认是追加模式,现在这里变成 "w" 模式 format='%(asctime)s %(filename)s[%(lineno)d] %(levelname)s:%(name)s:%(message)s' //format()方法就牛逼了,改变日志的格式,有固定的写法 %()s/d 如%(asctime)s是时间:2018-08-27 13:47:04,608 逗号后面的数字是毫秒级的(我猜测是处理时间) //%(filename)s是在哪个文件进行的操作就将该文件的名字表示出来 4.py 在这个文件里进行的操作,所以将其写入日志中(可能是方便以后查找) //%(lineno)d表示写这条日志的代码在文件里的第几行(可能也是方便以后更改) //%(levelname)s就是操作的级别名称啦,%(name)s用户的名字,默认是根用户,%(message)s就是内容 //会以上这些就差不多啦,其实还有很多别的,只是目前来说会这些就够用了 ) logging.debug('level debug') logging.info('level info') logging.warning('level warning') logging.error('level error') logging.critical('level critical') 结果 2018-08-27 13:47:04,608 4.py[93] DEBUG:root:level debug 2018-08-27 13:47:04,608 4.py[94] INFO:root:level info 2018-08-27 13:47:04,608 4.py[95] WARNING:root:level warning 2018-08-27 13:47:04,608 4.py[96] ERROR:root:level error 2018-08-27 13:47:04,608 4.py[97] CRITICAL:root:level critical
下面的方法更常用,因为用起来更灵活
import logging logger = logging.getLogger() //获得一个logging对象,这个对象是大哥大,后面就靠他来写日志了 fh = logging.FileHandler('logger.log-new')//获取文件流对象 ch = logging.StreamHandler()//获取控制台流对象 fm = logging.Formatter('%(asctime)s %(filename)s[%(lineno)d] %(levelname)s:%(name)s:%(message)s')//获取设置的格式 fh.setFormatter(fm)//让文件流对象“吸收”自定义的日志格式 因为这些流对象其实就是要在哪里操作日志,这个是在文件里操作,下面的是在控制台里操作,既然是写日志那就要有格式 ch.setFormatter(fm) # ch.setLevel(logging.ERROR) # fh.setLevel('DEBUG') logger.addHandler(fh)//让日志对象 logger “吸收” 文件流,就是说最后通过 logger对象写日志时要在哪个流写,可以有多个流,例如下面就是 logger.addHandler(ch) logger.setLevel(logging.DEBUG)//设置logger大哥大写日志时的等级 logger.debug('level debug')//下面这些就是用过logger大哥大写日志用的操作 logger.info('level info') logger.warning('level warning') logger.error('level error') logger.critical('level critical') 结果 8-08-27 16:56:59,191 4.py[117] DEBUG:root:level debug//因为在写获取大哥大对象logger时没有指定用户,所以默认是根用户 2018-08-27 16:56:59,192 4.py[118] INFO:root:level info 2018-08-27 16:56:59,192 4.py[119] WARNING:root:level warning 2018-08-27 16:56:59,192 4.py[120] ERROR:root:level error 2018-08-27 16:56:59,192 4.py[121] CRITICAL:root:level critical
有一点要注意的是
import logging logger1 = logging.getLogger('mylogger')//在这里就创建根用户下的子用户 mylogger 了 logger2 = logging.getLogger('mylogger') fh = logging.FileHandler('logger--new') ch = logging.StreamHandler() fm = logging.Formatter('%(asctime)s %(filename)s[%(lineno)d] %(levelname)s:%(name)s:%(message)s') fh.setFormatter(fm) ch.setFormatter(fm) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(ch) logger2.addHandler(fh) logger1.setLevel('INFO') logger2.setLevel('DEBUG') logger1.debug('1:level debug') logger1.info('1:level info') logger1.warning('1:level warning') logger1.error('1:level error') logger1.critical('1:level critical') logger2.debug('2:level debug') logger2.info('2:level info') logger2.warning('2:level warning') logger2.error('2:level error') logger2.critical('2:level critical') 结果 2018-08-27 17:12:48,931 4.py[144] DEBUG:mylogger:1:level debug 2018-08-27 17:12:48,932 4.py[145] INFO:mylogger:1:level info 2018-08-27 17:12:48,932 4.py[146] WARNING:mylogger:1:level warning 2018-08-27 17:12:48,932 4.py[147] ERROR:mylogger:1:level error 2018-08-27 17:12:48,932 4.py[148] CRITICAL:mylogger:1:level critical 2018-08-27 17:12:48,933 4.py[150] DEBUG:mylogger:2:level debug 2018-08-27 17:12:48,933 4.py[151] INFO:mylogger:2:level info 2018-08-27 17:12:48,933 4.py[152] WARNING:mylogger:2:level warning 2018-08-27 17:12:48,933 4.py[153] ERROR:mylogger:2:level error 2018-08-27 17:12:48,933 4.py[154] CRITICAL:mylogger:2:level critical 我知道你肯定很迷惑,明明 logger1 的级别是 INFO 为啥会变成了 DEBUG ,因为呀logger1和logger2的用户都是mylogger,在第一次获得logger1的时候子用户mylogger已经创建 出来了,所以你下面logger2又是用子用户mylogger时,且logger2是从DEBUG开始,连带的logger1也从DEBUG开始了
configparser模块
这个模块是干啥的呢?其实是拿来操作软件的配置文件的,配置文件是啥呢?其实就是一个文件里有很多块,每一块都有一个标题,在每一块里又有许多的键值对,人狠话不多,直接上代码
----> 创建一个配置文件
import configparser config = configparser.ConfigParser()//获取该模块的一个操作对象 config['DEFAULT'] ={ //['DEFAULT']是一块信息的标题,'DEFAULT'是很特殊的一块信息,直接赋个字典来,字典里的键值对就会变成配置文件里的键值对 "ServerAliveInterval":'45', "Compression ":'yes', 'CompressionLevel':'9', 'ForwardXll':'yes' } config['bitbucket.org'] = {} //这是写一块信息的另一个方法,先创建一个标题,标题下面啥键值对都没有 config['bitbucket.org']['User'] = 'hg' //在这里再写入键值对 config['djh.org'] = {} //和上面的方法差不多,先创建一个标题,然后将这个标题赋值给一个变量,通过变量来操作写信息 tmp = config['djh.org'] tmp['age'] = '19' tmp['sex'] = 'man' with open('confile-new','w',encoding='utf-8') as f: config.write(f) //因为你搞了这么多都只是在内存里搞,要把它实实在在的写入某个文件里才ok,只不过这里的写入文件和文件操作里的写文件不太一样,是在操作对象里用 //write,然后在把文件句柄传进去
-----------------------------查找-------------------------------------------------
import configparser config = configparser.ConfigParser()//同样的,先获取操作对象 config.read('confile-new')//将这个对象和某个要操作的配置文件关联起来 print(config.sections())//输出该配置文件的所有信息块的标题标题,返回一个列表,注意 DEFAULT 信息块不会返回,这个比较特殊 print('bitbucket.org' in config)//判断'bitbucket.org'是否在配置文件里 (是否是配置文件的信息块的标题) print(config['bitbucket.org']['user'])//取标题为'bitbucket.org'的信息块下的键为'user'的键值对的值 print(config['bitbucket.org']['USER'])//标题区分大小写,键不区分大小写 for each in config['djh.org']://获取标题为'djh.org'的信息块的所有键值对的键,特殊的,也会同时获取 DEFAULT 信息块的所有键 print(each) print(config.options('djh.org'))//获取标题为'djh.org'的信息块的所有键值对的键值,以列表的形式返回,当然也会同时获取 DEFAULT 信息块的所有键 print(config.items('djh.org'))//获取标题为'djh.org'的信息块的所有键值对,以列表的形式返回,元素是二元组,当然也会同时获取 DEFAULT 信息块的所有键 print(config.get('djh.org','age'))//连续取值,取标题为'djh.org'的信息块下键值为'age'的键值对的值,相当于config['djh.org']['age'] 结果 ['bitbucket.org', 'djh.org'] True hg hg age sex serveraliveinterval compression compressionlevel forwardxll ['age', 'sex', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardxll'] [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardxll', 'yes'), ('age', '19'), ('sex', 'man')] 19
---------------------增、删------------------------------------------
import configparser config = configparser.ConfigParser()//创建一个操作对象 config.read('confile-new')//将操作对象和某个配置文件关联,并且将整个配置文件读取进内存中 config.add_section('DJH.org')//追加一个信息块,标题为"DJH.org" config.set('DJH.org','name','大帅哥')//在某个信息块里加上键值对,第二个参数为键,第三个参数为值 # config['DJH.org']={//其实上面添加一个新的信息块完全可以用创建一个配置文件时的语法 # 'name':"大帅哥" # } # config['djh.org'] = {//在已有的信息块里添加新的键值对,这样做是添加不了的,只会全部修改直接覆盖 # 'name':"大帅哥" # } config.set('djh.org','name','大帅哥')//在已有的信息块里添加新的键值对只可以这样做 with open('confile-new','w',encoding ='utf-8') as f://最后,你在内存里对配置文件修改了,但是在硬盘里没有修改,所以需要最后刷新进硬盘 config.write(f) 结果 [DEFAULT] serveraliveinterval = 45 compression = yes compressionlevel = 9 forwardxll = yes [bitbucket.org] user = hg [djh.org] age = 19 sex = man name = 大帅哥 [DJH.org] name = 大帅哥 import configparser config = configparser.ConfigParser()//创建一个操作对象 config.read('confile-new')//将操作对象和某个配置文件关联,并且将整个配置文件读取进内存中 config.remove_section('bitbucket.org')//删除一个信息块 config.remove_option('djh.org','age')//删除某个信息块的某个键值对 config.write(open('confile','w',encoding='utf-8'))//重新刷新硬盘的文件 推荐这样写,不要用with,这个不需要自己关闭,因为本来就没有赋值给变量,python垃圾回收 //机制会自动清除的 如果删除的东西不存在不会报错 结果 [DEFAULT] serveraliveinterval = 45 compression = yes compressionlevel = 9 forwardxll = yes [djh.org] sex = man
------------------改------------------------------------------------
改其实就用set()方法就ok了
import configparser config = configparser.ConfigParser() config.read('confile-new') config.set('djh.org','age','22') config.write(open('confile','w',encoding='utf-8')) 结果 原本的 age = 18 变成了 age = 22
hashlib模块
hashlib模块就是提供了哈希算法,提供了一堆的算法,但这些算法都只是可以由明文转换成密文,无法从密文转换为明文,将不定长度的明文转换为定长度的密文,那这样的话有啥用处呢,就是在数据库里存储的不是明明白白的秘密,而是存储的是密文,也就是密码转换之后的密文,这样别人就算攻破了数据库拿到了这张密码表也不可以直接登陆,但是还是不安全,因为哈希算法全世界的人都可以用, 并且在客观的物质世界上每个不同的字符串仅仅对应唯一的哈希值,无论谁在何时操作得到的都是确定长度的哈希值,这样就可以建立一个特别大的数据库,然后将对应的哈希值也搞出来,然后再拿哈希值一个一个匹配,总是可以匹配到明文的,这就是所谓的撞库反解
import hashlib obj = hashlib.md5()//先获取hashlib库里的md5算法对象 obj.update('admin'.encode('utf-8'))//将要加密的字符串写入,并且写入是怎么个存储的 print(obj.hexdigest())//输出加密后的哈希值 结果 21232f297a57a5a743894a0e4a801fc3
但是呢,因为这样会出现撞库反解,故现在又可以再进一步加密,就是在 md5() 算法里加入自己写的前缀
import hashlib obj = hashlib.md5('djh'.encode('utf-8'))//加上自己独特的前缀 obj.update('admin'.encode('utf-8')) print(obj.hexdigest()) 结果 ee8d17d12e808b5a38bfcaf556f5da1a //其实这个是自定义前缀加上真正的密码之后组成的新的字符串的密文 也就是 djhadmin 的密文
这样的话计算别人撞库破解了也只是得到 djhadmin ,如果用这个尝试登陆的话就肯定错 因为会变成 djhdjhadmin 这个的密文显然和 djhadmin 不一样,但是是否意味着这样就安全了呢,其实并不,因为当人家用 djhadmin 尝试登陆发现出错的话,那就肯定知道是被你加前缀了,那就一个一个去掉然后再尝试呗,就是 jhadmin-->
hadmin --> admin 慢慢就试出来的啦,好像看起来这个加密也是没卵用的
还有一个地方需要注意的是:
import hashlib obj = hashlib.md5() obj.update('admin'.encode('utf-8')) print(obj.hexdigest()) obj.update('djh'.encode('utf-8'))//这个的哈希值不仅仅与 djh 有关,还与它上面已经加密的字符串有关,意思是这里得到的不是djh的密文而是admindjh的密文 print(obj.hexdigest()) 结果 21232f297a57a5a743894a0e4a801fc3 d158dbfd7456640026ef1cece8d5ef37 //这个是 admindjh 的哈希值
后面还有什么 sha1 sha224 sha256 sha384 sha512 这些加密算法,用都是和md5一样,只是最终得到的位数不一样,md5是32位