Python hashlib模块、configparser模块、logging模块(面向对象相关)

hashlib模块

算法介绍
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,
	把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,
	目的是为了发现原始数据是否被人篡改过。

摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,
	计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,
	都会导致计算出的摘要完全不同。

计算出一个字符串的MD5值:
import hashlib

# 获取密文的步骤
SALT = b'min' # 添加密钥成分
obj = hashlib.md5(SALT) # 实例化对象
obj.update("admin".encode("utf-8")) # 写入要加密的字节
res=obj.hexdigest() # 获取密文
print(res) #88dcb46e24f1085bee9cfe7fdbb6a32b
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
import hashlib

md5=hashlib.md5()
md5.update(b"hello")
md5.update(b"yuan")

print(md5.hexdigest())
print(len(md5.hexdigest()))

# helloyuan:       d843cc930aa76f7799bba1780f578439
# 分两步执行后的结果: d843cc930aa76f7799bba1780f578439
# 结果一样

# 分步应用:
md5=hashlib.md5()

with open("ssh_client.py","rb") as f:
	for line in f:
		md5.update(line) # 每一步分开执行,结果一样

print(md5.hexdigest()) 
MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符	串表示。
另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:
import hashlib
 
sha1 = hashlib.sha1()
sha1.update('how to use sha1 in ')
sha1.update('python hashlib?')
print sha1.hexdigest()
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。
比SHA1更安全的算法是SHA256和	SHA512,不过越安全的算法越慢,而且摘要长度更长。
应用
实现一个密文比对登录:
import hashlib


SALT = b'min'  # 添加密钥成分


def md5(pwd):
    obj = hashlib.md5(SALT)  # 实例化对象
    obj.update(pwd.encode('utf-8'))  # 写入要加密的字节
    return obj.hexdigest()  # 返回密文


user = input("请输入用户名:")
pwd = input("请输入密码:")
if user == 'min' and md5(pwd) == '88dcb46e24f1085bee9cfe7fdbb6a32b':
    print('登录成功')
else:
    print('登录失败')

# 抽奖应用
import random
import hashlib

name = ["神迷", "马克", "禾木", "影视辑", "每日", "影视菌", "焦点", "特派", "星期",
"行人","探索", "咖娱", "mark", "新片", "推荐"]
obj = hashlib.md5()
result = random.choice(name)
obj.update(result.encode("utf-8"))
true_code = obj.hexdigest()
print(true_code)
# 比对加密
for el in name:
    obj = hashlib.md5()
    obj.update(el.encode("utf-8"))
    get_code = obj.hexdigest()
    fin_code = input("请复制得到的加密内容:")
    if true_code == fin_code:
        print("解密后选中的人是:%s" % result)
        break

# 校验抽奖
for el in name:
    obj = hashlib.md5()
    choice_el = int(input("请输入已选中人序号,并校验:"))
    obj.update(name[choice_el].encode("utf-8"))
    check_code = obj.hexdigest()
    if true_code == check_code:
        print("天选之子是" + ":" + result)
        print("校验正确,此次有效")
        break
    else:
        print("对应值不对,存在作弊!!!")
        break
任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?
方法是存到数据库表中:
name    | password
--------+----------
michael | 123456
bob     | abc999
alice   | alice2008
如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。
此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。
正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5:
username | password
---------+---------------------------------
michael  | e10adc3949ba59abbe56e057f20f883e
bob      | 878ef96e86145580c38c87f0410ad153
alice    | 99b1c2188db85afee403b1536010c2c9
这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号。

对于用户来讲,当然不要使用过于简单的口令。但是,我们能否在程序设计上对简单口令加强保护呢?

由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常
用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:
hashlib.md5("salt".encode("utf8"))
经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,
	也很难通过MD5反推明文口令。

但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,
	这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?

如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,
	从而实现相同口令的用户也存储不同的MD5。

摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文);
	只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。

configparser模块

该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),
每个节可以有多个参数(键=值)。
创建文件
来看一个好多软件的常见文档格式如下:
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
  
[bitbucket.org]
User = hg
  
[topsecret.server.com]
Port = 50022
ForwardX11 = no
如何用python生成一个这样的文档怎么做?
import configparser

config = configparser.ConfigParser()

config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9',
                     'ForwardX11':'yes'
                     }

config['bitbucket.org'] = {'User':'hg'}

config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}

with open('example.ini', 'w') as configfile:

   config.write(configfile)
查找文件
import configparser

config = configparser.ConfigParser()

#---------------------------查找文件内容,基于字典的形式

print(config.sections())        #  []

config.read('example.ini')

print(config.sections())        #   ['bitbucket.org', 'topsecret.server.com']

print('bytebong.com' in config) # False
print('bitbucket.org' in config) # True


print(config['bitbucket.org']["user"])  # hg

