《Python》hashlib模块、configparser模块、logging模块

摘要:
该算法也称为哈希算法,哈希算法encode)ret=md5_Obj2。hextest()print#e5070266457aebf1e3570e1a1b9b0ce32 md5是最常用的摘要算法。它非常快。结果是一个固定的128位字节,通常由32位十六进制字符串表示。另一个常见的摘要算法是sha1。调用sha1类似于调用md5:importhashlibsha1_obj=hashlib。sha1()sha1_obj.updateret=sha1_obj.hexdigest()print#e0738b87e67bbfc9c5b77556665064446430e81c40sha1_obj2=hashlib。sha1()sha1_ obj1.updatesha1_obj1.update ret=sha1_ obj1.hexedigest()print#e0738b87e67bbfc9c5b7755666506446430e81c<class‘str‘>40 sha1结果为160位字节,通常由40位十六进制字符串表示。

一、hashlib模块

    Python的hashlib模块中提供了常见的摘要算法,如md5,sha1等等。

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

    不同的字符串通过这个算法计算出的密文总是不同的,相同的算法,相同的字符串,获得的结果总是相同的(不同的语言,不同的环境(操作系统、版本、时间))

    这个算法不可逆

我们以常见的照耀算法md5为例,计算出一个字符串的md5值:

import hashlib

md5_obj = hashlib.md5()     # 实例化一个对象md5_obj
md5_obj.update('666'.encode('utf-8'))
ret = md5_obj.hexdigest()
print(ret,type(ret),len(ret))   # fae0b27c451c728867a567e8c1bb4e53  <class 'str'>  32

md5_obj1 = hashlib.md5()
md5_obj1.update('hello word'.encode('utf-8'))
ret = md5_obj1.hexdigest()
print(ret,type(ret),len(ret))   # 13574ef0d58b50fab38ec841efe39df4  <class 'str'>  32

md5_obj2 = hashlib.md5()
md5_obj2.update('小天才'.encode('gbk'))
ret = md5_obj2.hexdigest()
print(ret)  # 1977f269c4c0f91d9526836069070f28  <class 'str'>  32

# 不管多长的字符串通过相同的算法得出的密文长度都是相同的

如果数据量很大,可以分多次调用update(),最后计算的结果是一样的:

  注:标点符号、空格等,只要改变一个结果都是截然不同的

import hashlib

md5_obj = hashlib.md5()
md5_obj.update('how to use sha1 in python hashlib?'.encode('utf-8'))
ret = md5_obj.hexdigest()
print(ret, len(ret))  # 561275505146bd1cbbad267924939e6d   32

md5_obj1 = hashlib.md5()
md5_obj1.update('how to use '.encode('utf-8'))
md5_obj1.update('sha1 in python '.encode('utf-8'))
md5_obj1.update('hashlib?'.encode('utf-8'))
ret = md5_obj1.hexdigest()
print(ret, len(ret))    # 561275505146bd1cbbad267924939e6d   32

md5_obj2 = hashlib.md5()
md5_obj2.update('how touse sha1 in python hashlib?'.encode('utf-8'))
ret = md5_obj2.hexdigest()
print(ret, len(ret))  # e50702666457aebf1e3570e1a1b9b0ce    32

  md5是最常用的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示,另一种常见的摘要算法是sha1,调用sha1和调用md5完全类似:

import hashlib

sha1_obj = hashlib.sha1()
sha1_obj.update('hello word'.encode('utf-8'))
ret = sha1_obj.hexdigest()
print(ret, type(ret), len(ret)) # e0738b87e67bbfc9c5b77556665064446430e81c  <class 'str'>  40

sha1_obj1 = hashlib.sha1()
sha1_obj1.update('hello '.encode('utf-8'))
sha1_obj1.update('word'.encode('utf-8'))
ret = sha1_obj1.hexdigest()
print(ret, type(ret), len(ret)) # e0738b87e67bbfc9c5b77556665064446430e81c  <class 'str'>  40

  SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长

摘要算法应用:

  任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:

username    |    password
------------+--------------
yang        |    123456
alex        |    111111
taibai      |    666666

  如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5:

username    |    password
------------+------------------------------------
yang        |    e10adc3949ba59abbe56e057f20f883e
alex        |    878ef96e86145580c38c87f0410ad153
taibai      |    99b1c2188db85afee403b1536010c2c9

  考虑这么个情况,很多用户喜欢用123456,888888,password这些简单的口令,于是,黑客可以事先计算出这些常用口令的MD5值,得到一个反推表:

'e10adc3949ba59abbe56e057f20f883e': '123456'
'21218cca77804d2ba1922c33e0151105': '888888'
'5f4dcc3b5aa765d61d8327deb882cf99': 'password'

  这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号。

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

  由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:

hashlib.md5("salt".encode("utf8"))

  经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。

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

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

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

# 给用户动态加‘盐’
import hashlib

def get_md5(username, password):
    md5_obj = hashlib.md5(username.encode('utf-8')) # 用用户名加盐,每个用户名都是唯一的,所以密码相同计算出的密文也是不一样
    md5_obj.update(password.encode('utf-8'))
    ret = md5_obj.hexdigest()
    return ret
