Python课程回顾(day20)

常用模块3

一、logging模块

日志模块
import logging

logging.basicConfig(
    filename='a.log',   # 指定文件打印路径,不指定文件名会默认打印到控制台
    filemode='a',       # 默认是a模式,可以不写
    format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
    datefmt='%Y-%m-%d %X %p',  # 定制(asctime)的时间格式
    level=10            # 设置日志的级别,代表当前级别及以上级别都可以打印

)
#  打印格式
# %(asctime)s   %(name)s   %(levelname)s       %(module)s:       %(message)s
#  格式化时间   日志名称     日志的级别     当前使用日志的模块名  日志具体的信息
logging.debug('调试信息')      # 10
logging.info('运行结果')       # 20
logging.warning('一级警告')    # 30       { 不同数字代表不同的级别
logging.error('二级警告')      # 40
logging.critical('三级警告')   # 50

# logging模块的四类对象
# logger  负责产生日志
logger1 = logging.getLogger('')      # 使用getLogger产生一个产生日志的对象


# filter  过滤日志(不常用)


# handler 控制日志打印到文件或是终端
# 可能很多文件都需要用到日志,所以可以在多个文件内打印
fh1 = logging.FileHandler(filename='a1.log', encoding='utf-8')  # 控制文件打印路径
fh2 = logging.FileHandler(filename='a2.log', encoding='utf-8')  # 控制文件打印路径
sh = logging.StreamHandler()  # 控制日志打印到终端


# formatter 控制日志的格式
fmt1 = logging.Formatter(
    fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
    datefmt='%Y-%m-%d %X %p'
)

fmt2 = logging.Formatter(
    fmt='%(asctime)s - %(message)s',
    datefmt='%Y-%m-%d %X %p'
)


# 让logger1对象产生的日志可以分别打印到不同的地方,要让他们绑定关系
logger1.addHandler(fh1)
logger1.addHandler(fh2)     # handler对象
logger1.addHandler(sh)


# 让logger1对象所绑定的handler对象再次绑定打印格式
fh1.setFormatter(fmt1)
fh2.setFormatter(fmt1)
sh.setFormatter(fmt2)


# 日志级别
# 日志级别要必须通过两层关卡(logger1级别,文件级别)才可以正常记录
logger1.setLevel(10)  # 基础级别,可以打印所有级别的信息
fh1.setLevel(20)      # 只处理打印大于等于20级别的信息
fh2.setLevel(30)      # 只处理打印大于等于30级别的信息
sh.setLevel(40)       # 只处理打印大于等于40级别的信息

logger1.warning('调试信息')    # 注意本层级别要 >= logger1的级别


了解:日志继承
import logging

logger1 = logging.getLogger('grandfather')
logger2 = logging.getLogger('grandfather.father')    # 继承关系要在设置文件名时将子集放置父集后
logger3 = logging.getLogger('grandfather.father.son')

sh = logging.StreamHandler()
fmt3 = logging.Formatter(
    fmt='%(asctime)s - %(message)s',
    datefmt='%Y-%m-%d %X %p'
)
sh.setFormatter(fmt3)

logger1.addHandler(sh)
logger2.addHandler(sh)
logger3.addHandler(sh)

logger1.setLevel(10)
logger2.setLevel(10)
logger3.setLevel(10)
sh.setLevel(10)

logger3.debug('----------')   # logger3会将得到的所有信息反继承给logger3的所有父集

二、hashlib模块

import hashlib    # hash是一种算法,该算法接收传入的内容经过运算后会得到一个hash值

# 特点1:只要传入的值一样,得到的hash值必然一样
m = hashlib.md5() # 使用.md5拿到一个hash工厂
m.update('hello'.encode('utf-8')) # 使用update进行加工
m.update('world'.encode('utf-8'))
m.update('klf'.encode('utf-8'))
print(m.hexdigest()) # hexdigest拿到hash值1079e6f8e24cecd0c41c8841f727b31e


m.update('helloworldklf'.encode('utf-8'))
print(m.hexdigest()) # 拿到hash值1079e6f8e24cecd0c41c8841f727b31e


# 特点2:不能由hash值反解成原本内容
# 基于hash值的这种特性,我们可以在接收用户输入的时候将用户输入的密码加工成hash值,
# 再由网络通讯发到我们的服务端进行数据保存,以达到用户密码的安全性。
# 用户再次校验时只需要跟原本的hash值做对比即可

# 但考虑到用户的个人习惯与撞库(一些常用密码格式的hash值),用户的密码还是不够安全
# 这时候我们就需要帮助用户来提高密码安全性:即密码加盐
user_pwd = 'klf123'

m = hashlib.md5()
m.update('abcdefg'.encode('utf-8')) # 在用户密码之前加入其他字符的hash值
m.update(user_pwd.encode('utf-8')) # 中间是用户密码
m.update('hijklmn'.encode('utf-8')) # 在用户密码之后加入其他字符的hash值

print(m.hexdigest()) # 生成新的hash值

