python_模块 hashlib ,configparser, logging

hashlib模块

算法介绍

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

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

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

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

我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:

 1 md5
 2 # s1 = '12343254'
 3 # ret = hashlib.md5()  # 创建一个md5对象
 4 # ret.update(s1.encode('utf-8')) # 调用此update方法对参数进行加密 bytes类型
 5 # print(ret.hexdigest())  # 得到加密后的结果 定长
 6 #
 7 # s2 = 'alex12fdsl,.afjsdl;fjksdal;fkdsal;fld;lsdkflas;dkfsda;3'
 8 # ret = hashlib.md5()  # 创建一个md5对象
 9 # ret.update(s2.encode('utf-8')) # 调用此update方法对参数进行加密 bytes类型
10 # print(ret.hexdigest())  # 得到加密后的结果 定长
11 #
12 # s3 = 'alex12fdsl,afjsdl;fjksdal;fkdsal;fld;lsdkflas;dkfsda;3'
13 # ret = hashlib.md5()  # 创建一个md5对象
14 # ret.update(s3.encode('utf-8')) # 调用此update方法对参数进行加密 bytes类型
15 # print(ret.hexdigest())  # 得到加密后的结果 定长
16 #
17 # # 无论字符串多长,返回都是定长的数字,
18 # # 同一字符串,MD5值相同.
19 #
20 # #闲人: 将你常用的密码 000000  111111   890425
21 # #对应关系表:
22 # # 000000     c108971251713ee7c59db5c097378018
23 # # 撞库: 因为撞库,所以相对不安全,如何解决?
24 # # 123456  e10adc3949ba59abbe56e057f20f883e
25 #
26 # # s4 = '123456'
27 # # ret = hashlib.md5()  # 创建一个md5对象
28 # # ret.update(s4.encode('utf-8'))
29 # # print(ret.hexdigest())  # e10adc3949ba59abbe56e057f20f883e
30 #
31 # #解决方式:加盐.
32 #
33 # s3 = '123456'
34 # ret = hashlib.md5('@$1*(^&@^2wqe'.encode('utf-8'))  # 创建一个md5对象,加盐
35 # ret.update(s3.encode('utf-8')) # 调用此update方法对参数进行加密 bytes类型
36 # print(ret.hexdigest())  # 得到加密后的结果 定长  c5f8f2288cec341a64b0236649ea0c37
37 
38 # 如果黑客盗取到你的固定盐 '@$1*(^&@^2wqe'内容
39 
40 # 变成随机的盐:
41 # username = '爽妹'
42 # password = '123456'
43 
44 # ret = hashlib.md5(username[::-1].encode('utf-8'))
45 # ret.update(password.encode('utf-8'))
46 # print(ret.hexdigest())
md5

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

 1 #sha 系列
 2 # hashlib.sha1()  #  sha1 与md5 级别相同,但是sha1比md5 更安全一些,
 3 # ret = hashlib.sha1()
 4 # ret.update('123456'.encode('utf-8'))
 5 # print(ret.hexdigest())  # 7c4a8d09ca3762af61e59520943dc26494f8941b
 6 
 7 # ret = hashlib.sha512()  #级别最高,效率低,安全性最大
 8 # ret.update('123456'.encode('utf-8'))
 9 # print(ret.hexdigest())  # ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413
10 
11 # 文件的校验
12 # 对于小文件可以,但是超大的文件内存受不了,(下面具体代码解决)
13 # def func(file_name):
14 #     with open(file_name,mode='rb') as f1:
15 #         ret = hashlib.md5()
16 #         ret.update(f1.read())
17 #         return ret.hexdigest()
18 #
19 # print(func('hashlib_file'))
20 # print(func('hashlib_file1'))
21 
22 # s1 = 'I am 旭哥, 都别惹我.... 不服你试试'
23 # ret = hashlib.md5()
24 # ret.update(s1.encode('utf-8'))
25 # print(ret.hexdigest())  # 15f614e4f03312320cc5cf83c8b2706f
26 
27 # s1 = 'I am 旭哥, 都别惹我.... 不服你试试'
28 # ret = hashlib.md5()
29 # ret.update('I am'.encode('utf-8'))
30 # ret.update(' 旭哥, '.encode('utf-8'))
31 # ret.update('都别惹我....'.encode('utf-8'))
32 # ret.update(' 不服你试试'.encode('utf-8'))
33 # print(ret.hexdigest())  # 15f614e4f03312320cc5cf83c8b2706f
34 
35 # def func(file_name):
36 #     with open(file_name,mode='rb') as f1:
37 #         ret = hashlib.md5()
38 #         while True:
39 #             content = f1.read(1024)
40 #             if content:
41 #                 ret.update(content)
42 #             else:
43 #                 break
44 #         return ret.hexdigest()
45 # print(func('hashlib_file'))
46 # print(func('hashlib_file1'))
sha系列

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