while 1:
    username = input('username:').strip()
    password = input('password:').strip()
    with open('User_info') as f:
        for line in f:
            usr, pwd = line.strip().split('|')
            if username == usr and get_md5(username, password) == pwd:
                exit('登录成功')
        else:
            print('登录失败')
# 文件的一致性校验
import hashlib
import os

def get_file_md5(file_path):
    md5_obj = hashlib.md5()
    with open(file_path, encoding='utf-8') as f:
        for line in f:
            md5_obj.update(line.encode('utf-8'))
    ret = md5_obj.hexdigest()
    return ret
print(get_file_md5('day25.py')) # e91bad51d91cb521de28e045c1182892
print(get_file_md5('D:/python/day25/day25.py')) # e91bad51d91cb521de28e045c1182892

# 非文本文件,要以rb的形式来读,读出来的都是bytes
def get_file_md5(file_path, buffer = 1024):
    md5_obj = hashlib.md5()
    file_size = os.path.getsize(file_path)
    with open(file_path, 'rb') as f:
        while file_size:
            content = f.read(buffer)
            file_size -= len(content)
            md5_obj.update(content)
    return md5_obj.hexdigest()
print(get_file_md5('day25.py')) # 5b6942e6bdc3d22f25f9982f36f00535
print(get_file_md5('D:/python/day25/day25.py')) # 5b6942e6bdc3d22f25f9982f36f00535

二、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)
'''
user
serveraliveinterval
compression
compressionleve1
forwardx11
'''

print(config.options('bitbucket.org')) # 同for循环,找到'bitbucket.org'下所有键 # ['user', 'serveraliveinterval', 'compression', 'compressionleve1', 'forwardx11']
print(config.items('bitbucket.org')) #找到'bitbucket.org'下所有键值对 # [('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionleve1', '9'), ('forwardx11', 'yes'), ('user', 'hg')]
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
# 日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG
logging.basicConfig(level=logging.DEBUG)   # 更改打印的内容,默认只打印info以上的内容
logging.debug('debug message')          # 计算或者工作的细节
logging.info('info message')            # 记录一些用户的增删改查的操作
logging.warning('input a string type')  # 警告操作
logging.error('error message')          # 错误操作
logging.critical('critical message')    # 批判的 直接导致程序出错退出的(闪退)
'''
DEBUG:root:debug message
INFO:root:info message
WARNING:root:input a string type
ERROR:root:error message
CRITICAL:root:critical message
'''

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

import logging  
logging.basicConfig(level=logging.DEBUG,  
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
                    datefmt='%a, %d %b %Y %H:%M:%S',  
                    filename='/tmp/test.log',  
                    filemode='w')  
  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')

  配置参数:

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对象配置:

  1、创建longger对象

  2、创建一个文件操作符,可以指定编码

  3、创建一个屏幕操作符

  4、设计一个日志格式

  5、给文件操作符、屏幕操作符绑定日志格式

  6、为文件操作符、屏幕操作符添加到longger对象上

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)单对文件流设置某个级别。

免责声明:文章转载自《《Python》hashlib模块、configparser模块、logging模块》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇基于opencv图片切割Redis 占用Windows系统盘空间23G下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

pycharm+python+Django之web开发环境的搭建(windows)

转载:https://blog.csdn.net/yjx2323999451/article/details/53200243/ pycharm+python+Django之web开发环境的搭建(windows) 最近在学习python,总感觉网上写的一些东西对新手(python方面的程序员)来说不是太友好。有些文章写得不是太详细,有些又写得比较高升。对于...

Python 网络爬虫 007 (编程) 通过网站地图爬取目标站点的所有网页

通过网站地图爬取目标站点的所有网页 使用的系统:Windows 10 64位Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyCharm 2016 04 我使用的 urllib 的版本:urllib2 注意: 我没这里使用的是 Python2 ,而不是Python3 一 . 前言 通过前两节(爬取一个...

Mac下Python和Pycharm之virtualenv

一、python如何配置virtualenv   1.安装virtualenv pip3 install virtualenvpip install -i https://pypi.tuna.tsinghua.edu.cn/simple virtualenvpip3 install --upgrade pip 2.创建目录 mkdir Myproject...

Power BI Python 在Power BI Desktop中使用Python导入数据

前面我有写过一篇博文,Power BI Python 在Power BI Desktop中使用Python绘图,今天我来使用Python脚本来生成Power Query的查询数据 我们一般都使用第三方的IDE先调试好Python代码,然后再在Power BI Desktop运行,我这里使用的是Pycharm,至于该IDE大家到网上找安装包吧。 先看看我们...

python爬取图片遇见src乱码: data:image/png;base64

  python爬取图片遇见src乱码: data:image/png;base64 向爬取自己喜欢的图片,但是在爬取下来的代码当中图片的src会出现乱码的情况:data:image/png;base64。搞了我好长时间,试过伪装headers,也试过通过修改网页js的内容来让img的src显示出来,也试过修改div的display属性,但是全部都没用,最...

python 第三方库BeautifulSoup4文档学习(4)

bs4 搜索文档树 搜索文档树有很多方法,比较常用的是find()和find_all() ,在方法中我们通常需要加上特定的参数去查找我们需要的内容,这样的参数就被看作为过滤器。 依然使用官方提供的测试html文档 html_doc = """ <html><head><title>The Dormouse's story...