学习python课程第二十天,,一. loggin


一. logging模块

  1. 日志的级别分别有:

    logging.debug (‘‘这是一个调试信息‘‘) #10 级别最低

    logging.info (‘一些常规的信息‘) #20

    logging.warning (‘警告信息‘) #30

    logging.error (‘错误信息‘) #40

    logging.critical (‘严重错误‘) #50

    # 在logging模块中又对应的常量用来表示级别

     默认情况下 默认级别是#30 waming 日志输出位置是控制台

  2. 自定义日志的配置

  示例:

    logging.basicConfig(

      filename = ‘a.log‘

      filemode = ‘at‘

      level = 10,

      format = ‘%(asctime)s %(levelname)s %(funcName)s %(lineno)s %(message)s‘,

      datefmt = ‘%Y-%m-%d %X %p‘)

    logging.debug(‘这是调试信息‘)

  可用参数:

    filename : 用指定的文件名创建FiledHandler (后边会具体讲解handler的概念) , 这样日志会被存储到

    指定的文件中

    

    filemode : 文件打开的方式, 在指定了filename时使用这个参数, 默认值为 ‘a‘ 还可以指定为 ‘w‘ .

    

    format : 指定handler使用的日志显示格式

    datefmt : 指定日期的格式

    level : 设置root logger (后边会讲解具体的概念) 的日志级别

    stream : 用指定的stream 创建streamHandler . 可以指定输出到sys.stderr , sys.stdout 或者文件

    默认为 sys.stderr, 若同时列出了filename 和 stream两个参数. 则stream参数会被忽略.

    可用的格式分别为 :

      %(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:35 , 897‘.逗号后面是毫秒

      %(therad)d : 线程ID, 可能没有

      %(theradName)s : 线程名 可能没有

      %(process)d: 进程ID, 可能没有

      %(message)s : 用户输出的消息

  3. 如何能够同时输出到多个位置 ?

   logging中的四个核心角色 !!

    1. logger 生成器

    2. handler 处理器

    3. filter 过滤器

    4. formatter 格式化

    

    一条日志完整的生命周期 :

    1. 由logger 产生日志 -> 2. 交给过滤器判断是否被过滤 -> 3. 将日志消息分发给绑定的所有处理器. -> 4.

    处理器按照绑定的格式化对象输出日志

    其中, 第一步会先检查日志的级别, 如果低于设置的级别, 则不执行 第四步 如果不指定格式则按照默认格式

    1. 创建一个日志生成器 :

    mylog = logging.getLogger(‘mylog‘)

    # 设置生成器级别

    mylog.setLevel(logging.DEBUG)

    2. 创建一个日志处理器 :

    fh = logging.FileHandler(‘b.log‘,encoding=‘utf-8‘)

    3. 创建一个格式处理器

    fm = logging.Formatter(

      ‘%(asctime)s %(levelname)s %(funcName)s %(lineno)s %(message)s‘ ,

       datefmt = ‘%Y-%m-%d %X %p‘)

  

    4. 将三个对象进行关联

    mylog.addHandler(fh)

    fh.setFormatter(fm)

    # 测试

    mylog.debug(‘mylog 的 测试‘)

  4. 日志的继承

    可以将一个日志指定为另一个日志的子日志, 或子孙日志, 当存在继承关系时, 子孙级日志收到日志时

    会将该日志向上传递,

    指定继承关系 :

    log1 = logging.getLogger(‘father‘)

    log2 = logging.getLogger(‘father.son‘)

    log3 = logging.getLogger(‘father.son.grandson‘)

    # 默认值为True, 表示 有继承关系. 当子的日志产生日志时, 给他父级以及父级以上都发一份.

    如果不需要, 就设置为False

    log3.propagate = False

    fh = logging.FileHandler(‘c.log‘.encoding=‘utf-8‘)

    fm = logging.Formatter(

      ‘%(asctime)s %(levelname)s %(funcName)s %(lineno)s %(message)s‘ ,

      datefmt = ‘%Y-%m-%d %X %p‘)

    log1.addHandler(fh)

    log2.addHandler(fh)

    log3.addHandler(fh)

    fh.setFormatter(fm)

    # 测试

    log3.error(‘测试‘)

    # 取消传递

    log3.propagate = False

    

    log1.warning(‘father log‘)

    log2.warning(‘father.son log‘)

    log3.warning(‘father.son.grandson log‘)  

  

  5. 通过字典配置日志模块

     每次都要编写代码来配置,非常麻烦, 我们最好能够写一次到处用.

    logging.config.dictConfig()

  6. 加载配置 :

    import logging.config

    logging.config.dictConfig (LOGGING_DIC)

    logging.getLogger(‘aa‘).debug(‘测试‘)

    

    # getLogger参数就是对应字典中loggers的key 如果没有匹配到key 什么都不做, 很多情况我们的日志

    可能对应不同的业务模块 我们需要在日志中体现业务信息 那问题是, 我的配置中不可能预先知道所有

    的业务名称 这时候我们可以将key设置为空, 这样以来, 获取的时候如果找不到对应的就用默认的. 并且

    日志对象的名称会变成你传入的key

    

  7. 流 处理器

    log1 = logging.getLogger(‘a‘)

    

    #输出文件

    fh = logging.FileHandler(‘c.log‘,encoding=‘utf-8‘)

    #输出到控制台

    sh = logging.StreamHandler()

    log1.addHandler(sh)

    log1.addHandler(fh)

    fm = logging.Formatter(

      ‘%(asctime)s %(levelname)s %(funcName)s %(lineno)s %(message)s‘,

      datefmt = ‘%Y-%m-%d %X %p‘)

    sh.setFormatter(fm)

    log1.warning(‘测试2!‘)

    import lib.common

    logger = lib.common.get_logger()

    def login():

      logger.debug(‘测试 测试!‘)

    login()

  

二. hashlib模块

  1. 什么是hash lib

    hash是一种算法, 是将一个任意长的数据, 根据计算, 得到一个固定长度特征码

    特征: 不同输入, 可能会有相同的结果. 但是几率特别小.

       相同的输入 必然得到相同的结果

       由于散列(特征)的性质 从原理来看是不可能反解的.

    用来验证 两个输入的数据是否一致

    使用场景

    1. 密码验证

             123432 44sdas4kkas4tk

            client 加密后的结果. server 拿到加密后.

    2. 验证数据是否被篡改过. 比如游戏安装包. 可以对比一下有没有被改过

    为了防止别人撞库成功 可以提升密码的复杂度. 其次可以为密码加盐 (加点内容进去)

    示例:

      import hashlib

      m = hashlib.md5(‘aaa.encode(‘utf-8‘)‘)

      print (len(m.hexdigest()))

      # 撞库破解的原理. 有人事先把常见的明文和密文的对应关系存到了数据库中.

        运气好就能查到

      # 可以选择密文的长度,

      h1 = hashlib.sha512(‘123‘.encode(‘utf-8‘))

      print(h1.hexdigest())

    加盐:

      m = hashlib.md5(‘321‘.encode(‘utf-8‘))

      # 加

      m.update(‘asfasfafasf‘.encode(‘utf-8‘))

      print (m.hexdigest())

    在创建的时候必须加盐的类型

      import hmac

      h = hmac.new(‘asdad‘.encode(‘utf-8‘))

      h.update(‘123‘.encode(‘utf-8‘))

      print(h.hexdigest())

三. re 模块

  re是Regular Expression 的简称, 表示正则表达法

    什么是正则表达式 ?

    表达式指的是默写带有特殊含义的符号或者符号组成的式子

    正则表达式是对字符进行处理的逻辑公式, 使用特殊字符或者一些特殊字符的组合,

    组成一个规则字符串, 这个规则字符串用来表达对字符的过滤逻辑

    支持的字符及其表达的含义.

  re 的使用:

    在爬虫里大量的使用 其实有框架帮你封装了这些复杂的正则

    在网站和手机app的注册功能中大量使用, 例如判断你的邮箱地址是否正确,

  1. 普通匹配.

    \s \w \d \n \t .

  2. 重复匹配.

    *: 任意, +:1- 无穷 ?:0 - 1

  3. 范围匹配

    a|b|c [abc] [0-9] [a-z] [A-Z] [0-9a - zA - Z] 注意: 仅匹配一个字符. 它的范围是根据ascii码表

    

    print(re.findall("\w","1aA_*")) # 匹配数字字母下划线
   
    print(re.findall("\W","1aA_*,")) # 匹配非数字字母下划线
    
    print(re.findall("\s"," \n\r\t\f")) # 匹配任意空白字符
    
    print(re.findall("\S"," \n\r\t\f")) # 匹配任意非空白字符
    
    print(re.findall("\d","123abc1*")) # 匹配任意非空白字符
    
    print(re.findall("\D","123abc1*")) # 匹配任意非空白字符
    
    print(re.findall("[abc]","AaBbCc")) # 匹配 a b c都行
    
    print(re.findall("[^abc]","AaBbCc")) # 除了 a b c都行
    
    print(re.findall("[0-9]","AaBbCc12349")) # 除了 a b c都行
    
    print(re.findall("[a-z]","AaBbCc12349")) # a-z 英文字母
    
    print(re.findall("[A-z]","AaBbC:c??2349[]")) # A-z 匹配原理 是按照ascII码表


4.匹配位置

    print(re.findall("\A\d","123abc1*")) # 从字符串的开始处匹配
    
    
print(re.findall("\d\Z","123abc1*9\n")) # 从字符串的结束处匹配 注意把\Z写在表达式的右边
    
    print(re.findall("\d$","123abc1*9")) # 从字符串的结束处匹配 如果末尾有换行 换行不会参与匹配
    
    
    print(re.findall("^\d","s1asasas121 \t")) # 从字符开始匹配数字


  

学习python课程第二十天

评论关闭