摘要算法应用

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

name    | password
--------+----------
michael | 123456
bob     | abc999
alice   | alice2008

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

username | password
---------+---------------------------------
michael  | e10adc3949ba59abbe56e057f20f883e
bob      | 878ef96e86145580c38c87f0410ad153
alice    | 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。

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

configparser模块:

该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。

  1 """
  2 Django settings for webwx project.
  3 
  4 Generated by 'django-admin startproject' using Django 1.10.3.
  5 
  6 For more information on this file, see
  7 https://docs.djangoproject.com/en/1.10/topics/settings/
  8 
  9 For the full list of settings and their values, see
 10 https://docs.djangoproject.com/en/1.10/ref/settings/
 11 """
 12 
 13 import os
 14 
 15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 17 
 18 
 19 # Quick-start development settings - unsuitable for production
 20 # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
 21 
 22 # SECURITY WARNING: keep the secret key used in production secret!
 23 SECRET_KEY = 'mpn^n-s-&+ckg_)gl4sp^@8=89us&@*^r1c_81#x-5+$)rf8=3'
 24 
 25 # SECURITY WARNING: don't run with debug turned on in production!
 26 DEBUG = True
 27 
 28 ALLOWED_HOSTS = []
 29 
 30 
 31 # Application definition
 32 
 33 INSTALLED_APPS = [
 34     'django.contrib.admin',
 35     'django.contrib.auth',
 36     'django.contrib.contenttypes',
 37     'django.contrib.sessions',
 38     'django.contrib.messages',
 39     'django.contrib.staticfiles',
 40     'web',
 41 ]
 42 
 43 MIDDLEWARE = [
 44     'django.middleware.security.SecurityMiddleware',
 45     'django.contrib.sessions.middleware.SessionMiddleware',
 46     'django.middleware.common.CommonMiddleware',
 47     # 'django.middleware.csrf.CsrfViewMiddleware',
 48     'django.contrib.auth.middleware.AuthenticationMiddleware',
 49     'django.contrib.messages.middleware.MessageMiddleware',
 50     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 51 ]
 52 
 53 ROOT_URLCONF = 'webwx.urls'
 54 
 55 TEMPLATES = [
 56     {
 57         'BACKEND': 'django.template.backends.django.DjangoTemplates',
 58         'DIRS': [os.path.join(BASE_DIR, 'templates')]
 59         ,
 60         'APP_DIRS': True,
 61         'OPTIONS': {
 62             'context_processors': [
 63                 'django.template.context_processors.debug',
 64                 'django.template.context_processors.request',
 65                 'django.contrib.auth.context_processors.auth',
 66                 'django.contrib.messages.context_processors.messages',
 67             ],
 68         },
 69     },
 70 ]
 71 
 72 WSGI_APPLICATION = 'webwx.wsgi.application'
 73 
 74 
 75 # Database
 76 # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
 77 
 78 DATABASES = {
 79     'default': {
 80         'ENGINE': 'django.db.backends.sqlite3',
 81         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 82     }
 83 }
 84 
 85 
 86 # Password validation
 87 # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
 88 
 89 AUTH_PASSWORD_VALIDATORS = [
 90     {
 91         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
 92     },
 93     {
 94         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
 95     },
 96     {
 97         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
 98     },
 99     {
100         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
101     },
102 ]
103 
104 
105 # Internationalization
106 # https://docs.djangoproject.com/en/1.10/topics/i18n/
107 
108 LANGUAGE_CODE = 'en-us'
109 
110 TIME_ZONE = 'UTC'
111 
112 USE_I18N = True
113 
114 USE_L10N = True
115 
116 USE_TZ = True
117 
118 
119 # Static files (CSS, JavaScript, Images)
120 # https://docs.djangoproject.com/en/1.10/howto/static-files/
121 
122 STATIC_URL = '/static/'
123 STATICFILES_DIRS = (
124     os.path.join(BASE_DIR,'static'),
125 )
126 
127 Django的配置文件举例
Django的配置文件举例

