一.time
1.时间表示形式
在Python中,通常有这三种方式来表示时间:时间戳、元组(struct_time)、格式化的时间字符串:
(1)时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
(2)格式化的时间字符串(Format String): ‘1988-03-16’
(3)元组(struct_time) :struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天等)
#<1> 时间戳 >>> import time >>> time.time() 1493200540.9646277 # <2> 时间字符串 >>> time.strftime('%Y-%m-%d %X') '2017-04-26 17:56:30' # <3> 时间元组 >>> time.localtime() time.struct_time(tm_year=2017, tm_mon=4, tm_mday=26, tm_hour=17, tm_min=56, tm_sec=48, tm_wday=2, tm_yday=116, tm_isdst=0)
小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
2.几种时间形式的转换
(1)
#一 时间戳<---->结构化时间: localtime/gmtime mktime >>> time.localtime(3600*24) >>> time.gmtime(3600*24) >>> time.mktime(time.localtime()) #字符串时间<---->结构化时间: strftime/strptime >>> time.strftime("%Y-%m-%d %X", time.localtime()) >>> time.strptime("2017-03-16","%Y-%m-%d")
(2)
>>> time.asctime(time.localtime(312343423)) 'Sun Nov 25 10:03:43 1979' >>> time.ctime(312343423) 'Sun Nov 25 10:03:43 1979'
1 #--------------------------其他方法 2 # sleep(secs) 3 # 线程推迟指定的时间运行,单位为秒。
二.random模块
>>> import random >>> random.random() #大于0且小于1 之间的小树 0.7032311694364002 >>> >>> random.randint(1,5) #1<=且<=5之间的整数 3 >>> >>> random.randrange(1,3) #大于等于1且小于3之间的整数 2 >>> >>> random.choice([1,'23',[4,5]]) #1或23或[4,5] [4, 5] >>> >>> random.sample([1,'23',[4,5]],2) #列表元素任意2个组合 ['23', [4, 5]] >>> >>> >>> random.uniform(1,3) #大于1 小于3的小数 1.1161744833134866 >>> >>> >>> >>> l = [1,3,5,7,9] >>> >>> random.shuffle(l) #打乱次序 >>> l [1, 3, 7, 5, 9] >>> random.shuffle(l) #再次打乱 >>> l [9, 7, 3, 1, 5]
#生成验证码:
import random def v_code(): code = '' for i in range(5): num=random.randint(0,9) alf=chr(random.randint(65,90)) #asiic码 add=random.choice([num,alf]) code="".join([code,str(add)]) return code print(v_code())
三.hashlib
1.算法介绍
python的hashlib提供了常见的摘要算法,如MD5,SHA1等。。。
摘要算法又称 哈希算法,散列算法。它通过一个函数,把任意长度的数据转为一个长度固定的数据串(通常用16进制的字符串)
摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib m = hashlib.md5() m.update('alex'.encode('utf8')) print(m.hexdigest()) #输出结果 534b44a19bf18d20b71ecc4eb77c572f
import hashlib m = hashlib.md5() m.update('alex'.encode('utf8')) #534b44a19bf18d20b71ecc4eb77c572f print(m.hexdigest()) m.update('alex'.encode('utf8')) #alexalex print(m.hexdigest()) n = hashlib.md5('salt'.encode('utf8')) n.update(b'alexalex') print(n.hexdigest())
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
import hashlib m = hashlib.md5() m.update('how to use md5 in python hashlib?'.encode('utf8')) print(m.hexdigest()) ##结果 #d26a53750bc40b38b65a520292f69306 m = hashlib.md5() m.update('how to use md5 in '.encode('utf8')) m.update('python hashlib?'.encode('utf8')) print(m.hexdigest()) ##结果 d26a53750bc40b38b65a520292f69306
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,不过越安全的算法越慢,而且摘要长度更长。
2.摘要算法应用
任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:
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。
摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
四.os模块
os模块是与操作系统交互的一个接口
''' os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","newname") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 输出操作系统特定的路径分隔符,win下为"\",Linux下为"/" os.linesep 输出当前平台使用的行终止符,win下为" ",Linux下为" " os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 os.path.getsize(path) 返回path的大小 '''
模块操作:
#----->1 import os print(os.getcwd()) f = open('test.txt','w') os.chdir(r'D:pycharmcatalogpy_fullstack_s4day32') #将路径33改为 32 f = open('test2.txt','w') print(os.getcwd()) #----->2 import os os.makedirs('aaaaa/bbb') os.removedirs('aaaaa/bbb') #----->3 import os print(os.listdir(r'D:pycharmcatalogpy_fullstack_s4/day33')) ##输出结果 ##['aaaaa', 'osmy.py', 'test.txt', 'validation.py', '__init__.py', '摘要哈希.py', '随机数.py'] print(os.stat(r'D:pycharmcatalogpy_fullstack_s4/day33/test.txt')) #----->4 # 'pang'+os.sep+'di' print(os.name) print(os.system('dir')) #----->5 import os abs = os.path.abspath('test.txt') print(os.path.basename(abs)) print(os.path.dirname(abs)) #输出结果 test.txt D:pycharmcatalogpy_fullstack_s4day33 #----->6 import os s1 = r'D:/pycharm/catalog' s2 = r'py_fullstack_s4/day33' # print(s1+os.sep+s2) ret = os.path.join(s1,s2) #推荐方法 print(ret) #输出结果 D:/pycharm/catalogpy_fullstack_s4/day33
五.sys模块
sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version 获取Python解释程序的版本信息 sys.maxint 最大的Int值 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称
六.re模块
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符匹配(普通字符,元字符):
1.普通字符:大多数字符和字母都会和自身匹配
import re r = re.findall('pangdi','tom123pangdi712') print(r) #输出结果 ['pangdi']
2.元字符:. ^ $ * + ? {}
1.#. :匹配出 以外的的任意字符
import re print(re.findall('a.','abcd')) print(re.findall('a..d','abcd')) print(re.findall('a.+d','abcd')) #结果 ['ab'] ['abcd'] ['abcd']
2.# ^ :从字符串开始的位置匹配
# $ :从字符串结尾匹配
import re print(re.findall('^tom','tom123jack321')) print(re.findall('333$','123tom321jack333')) #输出结果 ['tom'] ['333']
3.# * + ? {} :重复
import re print(re.findall('a+','wf34DW410wwre7890awww')) print(re.findall('[0-9]{4}','af34DW410re7890')) #输出结果 ['aaa', 'aa', 'a'] ['7890']
4. #贪婪匹配
import re print(re.findall('abc{1,3}','abcccKccc')) print(re.findall('abc{1,3}','abcdcccc')) #结果 # ['abccc'] # ['abc'] print(re.findall('d+','af12www3456KK9873')) print(re.findall('[^0-9]+','af12www3456KK9873')) #结果 ['12', '3456', '9873'] ['af', 'www', 'KK']
#非贪婪匹配
import re print(re.findall("d+?","af33K6666HH34WW77"))
#结果
['3', '3', '6', '6', '6', '6', '3', '4', '7', '7']
元字符之
1.元字符之字符集 []:
#---------> 1 import re r = re.findall("a[bc]d", "wwwabdkkkacd") r1 = re.findall('a[bc]d','abcd') print(r) print(r1) # #输出结果 ['abd', 'acd'] [] #---------> 2 import re r = re.findall('[a-zA-Z]','acDef') print(r) #结果 ['a', 'c', 'D', 'e', 'f'] #----------> 3 import re r = re.findall('[.*+]','a.cd+') r1 = re.findall('[.*+]','a.c+d*') print(r) print(r1) #结果 ['.', '+'] ['.', '+', '*']
在字符集里有功能的符号: - ^
import re ret = re.findall('[1-9]','3abc45') ret1 = re.findall('[^ab]','6akb45') ret2 = re.findall('[d]','6akb45') print(ret) print(ret1) print(ret2) #输出结果 ['3', '4', '5'] ['6', 'k', '4', '5'] ['6', '4', '5']
2.元字符之转义符
反斜杠后边跟元字符去除特殊功能 比如: .
反斜杠后边跟普通字符实现特殊功能 比如: d
d 匹配任何十进制数;它相当于类 [0-9]。
D 匹配任何非数字字符;它相当于类 [^0-9]。
s 匹配任何空白字符;它相当于类 [
fv]。
S 匹配任何非空白字符;它相当于类 [^
fv]。
w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
匹配一个特殊字符边界,比如空格 ,&,#等
import re r = re.findall('I','I am LIST') r1 = re.findall(r'I','I am LIST') print(r) print(r1) #输出结果 [] ['I']
我们聊一聊 先看下面两个匹配:
#-----------------------------eg1: import re ret=re.findall('cl','abcle') print(ret)#[] ret=re.findall('c\l','abcle') print(ret)#[] ret=re.findall('c\\l','abcle') print(ret)#['c\l'] ret=re.findall(r'c\l','abcle') print(ret)#['c\l'] #-----------------------------eg2: #之所以选择是因为在ASCII表中是有意义的 m = re.findall('blow', 'blow') print(m) m = re.findall(r'blow', 'blow') print(m) #结果 [] ['blow']
3.元字符之()分组
import re r = (re.findall('(ad)+','addd')) #把 ad 划分为一个组 print(r) #结果: ['ad'] r1 = (re.findall('(ad)+yuan','adddyuanqwe')) print(r1) #结果:[] #分组优先级 r2 = (re.findall('(ad)+yuan','adyuanqwe')) print(r2) #结果竟然是: ['ad'] !!! r3 = (re.findall('(d)+yuan','ad3456yuanqwe')) print(r3) #结果: ['6'] #取消分组优先级 ?: new_r2 = (re.findall('(?:ad)+yuan','adyuanqwe')) print(new_r2) #想要的结果:['adyuan'] new_r3 = (re.findall('(?:d)+yuan','ad3456yuanqwe')) print(new_r3) #['3456yuan']
#命名分组 ?P<name>
import re # r = re.findall(r'w+.aticles.d{4}','yuan.aticles.1234') # print(r) #结果:['yuan.aticles.1234'] # r1 = re.findall(r'(w+).aticles.(d{4})','yuan.aticles.1234') # print(r1) #结果:[('yuan', '1234')] #命名形式 ?P<name> r2 = re.search(r'(?P<author>w+).aticles.(?P<id>d{4})','yuan.aticles.1234') print(r2) #<_sre.SRE_Match object; span=(0, 17), match='yuan.aticles.1234'> print(r2.group('author')) print(r2.group('id')) #输出结果 <_sre.SRE_Match object; span=(0, 17), match='yuan.aticles.1234'> yuan 1234
4. 元字符之 | (或)
print(re.findall("www.(?:oldboy|baidu).com","www.oldboy.com")) #结果 ['www.oldboy.com']
re模块下的常用方法
1.返回所有满足匹配条件的结果,放在列表里
import re print(re.findall('n','alvin yuan')) #结果 ['n', 'n']
2.search
#函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象
# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
import re r = re.search('n','alvin yuan') print(r.group()) #结果 n
3.match
只在字符串开始的位置匹配
import re r = re.match('d+','34fgq67qwe') print(r.group()) #结果 34
4.split
分割
import re r = re.split('d+','asd34fg673qwe3065',1) r2 = re.split('d+','asd34fg673qwe3065',2) print(r) print(r2) #结果 ['asd', 'fg673qwe3065'] ['asd', 'fg', 'qwe3065']
5.sub
替换
import re r = re.sub('d+','A','hello 234www12367z',1) r1 = re.sub('d+','A','hello 234www12367z') print(r) print(r1) #结果 hello Awww12367z hello AwwwAz
6.compile
编译方法
import re c=re.compile("d+") r=c.findall("hello32world53") #== re.findall("d+","hello32world53") print(r) #结果 ['32', '53']
7.
import re r=re.finditer('d','ds3s4784a') print(r) print(next(r).group()) print(next(r).group()) print(next(r).group()) #结果 <callable_iterator object at 0x02A9F810> 3 4 7
注意:
import re r=re.findall('www.(baidu|oldboy).com','www.oldboy.com') print(r) #['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 r1 = re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') print(r1) #['www.oldboy.com']
补充:
import re print(re.findall("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")) print(re.search("<(?P<tag_name>w+)>w+</(?P=tag_name)>","<h1>hello</h1>")) print(re.search(r"<(w+)>w+</1>","<h1>hello</h1>")) #结果 ['h1'] <_sre.SRE_Match object; span=(0, 14), match='<h1>hello</h1>'> <_sre.SRE_Match object; span=(0, 14), match='<h1>hello</h1>'>
补充2:
#匹配出所有的整数 import re #ret=re.findall(r"d+{0}]","1-2*(60+(-40.35/5)-(-4*3))") ret=re.findall(r"-?d+.d*|(-?d+)","1-2*(60+(-40.35/5)-(-4*3))") ret.remove("") print(ret) #结果 ['1', '-2', '60', '5', '-4', '3']