# 注意:加盐的方式是随机的,想要破解就必须知道使用的hash工厂,加盐方式以及加盐位置
# 服务端反解的时候按照当初加盐的规则来反解即可


# 特点3:只要使用同一种hash算法,得到的hash值的长度的固定的
# 这种特点大大降低了用户所传入数据的大小所带来的空间不足
# 无论用户传入的数据有多大,得到的hash值的长度是固定的

三、re模块(重点******)

import re
# re模块之正则表达式re.findall的应用1:单次匹配

# print(re.findall('\w', 'abc 123 \n!@#$%\r\t\f'))  # '\w'匹配字符串内所有的数字、字母、下划线
# print(re.findall('\W', 'abc 123 \n!@#$%\r\t\f'))  # '\W'匹配的是字符串所有的非数字字母下划线,若字符串内有\则会使用一个斜杠转译后面的斜杠

# print(re.findall('\s', 'abc 123 \n!@#$%\r\t\f'))  # '\s'匹配的是字符串内所有的空白字符,('空字符'\n\r\t\f)
# print(re.findall('\S', 'abc 123 \n!@#$%\r\t\f'))  # '\S'匹配的是字符串内所有的非空白字符

# print(re.findall('\d', 'abc 123 \n!@#$%\r\t\f'))  # '\d'匹配任意数字(0~9)
# print(re.findall('\D', 'abc 123 \n!@#$%\r\t\f'))  # '\D'匹配任意非数字

# print(re.findall('\alex', 'egon,alex_sb123yxx_sb,lxx_sb'))  # 单纯输入的字符串则会将字符串作为整体全部匹配,若匹配不成功则返回空,有多少个匹配多少个

# print(re.findall('\Aalex', 'egon,alex_sb123yxx_sb,lxx_sb'))  # '\A'表示只从头开始找,若匹配不成功则返回空,若匹配成功只匹配一次,不会继续向后匹配
# print(re.findall('^alex', 'egon,alex_sb123yxx_sb,lxx_sb'))  # 作用等同于大A
# print(re.findall('alex\Z', 'egon,alex_sb123yxx_sb,lxx_sb'))  # '\Z'表示只从末尾开始找,若匹配不成功则返回空,若匹配成功只匹配一次,不会继续向后匹配
# print(re.findall('alex$', 'egon,alex_sb123yxx_sb,lxx_sb'))  # '$'作用等同于大Z

# 组合应用之*,$
# print(re.findall('^abc$', 'abc1'))  # 表示字符串必须为^与$之间的字符串,否则匹配不成功

# ==============================================================================

# re模块之正则表达式的应用2:重复匹配

# print(re.findall('a.c', 'a123c a2c anc aaaaaaac'))
# .表示匹配除换行符之外的任意'一个'字符,可加多个.,每个点都代表一个字符
# 结果:在a与c中间只有一个字符的情况下,才会匹配成功
# print(re.findall('a.c', 'a123c a2c anc aaaaaaac a\nc', re.DOTALL))
# re.DOTALL表示可以打破'.'不能匹配换行符的定义,当前是可以匹配任意字符的

# print(re.findall('ab?', 'a ab abb abbb abbbb abbbbb'))
# ?表示?左边的1个字符重复0次或1次(可以是0次,最多是1次)
# 结果:只要a匹配成功,b可以匹配0次(若为0次则只打印a),最多只匹配1次

# print(re.findall('ab*', 'a ab abb abbb abbbb abbbbb'))
# *表示*左边的1个字符重复0次或N次(可以是0次,没有最大匹配次数,有多少要多少)
# 结果:只要a匹配成功,b可以匹配0次(若为0次则只打印a),也可以匹配无限次

# print(re.findall('ab+', 'a ab abb abbb abbbb abbbbb'))
# *表示*左边的1个字符重复1次或N次(至少是1次,没有最大匹配次数,有多少要多少)
# 结果:只要a匹配成功,b可以匹配1次(若为0次则不打印),也可以匹配无限次

# print(re.findall('ab{0,1}', 'a ab abb abbb abbbb abbbbb'))
# {}内可以传入范围,指定匹配的次数,若后面的参数不写则代表N次(等同于*号的作用)
# 结果:等同于?号的作用

# 组合应用之.*(贪婪匹配)
# print(re.findall('a.*c', 'ac a123c a%$^$c aasdsdasdad'))
# .*表示可以匹配任意长度任意字符(除\n),但*会尽可能的去匹配多个字符
# 结果:.*的组合会将距离开头最近的a当做起始,将距离末尾最近的c当做结束,形成1个匹配然后结束,不建议使用

# 组合应用之.*?(非贪婪匹配)
# print(re.findall('a.*?c', 'ac a123c a%$^$c aasdsdasdad'))
# .*?中的问号的作用就是将贪婪匹配转换成非贪婪匹配
# 结果:会将距离开头最近的a当做起始,将距离a后面最近的c当做结束,形成一个匹配然后结束

# ==============================================================================

# re模块之正则表达式的应用3:分组()

# print(re.findall('(alex)_sb', 'alex_sb sdasfadsgasgalex_sb'))
# ()的作用是不影响正则表达式基本的匹配方法的前提下,只打印括号内的内容
# 结果:若匹配成功后只打印alex