创建文件

来看一个好多软件的常见文档格式如下:

 1 [DEFAULT]
 2 ServerAliveInterval = 45
 3 Compression = yes
 4 CompressionLevel = 9
 5 ForwardX11 = yes
 6   
 7 [bitbucket.org]
 8 User = hg
 9   
10 [topsecret.server.com]
11 Port = 50022
12 ForwardX11 = no
View Code

如果想用python生成一个这样的文档怎么做呢?

 1 import configparser
 2 
 3 config = configparser.ConfigParser()
 4 
 5 config["DEFAULT"] = {'ServerAliveInterval': '45',
 6                       'Compression': 'yes',
 7                      'CompressionLevel': '9',
 8                      'ForwardX11':'yes'
 9                      }
10 
11 config['bitbucket.org'] = {'User':'hg'}
12 
13 config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
14 
15 with open('example.ini', 'w') as configfile:
16 
17    config.write(configfile)
View Code

查找文件

 1 import configparser
 2 
 3 config = configparser.ConfigParser()
 4 
 5 #---------------------------查找文件内容,基于字典的形式
 6 
 7 print(config.sections())        #  []
 8 
 9 config.read('example.ini')
10 
11 print(config.sections())        #   ['bitbucket.org', 'topsecret.server.com']
12 
13 print('bytebong.com' in config) # False
14 print('bitbucket.org' in config) # True
15 
16 
17 print(config['bitbucket.org']["user"])  # hg
18 
19 print(config['DEFAULT']['Compression']) #yes
20 
21 print(config['topsecret.server.com']['ForwardX11'])  #no
22 
23 
24 print(config['bitbucket.org'])          #<Section: bitbucket.org>
25 
26 for key in config['bitbucket.org']:     # 注意,有default会默认default的键
27     print(key)
28 
29 print(config.options('bitbucket.org'))  # 同for循环,找到'bitbucket.org'下所有键
30 
31 print(config.items('bitbucket.org'))    #找到'bitbucket.org'下所有键值对
32 
33 print(config.get('bitbucket.org','compression')) # yes       get方法Section下的key对应的value
View Code

增删改操作

 1 import configparser
 2 
 3 config = configparser.ConfigParser()
 4 
 5 config.read('example.ini')
 6 
 7 config.add_section('yuan')
 8 
 9 
10 
11 config.remove_section('bitbucket.org')
12 config.remove_option('topsecret.server.com',"forwardx11")
13 
14 
15 config.set('topsecret.server.com','k1','11111')
16 config.set('yuan','k2','22222')
17 
18 config.write(open('new2.ini', "w"))
View Code

logging模块

函数式简单配

1 import logging  
2 logging.debug('debug message')  
3 logging.info('info message')  
4 logging.warning('warning message')  
5 logging.error('error message')  
6 logging.critical('critical message')
View Code

默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。

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

 1 import logging  
 2 logging.basicConfig(level=logging.DEBUG,  
 3                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
 4                     datefmt='%a, %d %b %Y %H:%M:%S',  
 5                     filename='/tmp/test.log',  
 6                     filemode='w')  
 7   
 8 logging.debug('debug message')  
 9 logging.info('info message')  
10 logging.warning('warning message')  
11 logging.error('error message')  
12 logging.critical('critical message')
View Code
 1 logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:
 2 
 3 filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。
 4 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
 5 format:指定handler使用的日志显示格式。
 6 datefmt:指定日期时间格式。
 7 level:设置rootlogger(后边会讲解具体概念)的日志级别
 8 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
 9 