print(config['DEFAULT']['Compression']) #yes

print(config['topsecret.server.com']['ForwardX11'])  #no


print(config['bitbucket.org'])          #<Section: bitbucket.org>

for key in config['bitbucket.org']:     # 注意,有default会默认default的键
    print(key)

print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键

print(config.items('bitbucket.org'))    # 找到'bitbucket.org'下所有键值对

print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key对应的value
增删改操作
import configparser

config = configparser.ConfigParser()

config.read('example.ini')

config.add_section('yuan')



config.remove_section('bitbucket.org')
config.remove_option('topsecret.server.com',"forwardx11")


config.set('topsecret.server.com','k1','11111')
config.set('yuan','k2','22222')

config.write(open('new2.ini', "w"))

logging模块

函数式简单配置
错误等级:
import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message') 
默认情况下Python的logging模块将日志打印到了标准输出中,
且只显示了大于等于WARNING级别的日志,
这说明默认的日志级别设置为WARNING
(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),
默认的日志格式为日志级别:Logger名称:用户输出消息。

灵活配置日志级别,日志格式,输出位置:
import logging

# 配置好日志处理文件,默认是GBK
logger = logging.basicConfig(
    filename='xxxxxxx.txt',  # 把日志信息写入的文件名
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',  # 时间的格式
    level=30)  # 大于等于 才会被执行(不写默认30)写入日志文件

logging.debug('x1')  # 10 开发时把这个文件开着
logging.info('x2')  # 20  提示
logging.warning('x3')  # 30 警告
logging.error('x4')  # 40 平时用的最多
logging.critical('x5')  # 50 几乎是最高的(系统崩溃之类的)

logging.log(100, 'x6')  # 自定义错误信息

# 合起来应用一下
import traceback


def func():
    try:
        a = a + 1
    except Exception as e:  # e是一个对象

        # print(e)#输出结果是一行错误信息,本来是打印对象地址的,说明执行__str__()方法
        # local variable 'a' referenced before assignment
        # logging.error(str(e))#所以只需 str(e) 就能获取到错误信息

        msg = traceback.format_exc()  # 获取当前错误的堆栈信息
        logging.error(msg)
# 日志文件,logging.basicConfig重写,只会执行第一个加载到内存的
import logging

logger1 = logging.basicConfig(filename='x1.txt',
                              format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                              datefmt='%Y-%m-%d %H:%M:%S',
                              level=30)

logger = logging.basicConfig(filename='x2.txt',
                             format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                             datefmt='%Y-%m-%d %H:%M:%S',
                             level=30)

logging.error('x4')
logging.error('x5')  # 输出结果,只生成了 x1.txt 并且写入了两条错误信息 x4和x5
日志切割:
import time
import logging
from logging import handlers

sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024,backupCount=5)
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    handlers=[fh,sh,rh],
    level=logging.ERROR
)

for i in range(1,100000):
    time.sleep(1)
    logging.error('KeyboardInterrupt error %s'%str(i))
配置参数:
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:
%(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用户输出的消息
logger对象配置
import logging

logger = logging.getLogger()
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log',encoding='utf-8') 

# 再创建一个handler,用于输出到控制台 
ch = logging.StreamHandler() 
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setLevel(logging.DEBUG)

fh.setFormatter(formatter) 
ch.setFormatter(formatter) 
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 
logger.addHandler(ch) 

logger.debug('logger debug message') 
logger.info('logger info message') 
logger.warning('logger warning message') 
logger.error('logger error message') 
logger.critical('logger critical message')

# logging库提供了多个组件:Logger、Handler、Filter、Formatter。
# Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,
# Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。
# 另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,
# 也可以通过 fh.setLevel(logging.Debug)单对文件流设置某个级别。

自定义日志
import logging

# 创建一个操作日志的对象logger(依赖FileHandler)
file_handler = logging.FileHandler('l1.log', 'a', encoding='utf-8')  # 创建文件
file_handler.setFormatter(logging.Formatter
                          (fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
                          )  # 设置日志格式   参数module:当前模块名

logger1 = logging.Logger('s1', level=logging.ERROR)  # 创建一个日志文件处理对象
# 参数分别是:名称,如'腾讯qq';错误等级
logger1.addHandler(file_handler)  # 将文件添加到日志

logger1.error('123123123')  # 记录一个错误

# 再创建一个操作日志的对象logger(依赖FileHandler)
file_handler2 = logging.FileHandler('l2.log', 'a', encoding='utf-8')
file_handler2.setFormatter(logging.Formatter
                           (fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
                           )

logger2 = logging.Logger('s2', level=logging.ERROR)
logger2.addHandler(file_handler2)

logger2.error('666')  # 结果会生成两个日志文件处理文件
示例用法 用上上面已经创建好的日志文件

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值