# 组合应用之.*?()(爬取网址)
# print(re.findall('href="(.*?)"', '<link href="/bundles/admin-new.css?v=Ye9IYl3rG1TPa1mMw-tr9jlbN_BMEt9-1G3QChTzFC01" rel="stylesheet"/>'))
# 结果:                                      ['/bundles/admin-new.css?v=Ye9IYl3rG1TPa1mMw-tr9jlbN_BMEt9-1G3QChTzFC01']

# ==============================================================================

# re模块之正则表达式的应用4:[]指定范围
# print(re.findall('a[0-9][0-9]c', 'a1c adc a4c aAc a11c aac'))
# []内可以使用-号来定义一个范围,英文是a-zA-Z,数字是0-9,在这个自定义范围内的才算匹配成功
# 结果:会将a与c之间是0-9的字符串匹配出来,若想匹配两位数则需要再加中括号进行再次匹配(会以两个字符去匹配),a1c a4c便不再成立
# 注意:若中括号内要匹配特殊符号例如+-*^之类的,'-'不可以放在两个符号之间,要放左右两边。

# print(re.findall('^a[0-9]c', 'a1c adc a4c aAc a11c aac'))
# []内前面加^号就代表取反的意思(原始默认为开头)即不再这个范围内的就匹配成功
# 结果:a与c之间不是0-9之间的就可以匹配

# 组合应用:
# print(re.findall('[a-z]+_sb', 'alex_sb egon_sb 123wxxxxxxxxx_sb ryc_sb'))
# [匹配条件]'+'匹配条件 '+'代表中括号内的条件可以匹配1次或N次,直到遇见不是括号范围内的字符然后与'+'后面的字符做匹配
# 结果:会优先匹配中括号内的(一直匹配),直到字符不属于中括号范围内的,开始匹配_sb
# print(re.findall('([a-z]+)_sb', 'alex_sb egon_sb 123wxxxxxxxxx_sb ryc_sb'))
# 加入小括号来只取名称

# ==============================================================================

# re模块之正则表达式的应用5:| 或者
# print(re.findall('compan(ies|y)', 'too many companies have bank rupt , and the next one company'))
# 在|左右两边的内容只要成立一个即匹配成功
# 结果:在compan后若为ies或为y的情况下,则匹配成功,因为有分组,所以只打印括号内的内容,(ies,y)

# print(re.findall('compan(?:ies|y)', 'too many companies have bank rupt , and the next one company'))
# 在分组内加入?:则代表打印分组外与分组内的所有内容,不单单只要括号内的内容(companies,company)

# ==============================================================================

# re模块之正则表达式search与match的应用:
# print(re.search('alex', '123 alex sb egon nb alex sb'))
# print(re.search('^alex', '123 alex sb egon nb alex sb'))
# search代表从起始到结束依次匹配,若匹配成功返回第一个匹配成功的对象,可以使用group打印结果
# 若匹配不成功则返回None,再使用group打印结果则会报错
# 表达式之前加^代表只匹配起始位置,若不成功则返回None,再使用group打印结果则会报错
# 一般使用search返回的对象(不加group)判断是否存在你需要找的字符

# print(re.match('alex', '123 alex sb egon nb alex sb'))
# match代表默认只从起始位置匹配,若匹配成功返回一个对象,使用group打印结果
# 若匹配不成功则返回None,再使用group打印结果则会报错

# ==============================================================================

# re模块之正则表达式split的应用
# info = 'a,b c:\*d/p'
# print(re.split('[ ,:\\\/*]', info))
# split的原理基本等同于字符串的split,不过re中的split可以使用多个符号来切分
# 将表达式内的各种符号对字符依次切分,只要字符内包含其中的某个切分符就进行切分
# 若两个字符之间存在两个或多个切分符则会切出相应的空字符

# ==============================================================================

# re模块之正则表达式sup的应用
# 要求:将第二个egon替换成大写
# print(re.sub('(.*?)(egon)(.*?)(egon)(.*?)', r'\1\2\3EGON\5', '123 egon is sb egon 123'))
# sub的作用基本相同于replace,但sub功能可以在指定位置替换指定的字符
# 结果:事先将字符分组,然后使用\1\2\3\4\5可以将分组替换位置,也可以在分组内直接替换字符

# 要求:将is左右两边的单词调换位置lqz123+ is sb09
# print(re.sub('([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)([^a-zA-Z]+)', r'\5\2\3\4\1\6', r'lqz123+ is sb09'))
# 首先明白单词的定义:由连续的字母组成。
# 基于这个理念来将字符进行分组,然后将分组调换位置即可

# ==============================================================================

# re模块之正则表达式compile的应用
# res = re.compile('alex')                   # 使用compile将经常用到的表达式定义成一个变量
# print(res.findall('alex_sb alex123 ale'))  # 通过变量就可以直接去匹配相应的字符

  

posted @ 2018-10-21 23:32  BlackLinks  阅读(151)  评论(0编辑  收藏  举报