10 format参数中可能用到的格式化串:
11 %(name)s Logger的名字
12 %(levelno)s 数字形式的日志级别
13 %(levelname)s 文本形式的日志级别
14 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
15 %(filename)s 调用日志输出函数的模块的文件名
16 %(module)s 调用日志输出函数的模块名
17 %(funcName)s 调用日志输出函数的函数名
18 %(lineno)d 调用日志输出函数的语句所在的代码行
19 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
20 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
21 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
22 %(thread)d 线程ID。可能没有
23 %(threadName)s 线程名。可能没有
24 %(process)d 进程ID。可能没有
25 %(message)s用户输出的消息
参数详解

logger对象配置

 1 import logging
 2 
 3 logger = logging.getLogger()
 4 # 创建一个handler,用于写入日志文件
 5 fh = logging.FileHandler('test.log',encoding='utf-8') 
 6 
 7 # 再创建一个handler,用于输出到控制台 
 8 ch = logging.StreamHandler() 
 9 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
10 fh.setLevel(logging.DEBUG)
11 
12 fh.setFormatter(formatter) 
13 ch.setFormatter(formatter) 
14 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 
15 logger.addHandler(ch) 
16 
17 logger.debug('logger debug message') 
18 logger.info('logger info message') 
19 logger.warning('logger warning message') 
20 logger.error('logger error message') 
21 logger.critical('logger critical message')
View Code

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

fh.setLevel(logging.Debug)单对文件流设置某个级别。

logging总结:

 1 #log 日志:
 2 #什么时候用到日志?
 3 #生活中:
 4 # 1, 公司员工信息工号等等需要日志.
 5 # 2, 淘宝,京东 你的消费信息,浏览记录等等都记录日志中,个性化推荐.
 6 # 3, 头条个性化设置(爱好记录的日志中).
 7 
 8 # 工作上:
 9 # 运维人员,任何员工对服务器做过的任何操作,都会记录到日志中.
10 # 如果你要是从事运维开发的工作,各处都需要日志.
11 # debug模式,需要依靠日志的.
12 #定时收集信息,也要记录日志.
13 
14 #  logging 模块是辅助你记录日志的,不是自动记录日志的.
15     # 低配版,logging
16     # 高配版,logger 对象
17 
18 # 低配版,logging
19 import logging
20 # 等级是一层一层升高的.
21 # logging.basicConfig(level=logging.ERROR)
22 # # level=logging.DEBUG 设置显示报错的级别.
23 # logging.debug('debug message')   # 调试信息
24 # logging.info('info message')    # 正常信息
25 # logging.warning('warning message')  # 警告信息:代码虽然不报错,但是警告你写的不规范,必须改.
26 # logging.error('error message')  # 错误信息.
27 # logging.critical('critical message') # 严重错误信息.
28 
29 # 用法实例:
30 # try:
31 #     num = input('>>>请输入')
32 #     num = int(num)
33 # except ValueError:
34 #     logging.error('出现了 %s' % ValueError)
35 
36 # 1,调整格式.(完善报错信息)
37 
38 # logging.basicConfig(level=logging.DEBUG,
39 #                     format='%(asctime)s %(filename)s (line:%(lineno)d) %(levelname)s %(message)s',
40 #                     )
41 # # level=logging.DEBUG 设置显示报错的级别.
42 # logging.debug('debug message')   # 调试信息
43 # logging.info('info message')    # 正常信息
44 # logging.warning('warning message')  # 警告信息:代码虽然不报错,但是警告你写的不规范,必须改.
45 # logging.error('error message')  # 错误信息.
46 # logging.critical('critical message') # 严重错误信息.
47 logging.basicConfig(level=logging.DEBUG,
48                     format='%(asctime)s %(filename)s (line:%(lineno)d) %(levelname)s %(message)s',
49                     # datefmt='%a, %d %b %Y %H:%M:%S',  # 设置时间格式
50                     filename='low_logging.log',
51                     # filemode='w',
52                     )
53 logging.warning('warning 警告错误!!!!')  # 警告信息:代码虽然不报错,但是警告你写的不规范,必须改.
54 logging.error('error message')  # 错误信息.
55 logging.critical('critical message') # 严重错误信息.
56 # level=logging.DEBUG 设置显示报错的级别.
57 # try:
58 #     num = input('>>>请输入')
59 #     num = int(num)
60 # except Exception as e:
61 #     logging.warning(e)  # 警告信息:代码虽然不报错,但是警告你写的不规范,必须改.
62 #     logging.error(e)  # 错误信息.
63 #     logging.critical(e) # 严重错误信息.
64 
65 # low logging 缺点:
66 # 1,写入文件 打印日志不能同时进行.
67 # 2 ,写入文件时文件编码方式为gbk..
低配版
 1 # 高配版
 2 # 第一版:只输入文件中.
 3 # import logging
 4 # logger = logging.getLogger() # 创建logger对象.
 5 # fh = logging.FileHandler('高配版logging.log',encoding='utf-8')  # 创建文件句柄
 6 #
 7 # # 吸星大法
 8 # logger.addHandler(fh)
 9 #
10 # logging.debug('debug message')
11 # logging.info('info message')
12 # logging.warning('warning message')
13 # logging.error('error message')
14 # logging.critical('critical message')
15 
16 # 第二版:文件和屏幕都存在.
17 # import logging
18 # logger = logging.getLogger() # 创建logger对象.
19 # fh = logging.FileHandler('高配版logging.log',encoding='utf-8')  # 创建文件句柄
20 # sh = logging.StreamHandler()  #产生了一个屏幕句柄
21 #
22 # # 吸星大法
23 # logger.addHandler(fh)  #添加文件句柄
24 # logger.addHandler(sh)  #添加屏幕句柄
25 #
26 #
27 # logging.debug('debug message')
28 # logging.info('info message')
29 # logging.warning('warning message')
30 # logging.error('error message')
31 # logging.critical('critical message')
32 
33 # 第三版:文件和屏幕都存在的基础上 设置显示格式.
34 # import logging
35 # logger = logging.getLogger() # 创建logger对象.
36 # fh = logging.FileHandler('高配版logging.log',encoding='utf-8')  # 创建文件句柄
37 # sh = logging.StreamHandler()  #产生了一个屏幕句柄
38 # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
39 #
40 #
41 # # 吸星大法
42 # logger.addHandler(fh)  #添加文件句柄
43 # logger.addHandler(sh)  #添加屏幕句柄
44 # sh.setFormatter(formatter)  # 设置屏幕格式
45 # fh.setFormatter(formatter)  # 设置文件的格式  (这两个按照需求可以单独设置)
46 #
47 #
48 # logging.debug('debug message')
49 # logging.info('info message')
50 # logging.warning('warning message')
51 # logging.error('error message')
52 # logging.critical('critical message')
53 
54 #第四版 文件和屏幕都存在的基础上 设置显示格式.并且设置日志水平.
55 # import logging
56 # logger = logging.getLogger() # 创建logger对象.
57 # fh = logging.FileHandler('高配版logging.log',encoding='utf-8')  # 创建文件句柄
58 # sh = logging.StreamHandler()  #产生了一个屏幕句柄
59 # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
60 # # logger.setLevel(logging.DEBUG)
61 # #如果你对logger对象设置日志等级.那么文件和屏幕都设置了.
62 # #总开关 默认从warning开始,如果想设置分开关:必须要从他更高级:(ERROR,critical)从这来个开始.
63 #
64 # # 吸星大法
65 # logger.addHandler(fh)  #添加文件句柄
66 # logger.addHandler(sh)  #添加屏幕句柄
67 # sh.setFormatter(formatter)  # 设置屏幕格式
68 # fh.setFormatter(formatter)  # 设置文件的格式  (这两个按照需求可以单独设置)
69 # fh.setLevel(logging.DEBUG)
70 #
71 # logging.debug('debug message')
72 # logging.info('info message')
73 # logging.warning('warning message')
74 # logging.error('error message')
75 # logging.critical('critical message')
高配版
原文地址:https://www.cnblogs.com/liuye1990/p/9287452.html