|
模块的分类
参考博客http://www.cnblogs.com/alex3714/articles/5161349.html
python中的模块分为三大类:
1.标准库(内置模块)
2.开源模块(第三方模块)
3.自定义模块(自己写的.py文件模块)
标准库
1.time
UTC是世界标准时间,中国是在东8区(GMT+8)
![image_1c0bi1c1j1pkr1rn91ovspjf1omo9.png-4.6kB][1]
导入time模块,通过time.timezone查看时区,28800是秒单位,除60是分钟,在除60的结果是小时,也就是说中国时区比UTC早8个小时。
1.1 time.time
![image_1c0bi20qd1hi61lm35m416qd5e7m.png-2.3kB][2]
time.time()查看时间戳,以秒为单位,这个数字实际没什么大的意义,只不过是从1970年开始算起到当前经历了多少秒。从1970年开始算是因为这是Unix诞生的时间。
![image_1c0bi2huj107sqhj1vej9ifle713.png-5.9kB][3]
1507535507/60/60/24/365(最终求的是多少年),结果是从1970年到现在为47年,1970+47就是今年的2017年。
1.2 time.sleep
![image_1c0bi30g51bnvevd1391asr7ug1g.png-1.6kB][4]
用于延迟,图中定义了延迟3秒
在写代码时,可以利用time.sleep延迟多久后在继续执行后续的代码。
1.3 time.gmtime
![image_1c0bi3mtd4ki1rgt12fvhoka4e1t.png-6.7kB][5]
以元组的方式转换时间戳,显示转换的时间,默认显示的是当前UTC的时间(不是中国东八区时间),比东八区差了8个小时。
时间格式为:年、月、日、小时、分钟、秒、本周第几天(从0开始算)、本年第几天(1-366)、是否是夏令时
![image_1c0bi434g1v2n1aprg9kqrk1te72a.png-7.6kB][6]
在括号中输入以秒为单位的数字进行计算UTC的时间(从1970年开始算)
1.4 time.localtime
![image_1c0bi5qjai2j1ken227chthjt3h.png-6.6kB][7]
以元组的方式转换时间戳,显示的是本地的时间。
![image_1c0bi688v11i51g2c1l051srqupe3u.png-10kB][8]
元组中的时间数据类似字典,当想要取出时间时,取对应的key就可以看到相应的value
![image_1c0bi6hjnh7a1v11ut31ul1gmm4b.png-14.9kB][9].
取出指定时间戳,显示是哪年的第多少天。
1.5 time.mktime
![image_1c0bi7328c3qj6n8h69bo1snk4o.png-2.7kB][10]
将具体的格式时间转换为时间戳
1.6 time.strftime与time.strptime
time.strftime用于将具体格式时间转换为格式化的字符串时间
![image_1c0bi7ig9t5f9pp144o1f0p5nj55.png-63.7kB][11]
通过help查看用法,可以看到%符号后面对应字母所代表的内容,图中红线部分是使用格式。
![image_1c0bi7vd21ov0uisg5714rc1shg5i.png-4.6kB][12]
%Y:年
%m:月
%d:日
%H:小时
%M:分钟
%S:秒
![image_1c0bi8ktmssm1r8jtj4u1hasv5v.png-61kB][13]
strptime的使用格式
strptime是用来将字符串转为具体的格式时间
![image_1c0bi9cgi81eu0q1g05hsubln6c.png-10.4kB][14]
strptime是与strftime相反的功能,这里用逗号隔开的两边内容格式要一 一对应,2017对应%Y,10对应%m,这里位置上的联系一定要对应。
![image_1c0bi9udvbi1l0ikkf1jea1fs16p.png-9.6kB][15]
strftime使用时间格式默认就是本地时间,可以通过指定其他的时间来输出字符串格式的时间,time.localtime相当于给这个格式赋值
![image_1c0bia92f9cg17kj19fchbliiq76.png-13kB][16]
调整格式的位置,输出的字符串时间格式也会随着改变
当前的x相当于2017-10-11 xx:xx:xx,而格式没有与该时间想对应,说明使用strftime在位置上的格式是没有联系的
1.7 time.asctime
![image_1c0bianj0dedhi214cm1r1lqq17j.png-19.3kB][17]
![image_1c0bias9n1l9974h9njdi6106a80.png-3.5kB][18]
用英文的方式进行表示(将元组的格式事件转换为英文时间格式)
![image_1c0bib8gnbuv17er2dji2oa3r8d.png-3.7kB][19]
1.8 time.ctime
用于将时间戳转换为英文时间格式
![image_1c0bibknfqd91ojs17671eh1k7f8q.png-9.8kB][20]
2.datetime
datetime.date 获取年月日
datetime.time 获取时分秒
datetime.datetime 获取年月日时分秒
![image_1c0bici7tr8jotq6is15nn1def97.png-4.6kB][21]
获取现在的时间
![image_1c0bics6ehj5567qn0cfn7s99k.png-9.6kB][22]
显示根据当前时间+3天;显示根据当前时间-3天
![image_1c0bidam5djm1mh0125r7irm95a1.png-10.7kB][23]
前后的小时 时间
3.random模块
3.1 random.random
![image_1c0bidt661st9ltc1tng6dbkuoae.png-8.9kB][24]
随机获取浮点数
3.2 random.randint
![image_1c0bieb2um9uquv1cmc1vu2q7qar.png-12.5kB][25]
随机获取指定的整数
3.3 random.randrange
![image_1c0bien86ad11rh9021n8scnb8.png-13.5kB][26]
使用randrange和range类似,最后一个数字不算
3.4 random.choice
![image_1c0bif49i1g9goma1ovhe9912kbl.png-20.2kB][27]
在不同的数据类型中随机选值
3.5 radom.sample
![image_1c0big5tn14abk9j1vf2fv01u0oc2.png-14.2kB][28]
随机取两个值
3.6 random.uniform
random.random默认只能取值0-1的浮点数,可以通过random.uniform来指定浮点数范围
![image_1c0bigmvoepf10roneo11nq1etacf.png-20.1kB][29]
3.7 random.shuffle(洗牌功能)
![image_1c0bihqs5131lh910gk1nfgpqmcs.png-5kB][30]
把顺序打乱
3.8 验证码练习
3.8.1使用数字验证
import random
checkcode = ''
for i in range(4): #指定4位验证码的长度
current = random.randint(0,9) #指定随机数字
checkcode+=str(current) #将随机的数字加入到变量中
print (checkcode) #打印随机的验证码
![image_1c0bijapt16v2ej91ug01gju14aod9.png-0.7kB][31]
3.8.2使用数字+字母验证
![image_1c0bijkuqskr17tshu3036lodm.png-2.6kB][32]
chr65到69 一 一对应了A-Z字母
checkcode = ''
for i in range(4): #循环4次,相当于4位长度的验证码
current = random.randint(0,4) #设定current随机数字与range范围相等
if current == i:
tmp = chr(random.randint(65,90)) #随机匹配:当current等于i时,就随机一个字母
else:
tmp=random.randint(0,9) #当current不等于i时,就随机一个数字
checkcode+=str(tmp) #将tmp产生的数字或字母加入到checkcodee变量中
print (checkcode)
![image_1c0bikp1po7q13hh1o191t994dne3.png-0.8kB][33]
字母+数字的随机验证码
4.OS模块
http://python.usyiyi.cn/translate/python_278/library/os.html
os模块使用参考网址
os用于调取系统命令
4.1 os.getcwd
![image_1c0bilu6c1cgiu351k6h7dra9eg.png-5.2kB][34]
获取当前操作目录
4.2 os.chdir
![image_1c0bimdeb1d2s1j2t1dg21u8k1tonet.png-4.4kB][35]
切换操作目录
c:后面是两个\,第一个\是转译符,使用\只能转译后面的一个符号
![image_1c0bin1jl1hmpcaf571vqipunfa.png-7.7kB][36]
通过用r来转义
4.3
图中的os.xxx在该博客属于违规内容无法输入
![image_1c0binjejnbenno1e231nqnek1fn.png-1.5kB][37]
返回当前目录
一个点'.'表示当前目录
4.4 os.pardir
![image_1c0bip3fam0a1pu819kl1m1npf3g4.png-1.5kB][38]
返回上级目录
两个'..' 两个点表示上级目录
4.5 os.makedirs与 os.removedirs
4.5.1
![image_1c0bipq7lc3d1brj1olr18c1cc8gh.png-2.9kB][39]
在D盘先建立a目录,在a目录中建立b目录,以此类推
![image_1c0biq44ifjr1ffe1v2oqt8h1gu.png-7.9kB][40]
makedirs可以建立多个目录
4.5.2
![image_1c0bisl0f1v4p1o1sjdk1m881j9thr.png-6.5kB][41]
在a目录中建立一个文档
![image_1c0bitgst1aav7121lt2ge71q6kil.png-2.7kB][42]
![image_1c0bitle91v3i73g7ckdbafgtj2.png-5.7kB][43]
可以看到除了D盘和a目录,其他目录都被删除了;这是因为使用os.removedirs是删除空的目录,当前D盘和a目录都是非空
removedirs是递归的删除,只要上一层目录为空就删除,会删掉多个空的目录
4.6 os.mkdir
mkdir也是用于建立目录的,只不过是建立单个目录的
![image_1c0bj1gu11a331ou15teheq1r4tjf.png-11.1kB][44]
建立多个目录失败
![image_1c0bj1r2mditgbv1rc63063vdjs.png-2.3kB][45]
![image_1c0bj1vtteng7qrqqgire16m9k9.png-6.5kB][46]
建立单个目录,建立多级目录的话,需要一个一个的去建立
4.7 os.rmdir
![image_1c0bj2iv61dfc2u57lj9h75pkkm.png-3.5kB][47]
将原有的目录删除,重新建立,然后通过rmdir删除,只会删除一个目录,不会删除多个。
![image_1c0bj49811nkr9f41n9l1msvmsrmg.png-4.7kB][48]
4.8 os.listdir
![image_1c0bj431l1tdrdrsn3nmd4afm3.png-10.8kB][49]
以列表的方式列出当前目录有哪些内容
‘.’表示当前目录
默认也是列出当前目录
![image_1c0bj4oat1ff79bj1fd81fnavp6mt.png-2.6kB][50]
列出指定目录内容
4.9 os.remove
删除指定内容
4.10 os.rename
os.rename('oldname','newname') 重命名
4.11 os.stat
获取指定内容属性信息
![image_1c0bj5ht865hct4ldhhi216itna.png-9kB][51]
4.12 os.sep
在Windows中路径是用 右斜杠\ 来表示分隔的
在linux中路径是用左斜杠/来表示分隔
![image_1c0bj5sd11s1o38b1nmg1pr3i4nn.png-18.6kB][52]
os.sep会根据系统的不同,来改变分隔符的,在Windows中是\(其中一个\是转译符),使用os.sep代替\,这样即使在不同的操作系统也能正确的使用对应的分隔符
4.13 os.linesep
![image_1c0bj67giohb36b71s13ad1j6po4.png-1.7kB][53]
换行符是\r\n
4.14 os.environ与os.pathsep
![image_1c0bj6ivthkr1io7106r1fj2vtoh.png-71.6kB][54]
通过environ获取系统的环境变量,以字典格式显示,在Windows中 如果一个key对应多个路径的话是以分好‘;’分隔的,os.pathsep就是对应这个分隔符(在Windows中对应‘;’,在linux中对应‘:’)
![image_1c0bj6uhrr4vhhh1b7fjf15a5ou.png-1.8kB][55]
4.15 os.name
![image_1c0bj8q52kj31hgh7j6aii18sopb.png-1.5kB][56]
显示当前系统类型,nt表示Windows
4.16 os.system
用来执行当前系统的命令
![image_1c0bj96gs7pf19q535813hk1720po.png-44.2kB][57]
编码不同,所以显示乱码
4.17 os.path
4.17.1 os.path.abspath
获取绝对路径(之前在导入模块时使用过,导入不同目录的模块)
4.17.2 os.path.split
![image_1c0bjac20lmcubf17sj1p4hjl2q5.png-4.2kB][58]
以元组的方式显示,将目录和文件分隔开。
4.17.3 os.path.dirname与os.path.basename
![image_1c0bjaqd1aaplif1eqh7q1unkqi.png-10kB][59]
一个取目录名,一个结尾的。
4.17.4 os.path.exist
![image_1c0bjbbhm1rp1g5b1ja31n811eqjqv.png-2.6kB][60]
判断路径是否存在
4.17.5 os.path.isabs
![image_1c0bjce57l1b27a1ptj1ieatnors.png-2.8kB][61]
判断是否是以根开头的绝对路径
在Windows中每个盘符都是根,在linux中/是根
如果False的话就是相对路径
4.17.6 os.path.isfile与 os.path.isdir
![image_1c0bjet2f14qbkr416vb17io12p2s9.png-5.7kB][62]
判断是否是一个文件
![image_1c0bjf7g71tr21746s0h1u2t12pnsm.png-2.8kB][63]
判断是否是目录
4.17.7 os.path.join
![image_1c0bjgf4j1q7eu04c1r1v2uu0lt3.png-4.3kB][64]
将目录与文件组合并返回
4.17.8 os.path.getatime与 os.path.getmtime
![image_1c0bjguheji37n6g2r1m07594tg.png-6.9kB][65]
获取文件的最后存取时间,时间格式为时间戳
![image_1c0bjha236ln1ckt1ups1kqoqqstt.png-6.9kB][66]
获取修改时间
5. sys与shutil模块
sys模块没有细讲,请单独翻阅资料
5.1 sys.version
![image_1c0bji91j1kg81f69154j10s71nagua.png-8.1kB][67]
获取当前python的版本信息
5.2 sys.argv
获取相对路径(初始模块文章中讲过)
6. shutil模块
shutil用于copy文件用的
6.1 shutil.copyfileobj
import shutil
f1 = open('test1.txt',encoding='utf-8')
f2 = open('test2.txt','w',encoding='utf-8')
shutil.copyfileobj(f1,f2)
![image_1c0bjmetm1v2eg3m10kbsf4qv2v7.png-6.8kB][68]
成功的将test1中的内容copy到test2
6.2 shutil.copyfile
shutil.copyfile中已经带有打开文件的代码,所以无需额外再次打开文件了,直接使用即可
![image_1c0bjn1en19mb1dtg10fh1rgm1et1vk.png-4.4kB][69]
![image_1c0bjn7at9mg1hkm1aceb0k15pt101.png-7.3kB][70]
6.3 shutil.copymode
将文件的权限拷贝,新文件的用户属主是新用户
6.4 shutil.copystat
![image_1c0bjnjkf57o1nu2vce14jitl10e.png-4.1kB][71]
只copy了权限
6.5 shutil.copytree与shutil.rmtree
![image_1c0bjo3dgsa21lqq12i21bsq1v5210r.png-19.2kB][72]
![image_1c0bjo8tr1t61v3ni3o5ee1hjj118.png-20.4kB][73]
6.6 shutil.make_arvhive
![image_1c0bjoiqr1fgcc48flo15mo1sgg11l.png-3.5kB][74]
![image_1c0bjp4qm1dkr1qfks8kjnl2j2122.png-19.9kB][75]
默认在当前操作目录
![image_1c0bjpfd5asvrjb1j8joh188h12f.png-6.8kB][76]
![image_1c0bjpmb812ja17m31buts8hqtg12s.png-2.1kB][77]
指定目录
6.7 zipfile、tarfile
import zipfile
压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()
解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall()
z.close()
压缩
import tarfile
tar = tarfile.open('your.tar','w')
tar.add('/Users/wupeiqi/PycharmProjects/bbs2.log', arcname='bbs2.log')
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb.log')
tar.close()
解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
tar.close()
7. json、pickle、shelve
json,用于字符串 和 python数据类型间进行转换
pickle,用于python特有的类型 和 python的数据类型间进行转换
Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load
7.1 json
json之前整理过,可以在不同的语言或系统平台进行数据的转换
只支持部分数据类型
s1={"k1":"v1"}
st=json.dumps(s1)
print(st,type(st))
s='{"k1":"v1"}'
dic=json.loads(s)
print(dic,type(dic))
输出结果为:
{"k1": "v1"} <class 'str'>
{'k1': 'v1'} <class 'dict'>
可以看出json的dumps方法处理数据时会将数据转换为字符类型,loads则会重新还原它的类型。
再来看json的dump和load方法,通过示例来了解:
li=[11,22,33]
li=json.dump(li,open('db','w'))
li=json.load(open('db','r'))
print(li,type(li))
输出结果为:
[11, 22, 33] <class 'list'>
Json模块dumps、loads、load、dump的区别:
load,dump可加载外部文件,处理文件的数据,dumps,loads主要处理内存中的数据
7.2 pickle
pickle之前整理过,只能在python之间数据进行转换(如不同版本)
支持全部数据类型
import pickle
i=[11,22,33]
r=pickle.dumps(li)
print(r)
result=pickle.loads(r)
print(result)
结果为:
b'\x80\x03]q\x00(K\x0bK\x16K!e.'
[11, 22, 33]
pickle的dupms方法会将数据存为pickle特有的数据类型
再看pickle的dump和load方法,通过示例我们来了解:
import pickle
i=[11,22,33]
pickle.dump(i,open('db','wb'))
result=pickle.load(open('db','rb'))
print(result)
结果为:
[11, 22, 33]
需要注意的是dump文件或者load文件是需要使用二进制。
7.3 shelve
shelve是一额简单的数据存储方案,他只有一个函数就是open(),这个函数接收一个参数就是文件名,然后返回一个shelf对象,你可以用他来存储东西,就可以简单的把他当作一个字典,当你存储完毕的时候,就调用close函数来关闭。
f = shelve.open('user.db','wc')
f['baidu'] = 'www.baidu.com'
f['qq'] = 'www.qq.com'
f['360'] = 'www.360.cn'
f.close()
f = shelve.open('user.db','a+')
print(f['baidu'],f['qq'],f['360'])
结果为:
www.baidu.com
www.qq.com
www.360.cn
对shelve序列化数据进行更新操作,通过示例来进行学习:
f=shelve.open('user_db','c')
f["user"]={"数码电器": {"打印机": "3600", "手机": "3800", "电脑": "8000", "照相机": "10000"},
"服装百货": {"方便面": "4", "夹克": "300", "牛仔裤": "288", "王老吉": "6"},
"化妆品": {"韩束": "388", "欧诗漫": "666", "欧莱雅": "888", "百雀羚": "259"},
"汽车":{"帕沙特": "250000", "奇瑞": "100000", "特斯拉": "999999", "宝马X5": "550000"}
}
a=(f["user"])
a.update({"食品":{"猪肉":"12","牛肉":"28","鸡肉":"8","羊肉":"32",}})
f["user"]=a
f.close()
f=shelve.open('user_db','a')
print(f["user"])
8. xml处理模块
xml与json类似,json使用起来更简单,只不过在json没有诞生时,使用的就是xml。
不过现在有一些企业依然使用xml来取xml数据
xml是通过<>节点来区别数据结构的
8.1 xml处理
![image_1c0bk16o75am1kb91dnr1gf31mie139.png-92.8kB][78]
这是一个xml文件的内容
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml") #要处理xmltest.xml文件
root = tree.getroot()
print(root) #只会打印出内存地址
print(root.tag) #会打印出内存地址对应的内容
![image_1c0bk1qviaeq1giv12il1ovu1lsv13m.png-3.2kB][79]
将第一行的data给打印出来了
遍历xml文档
for child in root:
print(child.tag, child.attrib)
for i in child:
print(i.tag, i.text,i.attrib)
![image_1c0bk2ruq11a21014kkf1dli12cv143.png-31.6kB][80]
![image_1c0bk31imjaqi9k20enh8pr714g.png-14.7kB][81]
child.tag是xml文件中的标签名(如:country), child.attrib是属性(如:name="Liechtenstein")
![image_1c0bk3g9sssm1v2l4601tvb50314t.png-3.2kB][82]
i.tag表示rank(标签名)
i.text表示2 (值)
i.attrib表示updated="yes"> (属性)
只遍历year 节点
for node in root.iter('year'):
print(node.tag, node.text)
![image_1c0bk4kh21kev18nh8qa1m8d8do15q.png-1.7kB][83]
8.2 xml修改
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
for node in root.iter('year'): #循环year有关的节点
new_year = int(node.text) + 1 #循环的是字符串,需要转换成数字然后+1(加一年)
node.text = str(new_year) #text表示值,将这个值(20XX)转换为字符串
node.set("updated_by", "Alex") #新增属性
tree.write("xmltest.xml") #将内容写入源文件(xmltest.xml)
![image_1c0bk53bv1kkcic2mu8ukm412167.png-60.9kB][84]
可以看到源文件中的year值都加了一年
8.3 删除
![image_1c0bk5omclpk1gdo1qrq1h5lf16k.png-37.1kB][85]
删除之前有一个叫Panama的country
for country in root.findall('country'): #查找所有country rank = int(country.find('rank').text) #查找country下面的rank
if rank > 50: #如果ran中的值大于50就删除当前country
root.remove(country)
tree.write('output.xml')
![image_1c0bk67dp15ah11031umb1bvo1tvs171.png-59.1kB][86]
已经看不到Panama这个country了
8.4 创建
import xml.etree.ElementTree as ET
new_xml = ET.Element("personinfolist") #根节点personinfolist
personinfo = ET.SubElement(new_xml, "personinfo", attrib={"enrolled": "yes"}) #创建new_xml的子节点; personinfo是节点名;attrib是属性
name = ET.SubElement(personinfo, "name") #该节点是personinfo的子节点
name.text = "Alex Li"
age = ET.SubElement(personinfo, "age", attrib={"checked": "no"})
sex = ET.SubElement(personinfo, "sex")
age.text = '56'
personinfo2 = ET.SubElement(new_xml, "personinfo", attrib={"enrolled": "no"})
name = ET.SubElement(personinfo2, "name")
name.text = "Oldboy Ran"
age = ET.SubElement(personinfo2, "age")
age.text = '19'
et = ET.ElementTree(new_xml) # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True) #xml_declaration表示生成的格式是xml
ET.dump(new_xml) # 打印生成的格式
![image_1c0bk9b29q2j1fvqi51jtqep818r.png-23.8kB][87]
可以看到生成的xml文件,只不过默认格式不对,需要手动调整一下。
![image_1c0bk91cmoa41peh4g1n8p7aj18e.png-34.4kB][88]
调整后的文件
9. PyYAML和configparser
9.1 PyYAML
PyYAML是用来做配置文件的
9.2 configparser
configparser 可以用来生成和修改常见配置文件,如:以conf为结尾的配置文件
python3的写法:configparser
python2的写法:ConfigParser
9.2.1 写入
import configparser
config = configparser.ConfigParser() #生成处理对象并赋值
config['DEFAULT']={'ServerAliveInterval':'45',
'Compression':'yes',
'CompressionLevel':'9',
'ForwardX11':'yes'}
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'} #生成配置文件内容,以字典的方式
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg' #与上面的结果一样,只是写的方式不同
config['topsecret.server.com'] = {}
config['topsecret.server.com']
config['topsecret.server.com']['Host Port'] = '50022' # mutates the parser
config['topsecret.server.com']['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)
![image_1c0bkari3boj1m7n1k8k1k5l1ato198.png-22.3kB][89]
通过python生成的一个配置文件
红色表示节点,图中内容有三个节点
9.2.2 读取
import configparser
conf = configparser.ConfigParser()
conf.read("example.ini")
print(conf.defaults())
![image_1c0bkc815nst6m1e661a9oe741a5.png-4.8kB][90]
使用defaults可以调用example.ini文件中的[DEFAULT]对应的内容,defaults是自带的操作方法
print(conf['bitbucket.org']['user'])
![image_1c0bkcl3mqjm76t1shv17rfp641ai.png-0.5kB][91]
其他的节点只能通过字典的方式来调用
sec = conf.remove_section('bitbucket.org') #删除指定节点
conf.write(open('example.ini', "w")) #写入
![image_1c0bkd6vlfq01pebk4v18vnmlt1av.png-14.1kB][92]
10. hashlib
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
10.1 MD5
import hashlib
m = hashlib.md5() #使用MD5算法
m.update(b'Hello') #b表示bytes类型
print (m.hexdigest()) #使用十六进制打印,hexdigest就表示十六进制格式
m.update(b'Its me')
print (m.hexdigest())
![image_1c0bkds20b5pcj516111e3o10uo1bc.png-4kB][93]
第一个生成的MD5是Hello
第二个生成的MD5是Hello加上Its me
因为MD5值不能翻转,所以通过其他方式确认第二个MD5是否是两个字符串加在一起生成的
![image_1c0bke7bg1u7r1r6t1fv21hlj1jh11bp.png-20.3kB][94]
![image_1c0bkepk356oc721kmo1di115it1c6.png-4.7kB][95]
可以看到通过m2打印的MD5 值与之前的一样,说明之前的解释没有错。
10.2 sha
m3 = hashlib.sha3_512()
m3.update(b'HelloIts me')
print (m3.hexdigest())
![image_1c0bkfkun1anc10kljrq19io1pgq1cj.png-15.2kB][96]
sha512加密长度深,算法复杂度也高,但效率也是相对较低
10.3 hmac
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 再进行处理然后再加密
散列消息鉴别码,简称HMAC,是一种基于消息鉴别码MAC(Message Authentication Code)的鉴别机制。使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;
一般用于网络通信中消息加密,前提是双方先要约定好key,就像接头暗号一样,然后消息发送把用key把消息加密,接收方用key + 消息明文再加密,拿加密后的值 跟 发送者的相对比是否相等,这样就能验证消息的真实性,及发送者的合法性了。
import hmac
h = hmac.new(b'12345',b'qwerasdf') #abc123是key,1234qwer是消息,
print (h.hexdigest())
![image_1c0bkg34d1psdvb7ivm2hk1bpt1d0.png-2.8kB][97]
![image_1c0bkg9efd92t111umb1asp79b1dd.png-13.3kB][98]
![image_1c0bkgeo816sl1hp2jenspbkv41dq.png-13.5kB][99]
默认不能用中文,只能用ASCII码(前面有b,必须生成bytes格式,bytes格式要用ASCII)
![image_1c0bkgsljgjv127ntjd1lk3pac1e7.png-11.9kB][100]
key必须使用bytes格式,消息可以使用中文,但需要将前面的b去掉,然后并封装新的格式(utf-8)
![image_1c0bkh7i3t251lccs4i11bsohv1ek.png-2.8kB][101]
11. subprodcess
subprodcess是os.system和os.spawn*的替代模块
12. logging
12.1 日志级别信息输出
import logging
logging.debug('test debug')
logging.info('test info')
logging.warning('the warning info')
logging.error('the error info')
logging.critical('the critical info')
![image_1c0bki7b07ro17qo1ln5pl91l1a1f1.png-5.9kB][102]
logging.basicConfig(filename='app.log',level=logging.DEBUG)
这条代码一定要放在下面代码的上面才会生效。
这里日志级别是DEBUG,意思就是将DEBUG以及比其高的级别的日志都进行输出
![image_1c0bkithj173f3g1up9q1a10p51fe.png-8.7kB][103]
可以看到新增代码后,就不在pycharm中输出日志信息了
![image_1c0bkl9qgk8b1ua1aon5jk13791fr.png-28.5kB][104]
根据指定的app.log文件,将信息输出到文件中。
![image_1c0bkm4gf19dk1h1c1hncdr0gfq1g8.png-43kB][105]
在执行一遍代码,日志信息就会增加到app.log文件中(不会覆盖)
![image_1c0bkmfto1o8tnj1lm61l1r13jf1gl.png-26kB][106]
将WARNING级别以及比其高的级别日志信息输出
![image_1c0bkmpdn1bf7e1m6oc1tkuue21h2.png-12.1kB][107]
12.3 添加日志格式
logging.basicConfig(filename='app.log',level=logging.WARNING,format='%(asctime)s %(message)s',datefmt='%m/%d/%Y %I:%M:%S %p')
format定义日志格式内容; datefmt定义时间格式(月/日/年 时分秒 %p表示上午或下午)
![image_1c0bkoe9f138a1na9chb13ar1b761hf.png-15.5kB][108]
![image_1c0bkrbqa85l1fgp1l1a866sri1k9.png-42.9kB][109]
![image_1c0bkr6gptgcde569016kas521js.png-15.7kB][110]
定义日志格式,让其显示日志级别
![image_1c0bkrjeb1gjsni19bt147i1pvg1km.png-12.4kB][111]
![image_1c0bkrqmc12861usn1k81180icta1l3.png-16.4kB][112]
显示输出的文件名
![image_1c0bks4ih1o511rvi1ihl1q9mtq31lg.png-28.6kB][113]
因为格式原因输出有乱码,实际输出的应该是logging模块.py
![image_1c0bkshlk18rvi6n12ea1iq45901lt.png-16.9kB][114]
使用%(lineno)d可以显示输出文档的行号
![image_1c0bkssbuj2p19hhajt17be2r21ma.png-17.5kB][115]
可以看到该日志信息是通过哪个文档的哪一行输出的。
![image_1c0bkt6lduufgsr1lon3n9maa1mn.png-17kB][116]
%(funcName)s显示生成日志的函数名称
![image_1c0bktgim1iodlkj1786umi18us1n4.png-7.8kB][117]
![image_1c0bktoukd4sj751dmu18npjqd1nh.png-26.4kB][118]
可以看到app_run;不是通过函数则为空(<module>)
12.4 logging模块涉及四个主要类
logger提供了应用程序可以直接使用的接口
handler将(logger创建的)日志记录发送到合适的目的输出(输出到屏幕、文件、邮件等);
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。
12.4.1 logger
logger相当于一个接口,发送日志都需要调用logger。
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”) #返回一个logger对象,如果没有指定name,返回root logger。只要name相同,返回的logger对象都是同一个而且只有一个,即name和logger对象是一一对应的。这意味着,无需把logger对象在各个模块中传递。只要知道name,就能得到同一个logger对象。
通常logger的名字我们对应模块名,如聊天模块、数据库模块、验证模块等。
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel): #指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt): #添加或删除指定的filter (这个很少用到)
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr): #增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical(): #可以设置的日志级别
12.4.2 handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel): #指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter(): #给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt): #新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler(输出到屏幕)
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm]) 其中strm参数是一个文件对象。默认是sys.stderr
2) logging.FileHandler(输出到文件)
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode]) filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
12.4.2.1输出到多个目的
import logging
logger = logging.getLogger('TEST-LOG') #获取接口对象
logger.setLevel(logging.DEBUG) #定义记录告警信息的最低等级
ch = logging.StreamHandler() #定义Handler,可以输出到屏幕
ch.setLevel(logging.WARNING) #定义输出到屏幕的告警级别
fh = logging.FileHandler('access.log',encoding='utf-8') #定义Handler输出到信息的文件名称
fh.setLevel(logging.ERROR) #定义输出到文件的告警级别
ch_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #定义Handler输出到屏幕的格式
fh_formatter = logging.Formatter('%(asctime)s - %(process)d %(filename)s:%(lineno)d') #定义Handler输出到文件的格式
ch.setFormatter(ch_formatter) #关联Handler输出到屏幕的格式
fh.setFormatter(fh_formatter) #关联Handler输出到文件的格式
logger.addHandler(fh) #增加被输出的内容,与logger接口对象做关联
logger.addHandler(ch) #增加被输出的内容,与logger接口对象做关联
#屏幕和文件中都可以被输出
logger.warning('aaaa') #定义告警级别和信息
logger.error('bbbb') #定义告警级别和信息
![image_1c0bl46en1i8g5cad4t13r31f821qb.png-7kB][119]
输出到屏幕的告警信息,因为定义的最低告警级别是warning,所以两个级别的信息都可以看到
![image_1c0bl4fl5ab7l2u801vloam71qo.png-10.8kB][120]
输出到文件的告警信息,因为定义的级别是error,所以比error低的告警信息warning信息是看不到的
12.4.2.2 按大小自动截断
import logging
from logging import handlers #需要单独import handlers这个函数
logger = logging.getLogger('TEST')
log_file = "test-log.log"
fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3,encoding='utf-8')
#文件名为log_file,每个文件最大存储10字节,最多保留3个备份文件。
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test2")
logger.warning("test3")
logger.warning("test4")
logger.warning("test5")
logger.warning("test6")
![image_1c0bl5cqkr4oshurnh1tr9qgh1r5.png-43.1kB][121]
可以看到自动截断,只保留了3个备份文件,当前主文件的内容就是最后存储的信息'test6'
![image_1c0bl5m6nmvp1stm1mve7du1u151ri.png-12.5kB][122]
log.1是最接近主文件的内容的,所以是'test5'
![image_1c0bl638t1274b47u0ov7uihe1rv.png-13kB][123]
log.3文件存储的是最旧的内容,因为只能每个文件最大10字节,且有3个备份文件的限制,之前的'test1'和'test2'都被删除了。
12.4.2.3 按时间自动截断
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)
import logging
from logging import handlers #需要单独import handlers这个函数
import time
logger = logging.getLogger('TEST')
log_file = "test-log.log"
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3,encoding='utf-8')
#使用handlers.TimedRotatingFileHandler,S表示秒,5就是每隔5秒
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
time.sleep(2)
logger.warning("test2")
time.sleep(2)
logger.warning("test3")
logger.warning("test4")
time.sleep(2)
logger.warning("test5")
logger.warning("test6")
![image_1c0bl79c51sc5197p10et1bm619ps1sc.png-40.2kB][124]
从第5秒开始截断的
13. re正则表达式模块
13.1 函数语法:
re.match(pattern,string, flags=0)
匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
13.2 re.match函数
函数参数说明:
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
13.2.1 举例1:
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
import re
print(re.match('www', 'www.google.com'))
print(re.match('www', 'www.google.com').span())
print(re.match('google', 'www.google.com'))
括号中第一个'www'是正则表达式,相当于匹配的规则; 后面是要匹配的字符串内容。
![image_1c0bl8htnbsm16lhccj1ado14901sp.png-5.3kB][125]
第一个结果可以看到从起始位置匹配到了'www'
第二个结果来输出匹配到内容的下标位置
第三个结果是none,这是因为在www.google.com中不是以google为起始位置的,所以匹配不到。
13.2.2 举例:
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line)
#将line这个变量作为一个需要匹配的内容;
#这里正则表达式通过()分了两个部分,可以用group来表达,在are之前的(.*)是一部分,在are之后的(.*?) 一个部分,如果去掉的话匹配结果就不同了。
每一个()表示一个分组
if matchObj:
print ("matchObj.group() : ", matchObj.group()) #匹配所有()和非()表达式中的内容
print ("matchObj.group(1) : ", matchObj.group(1)) #匹配第一个()中的表达式内容
print ("matchObj.group(2) : ", matchObj.group(2)) #匹配第二个()中的表达式内容
print ("matchObj.group(3) : ", matchObj.groups()) #匹配所有()中的表达式美容,并以元组的形式显示
else:
print ("No match!!")
![image_1c0bl9gdj11rt1pn6g0p1pli1ngt1t6.png-6.8kB][126]
13.3 正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
![image_1c0bl9vv9nsojf1r7h5og12gf1tj.png-24.7kB][127]
13.4 正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'/t',等价于'//t')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
![image_1c0blaf8qeve1rl51vuf3871ib21u0.png-57.1kB][128]
![image_1c0blatem1mfg1c0s1lja153c1jui1ud.png-58.4kB][129]
![image_1c0blb49d1dfo2tm1vi31n3f17gi1uq.png-22.9kB][130]
13.5 正则表达式实例
![image_1c0blbpa6nmv9q0tsp12nn19rn1v7.png-32.6kB][131]
![image_1c0blc05bg5svc7chv1ssq73c1vk.png-31.7kB][132]
13.6 使用模式举例
line = 'www.google.com'
rule = re.match(r'.',line)
print (rule)
print (rule.group())
![image_1c0bldjoj1qic1i6375d1lsh154v21h.png-4.3kB][133]
使用一个'.'表达除了\n 外的任意一个字符(字母、数字、特殊字符),可以看到职匹配了第一个w
不使用group来表达的话会多现实一些参数,比如span表达了第一个w所在下标的位置范围
line = 'www.google.com'
rule = re.match(r'.+',line)
![image_1c0blducmgd8qa217mp1ul01on021u.png-1.4kB][134]
'.+'通过'+'匹配了0个或多个'.'
rule1 = re.match(r'w',line) #匹配一个字母
rule2 = re.match(r'w+',line) #匹配0或多个字母
rule3 = re.match(r'w{2}',line) #匹配2个字母
rule4 = re.match(r'w{1,3}',line) #匹配1到3个字母(至少1个,最多3个)
print (rule1.group())
print (rule2.group())
print (rule3.group())
print (rule4.group())
![image_1c0blev5v12ess0ied86rjja722b.png-0.7kB][135]
匹配了字母,遇见'.'后不符合表达式(不属于字母),所以连带'.'后面的所有内容也都不匹配了。
rule5 = re.match(r'w+|.+',line)
rule6 = re.match(r'.+|w+',line)
![image_1c0blfk381h8s1f5s1vbf1egcvn022o.png-1.7kB][136]
通过|来表示或的意思,但是在匹配的时候,只要前面的规则匹配到了,后面就不在匹配了,所以可以看到匹配的结果不同。
re.search('www','www.google.com').group() #注意匹配www时是没有使用r或\转义的,所以匹配的就是www字符本身
re.search('google','www.google.com').group()
![image_1c0blg77913urboo1sv3c7c1k40235.png-8.9kB][137]
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
re.search('(\d{3})(\d{4})','123456789123456789').groups()
![image_1c0blgqhrmmc1pci1s13hl0mmh23i.png-6.3kB][138]
匹配数字,因为有两个(),所以在元组中分为两个元素显示
使用:‘^,$,Z’
![image_1c0blhhnd5j2194s1bst1lpc1st523v.png-19kB][139]
通过^匹配以数字开头的,通过$匹配以数字结尾的,第一个报错是因为匹配的内容不是数字结尾,另一个匹配则是以数字为结尾所以不会报错。
Z与$是一个意思
rule = re.search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}','192.168.1.1').group()
print (rule)
![image_1c0bllfe512of1k01sa11e14102424c.png-1.2kB][140]
rule = re.search('(\d{1,3}\.){3}\d{1,3}','192.168.1.1').group() #稍微优化
print (rule)
![image_1c0blm0mddub11jg1ef6c1u1oe824p.png-1.2kB][141]
rule = re.search('([0-2]?[0-9]?[0-9]+\.){3}[0-2]?[0-9]?[0-9]','192.168.1.1').group()
print (rule)
![image_1c0blmmi310n71b951rimoo41pa9256.png-1.2kB][142]
以上都不是合法的IP地址写法
- 匹配:合法IP地址
rule = re.search('^((25[0-5]|2[0-4]\d|[1]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[1]?\d?\d)$','255.168.1.255').group()
print (rule)
![image_1c0blnhr51jo1gd8rj5gld4ll25j.png-1.2kB][143]
rule = re.search('^((25[0-5]|2[0-4]\d|[1]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[1]?\d?\d)$','256.168.1.255').group() #第一个IP被协成256,这是不合法的
print (rule)
![image_1c0blo0mka38741h8l1cth65k260.png-17.2kB][144]
可以看到报错
rule1 = re.search('\d+','ab13aa22cc334bb44adsf234656').group()
rule2 = re.findall('\d+','ab13aa22cc334bb44adsf234656') #这里不需要group
print (rule1)
print (rule2)
![image_1c0blot4i1hku1ng6g9n14p5qem26d.png-2.3kB][145]
可以看到search只能寻找其中一个,而findall可以寻找所有。
rule3= re.findall('\D+','ab13aa22cc334bb44adsf234656')
print (rule3)
![image_1c0blpcfad3o12ct7f51722e4l26q.png-1.6kB][146]
\D表示非数字
- 使用:'re.split'
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656')
print (rule1)
![image_1c0blq4o0b293161a42fd11bs9277.png-2.1kB][147]
- 使用re.split分隔成列表显示
可以看到与findall类似,但是split后面因为有数字所以就分隔了一个空
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656dd') #最后面加个dd字符串
print (rule1)
![image_1c0blqv1h15uljmv3q1m8og7s27k.png-1.7kB][148]
使用re.split分隔成列表显示
可以看到与findall类似,但是split后面因为有数字所以就分隔了一个空
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656dd') #最后面加个dd字符串
print (rule1)
![image_1c0blrqj61c51cps1omd1lkr7bd281.png-1.7kB][149]
会将dd进行分隔
rule = re.sub('\d+','|','ab13aa22cc334bb44adsf234656dd')
print (rule)
![image_1c0blst921gpudlh6u51mth6gv28e.png-1.2kB][150]
使用re.sub进行替换,将数字替换成 |
rule = re.sub('\d+','XXX','ab13aa22cc334bb44adsf234656dd',count=2)
print (rule)
![image_1c0bltm7d13on5bc1ou627o1q9p28r.png-2.4kB][151]
count是替换几次
- flags
rule = re.search('a+','AAAaaa').group()
print (rule)
![image_1c0bm05dg16056fl15c7c961arm2b8.png-0.3kB][152]
只能匹配到小写的a
rule = re.search('a+','AAAaaa',re.I).group()
print (rule)
![image_1c0bm0026igglte16si1n6q1sn52ar.png-0.5kB][153]
使用falgs中的re.I可以忽略大小写
14.subprocess
os.system('dir') #可以显示当前目录内容
aaa = os.system('dir') #赋值变量
打印变量发现得到的不是执行结果,而是执行状态,在Windows中 0 表示执行成功, 1 表示执行失败。
os.popen('dir')
使用os.popen('dir') 可以显示执行结果,但是当前看到的是内存地址
os.popen('dir').read()
需要加一个.read()来查看命令的执行结果
- subprocess for linux(Ubuntu)
在linux中尝试使用subprocess模块
查看当前路径目录内容,并返回查看信息
subprocess模块是python从2.4版本开始引入的模块。主要用来取代 一些旧的模块方法,如os.system、os.spawn、os.popen、commands.*等。subprocess通过子进程来执行外部指令,并通过input/output/error管道,获取子进程的执行的返回信息。
常用方法:
- subprocess.call()
- subprocess.call(command) 方法
subprocess的call方法可以用于执行一个外部命令,但该方法不能返回执行的结果,只能返回执行的状态码: 成功(0) 或 错误(非0)
call()方法中的command可以是一个列表,也可以是一个字符串,作为字符串时需要用原生的shell来执行:
import subprocess
#方法一
>>> a = subprocess.call(['ls','-l'])
总用量 32
drwxr-xr-x 2 test test 4096 12月 3 00:58 公共的
drwxr-xr-x 2 test test 4096 12月 3 00:58 模板
drwxr-xr-x 2 test test 4096 12月 3 00:58 视频
drwxr-xr-x 2 test test 4096 12月 3 00:58 图片
drwxr-xr-x 2 test test 4096 12月 3 00:58 文档
drwxr-xr-x 2 test test 4096 12月 3 00:58 下载
drwxr-xr-x 2 test test 4096 12月 3 00:58 音乐
drwxr-xr-x 3 test test 4096 12月 3 12:25 桌面
>>>
>>> a
0
#方法二
>>> b = subprocess.call("ls -l",shell=True)
总用量 32
drwxr-xr-x 2 test test 4096 12月 3 00:58 公共的
drwxr-xr-x 2 test test 4096 12月 3 00:58 模板
drwxr-xr-x 2 test test 4096 12月 3 00:58 视频
drwxr-xr-x 2 test test 4096 12月 3 00:58 图片
drwxr-xr-x 2 test test 4096 12月 3 00:58 文档
drwxr-xr-x 2 test test 4096 12月 3 00:58 下载
drwxr-xr-x 2 test test 4096 12月 3 00:58 音乐
drwxr-xr-x 3 test test 4096 12月 3 12:25 桌面
>>> b
0
如上实例所示,虽然我们能看到执行的结果,但实际获取的值只是状态码
当调取变量时只能看到0这个状态值
用法与subprocess.call()类似,区别是,当返回值不为0时,直接抛出异常
>>> a = subprocess.check_call('df -hT',shell=True)
文件系统 类型 容量 已用 可用 已用% 挂载点
udev devtmpfs 969M 0 969M 0% /dev
tmpfs tmpfs 199M 6.3M 193M 4% /run
/dev/sda1 ext4 19G 5.1G 13G 29% /
tmpfs tmpfs 992M 168K 992M 1% /dev/shm
tmpfs tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs tmpfs 992M 0 992M 0% /sys/fs/cgroup
tmpfs tmpfs 199M 40K 199M 1% /run/user/1000
/dev/sr0 iso9660 1.5G 1.5G 0 100% /media/test/Ubuntu-Kylin 16.04 LTS amd64
>>>
>>> a
0
>>>
>>>
>>>
>>> a = subprocess.check_call('dfdsf',shell=True)
/bin/sh: 1: dfdsf: not found
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/subprocess.py", line 581, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'dfdsf' returned non-zero exit status 127
>>>
>>> a
0
>>>
- subprocess.check_output()
call()方法启动的进程,其标准输入输出会绑定到父进程的输入和输出。调用程序无法获取命令的输出结果。但可以通过check_output()方法来捕获输出。
>>>
>>> output=subprocess.check_output("ls -l",shell=True)
>>>
>>> output
b'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 32\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe5\x85\xac\xe5\x85\xb1\xe7\x9a\x84\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe6\xa8\xa1\xe6\x9d\xbf\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe8\xa7\x86\xe9\xa2\x91\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe5\x9b\xbe\xe7\x89\x87\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe6\x96\x87\xe6\xa1\xa3\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe4\xb8\x8b\xe8\xbd\xbd\ndrwxr-xr-x 2 test test 4096 12\xe6\x9c\x88 3 00:58 \xe9\x9f\xb3\xe4\xb9\x90\ndrwxr-xr-x 3 test test 4096 12\xe6\x9c\x88 3 12:25 \xe6\xa1\x8c\xe9\x9d\xa2\n'
>>>
#在python3中输出的结果是bytes格式
以下例子将chek_output()方法执行命令异常时的错误捕获,而避免输出到控制台.
>>>
>>> try:
... output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
File "<stdin>", line 2
output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
^
IndentationError: expected an indented block
>>> try:
... output = subprocess.check_output("lT -l", shell=True, stderr=subprocess.STDOUT)
... except subprocess.CalledProcessError as err:
... print("Command Error", err)
...
Command Error Command 'lT -l' returned non-zero exit status 127
>>>
>>> a = subprocess.getstatusoutput('ls -l')
>>>
>>> a
(0, '总用量 32\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 公共的\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 模板\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 视频\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 图片\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 文档\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 下载\ndrwxr-xr-x 2 test test 4096 12月 3 00:58 音乐\ndrwxr-xr-x 3 test test 4096 12月 3 12:25 桌面')
>>>
# 直接返回执行状态和结果,通常getstatusoutput使用比其他方式多。
上面这些subprocess的方法底层都是封装的subprocess.Popen
- subprocess.Popen
>>> res = subprocess.Popen('ifconfig | grep 192', shell=True)
>>> inet 地址:192.168.142.128 广播:192.168.142.255 掩码:255.255.255.0
>> res #内存地址
<subprocess.Popen object at 0x7f4b6176a518>
>>
>> res.read() #可以看到使用read读取不到内容
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Popen' object has no attribute 'read'
>>
>>
>>>
>>> res = subprocess.Popen('ifconfig | grep 192', shell=True,stdout=subprocess.PIPE) #通过在内存中生成一个管道,将res存储的数据放入管道中,然后通过管道将数据输出到屏幕上。
>>> res
<subprocess.Popen object at 0x7f4b6176aba8>
>>>
>>> res.stdout.read()
b' inet \xe5\x9c\xb0\xe5\x9d\x80:192.168.142.128 \xe5\xb9\xbf\xe6\x92\xad:192.168.142.255 \xe6\x8e\xa9\xe7\xa0\x81:255.255.255.0\n'
>>>
>>>
stdout表示标准输出
stdin表示标准输入
stderr表示错误
>>>
>>> res = subprocess.Popen('asdf | grep 192', shell=True,stdout=subprocess.PIPE)
>>> /bin/sh: 1: asdf: not found
>>> res.stdout.read() #错误是没办法直接被输出读取到的
b''
>>>
>>> res = subprocess.Popen('asdf | grep 192', shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> res.stdout.read()
b''
>>>
>>> res.stderr.read() #可以查看错误信息
b'/bin/sh: 1: asdf: not found\n'
>>>
>>>
在linux中subprocess每一次执行相当于调用一次shell脚本,而shell相当于一个程序。
>>> res = subprocess.Popen("sleep 10; echo 'hello' ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>>
>>> res.stdout.read() #可以看到我们将hello读取出来了,但是在正常执行程序时,这个程序是多久执行完成的我们并不知道。
b'hello\n'
>>>
>>> res = subprocess.Popen("sleep 10; echo 'hello' ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) #我们再次执行该代码
>>> res.stdout.read() #可以发现=需要等待设定的10秒时间,才能将hello输出到屏幕。
b'hello\n'
如果使用res.poll()就可以发现当前程序是否执行完成或未完成。
>>> res = subprocess.Popen("sleep 10; echo 'hello' ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) #再次执行该程序,需要运行10秒才能完成
>>> print (res.poll())
None
>>>
>>> print (res.poll())
None
>>>
>>> print (res.poll())
None
>>>
>>> print (res.poll())
0
>>>
# 然后我们看到不断的通过print (res.poll()) 查看执行情况,在10秒以内我们可以看到None,说明该程序还未执行完成(但可以确认程序正在执行),直到看到 0 时说明程序已经执行完成
>>>
>>> res = subprocess.Popen("sleep 10; echo 'hello' ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> res.wait() #wait()直接等待程序执行结果
0
>>>
>>> res = subprocess.Popen("sleep 10; echo 'hello' ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> res.terminate() #终止程序运行
>>>
>>> res.stdout.read() #可以看到没有读取到任何信息,说明程序被终止成功。
b''
>>>
sub.community 这个功能几乎用不到
>>>
>>> res = subprocess.Popen("pwd ", shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd="/tmp") #使用cwd可以改变当前程序运行的目录位置
>>> res.stdout.read()
b'/tmp\n' #可以看到已经改变位置在/tmp下
>>>
可用参数:
args:shell命令,可以是字符串或者序列类型(如:list,元组) bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。
所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
shell:同上
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
startupinfo与createionflags只在windows下有效
将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
在linux中安装程序需要密码
通过这种方式可以实现在linux中自动发送密码
在python中可以通过subprocess模块发送命令安装
>>>
>>> import subprocess
>>>
>>> subprocess.Popen("echo '123' | sudo -S apt-get install vim",shell=True)
<subprocess.Popen object at 0x7f7f6496e080>
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
将会同时安装下列软件:
vim-common vim-runtime vim-tiny
建议安装:
ctags vim-doc vim-scripts vim-gnome-py2 | vim-gtk-py2 | vim-gtk3-py2 | vim-athena-py2 | vim-nox-py2 indent
下列【新】软件包将被安装:
vim vim-runtime
下列软件包将被升级:
vim-common vim-tiny
升级了 2 个软件包,新安装了 2 个软件包,要卸载 0 个软件包,有 650 个软件包未被升级。
需要下载 6,199 kB/6,748 kB 的归档。
解压缩后会消耗 30.0 MB 的额外空间。
您希望继续执行吗? [Y/n] 中止。
>>>
···
[1]: http://static.zybuluo.com/aubreyzheng/ey3jffkdmvhzy7eim3nlnwca/image_1c0bi1c1j1pkr1rn91ovspjf1omo9.png
[2]: http://static.zybuluo.com/aubreyzheng/hhm8t6ds9tqms9lysj90e57y/image_1c0bi20qd1hi61lm35m416qd5e7m.png
[3]: http://static.zybuluo.com/aubreyzheng/s8oz8lcpq08j3war4a7k51jh/image_1c0bi2huj107sqhj1vej9ifle713.png
[4]: http://static.zybuluo.com/aubreyzheng/muzxad6n6evn7hg9vjwh5tfn/image_1c0bi30g51bnvevd1391asr7ug1g.png
[5]: http://static.zybuluo.com/aubreyzheng/k09g91hc0fb7t1oz2tykblt2/image_1c0bi3mtd4ki1rgt12fvhoka4e1t.png
[6]: http://static.zybuluo.com/aubreyzheng/kdsnz5u4kluxa385avsqrrrg/image_1c0bi434g1v2n1aprg9kqrk1te72a.png
[7]: http://static.zybuluo.com/aubreyzheng/6cwb59jgtwi8w329er97ncrf/image_1c0bi5qjai2j1ken227chthjt3h.png
[8]: http://static.zybuluo.com/aubreyzheng/mvm4teauy1n906le1lt4f72t/image_1c0bi688v11i51g2c1l051srqupe3u.png
[9]: http://static.zybuluo.com/aubreyzheng/h6cwt2jtowmi2e5fm680h6g2/image_1c0bi6hjnh7a1v11ut31ul1gmm4b.png
[10]: http://static.zybuluo.com/aubreyzheng/4u7u5znuno2a42hig4tbynao/image_1c0bi7328c3qj6n8h69bo1snk4o.png
[11]: http://static.zybuluo.com/aubreyzheng/d6feq80k196tuu854g09rz0u/image_1c0bi7ig9t5f9pp144o1f0p5nj55.png
[12]: http://static.zybuluo.com/aubreyzheng/2mqgou980vbnyyro8i1mau60/image_1c0bi7vd21ov0uisg5714rc1shg5i.png
[13]: http://static.zybuluo.com/aubreyzheng/04r8yk5j76jhlwty4aryzfkw/image_1c0bi8ktmssm1r8jtj4u1hasv5v.png
[14]: http://static.zybuluo.com/aubreyzheng/frxw3vqxdpojqmtwzxcok061/image_1c0bi9cgi81eu0q1g05hsubln6c.png
[15]: http://static.zybuluo.com/aubreyzheng/09z1ovayiwxrwl1y6envf5o2/image_1c0bi9udvbi1l0ikkf1jea1fs16p.png
[16]: http://static.zybuluo.com/aubreyzheng/r62hajzf8xh26wzg2kz7ip6w/image_1c0bia92f9cg17kj19fchbliiq76.png
[17]: http://static.zybuluo.com/aubreyzheng/62lybvxuqcn8qky326w532z7/image_1c0bianj0dedhi214cm1r1lqq17j.png
[18]: http://static.zybuluo.com/aubreyzheng/vt3nc27fdxnn95d9irdgfbqi/image_1c0bias9n1l9974h9njdi6106a80.png
[19]: http://static.zybuluo.com/aubreyzheng/fl7lou3rgxhdxlwwf59aw2aq/image_1c0bib8gnbuv17er2dji2oa3r8d.png
[20]: http://static.zybuluo.com/aubreyzheng/ugi8m8ht4ve2sgey2n0yky9w/image_1c0bibknfqd91ojs17671eh1k7f8q.png
[21]: http://static.zybuluo.com/aubreyzheng/td03i1l1abior0y37f32hx2y/image_1c0bici7tr8jotq6is15nn1def97.png
[22]: http://static.zybuluo.com/aubreyzheng/kqhd595c9285otrdft1sk5z3/image_1c0bics6ehj5567qn0cfn7s99k.png
[23]: http://static.zybuluo.com/aubreyzheng/9xbj46xvrvbfo06ipu3derfd/image_1c0bidam5djm1mh0125r7irm95a1.png
[24]: http://static.zybuluo.com/aubreyzheng/5aagf90xuptqst0vjcymycuo/image_1c0bidt661st9ltc1tng6dbkuoae1.png
[25]: http://static.zybuluo.com/aubreyzheng/cb4n66w385dgf20tov4xgl48/image_1c0bieb2um9uquv1cmc1vu2q7qar.png
[26]: http://static.zybuluo.com/aubreyzheng/6ggapqsa9jdx5n7amfyzgigj/image_1c0bien86ad11rh9021n8scnb8.png
[27]: http://static.zybuluo.com/aubreyzheng/6r3xnlwm48ddeqzy3y2ttk5v/image_1c0bif49i1g9goma1ovhe9912kbl.png
[28]: http://static.zybuluo.com/aubreyzheng/a0r3bwqub6ijxyh68g095tv1/image_1c0big5tn14abk9j1vf2fv01u0oc2.png
[29]: http://static.zybuluo.com/aubreyzheng/8a3ve4cw17n2ktizhs1loz2t/image_1c0bigmvoepf10roneo11nq1etacf.png
[30]: http://static.zybuluo.com/aubreyzheng/if0hr28ye1d5eyzgqye5hbq4/image_1c0bihqs5131lh910gk1nfgpqmcs.png
[31]: http://static.zybuluo.com/aubreyzheng/q0u5c5uocegi325o8gf0iws0/image_1c0bijapt16v2ej91ug01gju14aod9.png
[32]: http://static.zybuluo.com/aubreyzheng/fyzzrugu3umqj5w02iq2v1oj/image_1c0bijkuqskr17tshu3036lodm.png
[33]: http://static.zybuluo.com/aubreyzheng/fffu6uq6a4m4334x53k6vchw/image_1c0bikp1po7q13hh1o191t994dne3.png
[34]: http://static.zybuluo.com/aubreyzheng/mtb6alju24ibr2hn0xd5zb4c/image_1c0bilu6c1cgiu351k6h7dra9eg.png
[35]: http://static.zybuluo.com/aubreyzheng/2w72cp7x4040mc2pkoop211w/image_1c0bimdeb1d2s1j2t1dg21u8k1tonet.png
[36]: http://static.zybuluo.com/aubreyzheng/cenoiys05zqvrukkteei3lm7/image_1c0bin1jl1hmpcaf571vqipunfa.png
[37]: http://static.zybuluo.com/aubreyzheng/5vj7riklw3qc5ub1s55zvsuo/image_1c0binjejnbenno1e231nqnek1fn.png
[38]: http://static.zybuluo.com/aubreyzheng/ao37cwic752r5zn9sveeuect/image_1c0bip3fam0a1pu819kl1m1npf3g4.png
[39]: http://static.zybuluo.com/aubreyzheng/ifeo1nuer3t35qw7034tuabg/image_1c0bipq7lc3d1brj1olr18c1cc8gh.png
[40]: http://static.zybuluo.com/aubreyzheng/7vol4du4k9tfbtmerglnrjsh/image_1c0biq44ifjr1ffe1v2oqt8h1gu.png
[41]: http://static.zybuluo.com/aubreyzheng/pjj12wnscnmiro99mph24o67/image_1c0bisl0f1v4p1o1sjdk1m881j9thr.png
[42]: http://static.zybuluo.com/aubreyzheng/ioltyz76ybqafbz0udoi06tm/image_1c0bitgst1aav7121lt2ge71q6kil.png
[43]: http://static.zybuluo.com/aubreyzheng/jwwcthv32496awe0vyxj9g11/image_1c0bitle91v3i73g7ckdbafgtj2.png
[44]: http://static.zybuluo.com/aubreyzheng/51ih3p70nhon8wptnsq4vs0i/image_1c0bj1gu11a331ou15teheq1r4tjf.png
[45]: http://static.zybuluo.com/aubreyzheng/spshrdh070rlvi8767bu2da9/image_1c0bj1r2mditgbv1rc63063vdjs.png
[46]: http://static.zybuluo.com/aubreyzheng/cf4o5459tdkt203vwtbxjpbs/image_1c0bj1vtteng7qrqqgire16m9k9.png
[47]: http://static.zybuluo.com/aubreyzheng/182hadpvpmh6jnv3zd14ji7u/image_1c0bj2iv61dfc2u57lj9h75pkkm.png
[48]: http://static.zybuluo.com/aubreyzheng/d6ihdp2r6j86e1r9u0we3w8p/image_1c0bj49811nkr9f41n9l1msvmsrmg.png
[49]: http://static.zybuluo.com/aubreyzheng/lcokg4ptzkvvvlajqw60tdhf/image_1c0bj431l1tdrdrsn3nmd4afm3.png
[50]: http://static.zybuluo.com/aubreyzheng/n702i2lgx5jlk8dr8x1h3907/image_1c0bj4oat1ff79bj1fd81fnavp6mt.png
[51]: http://static.zybuluo.com/aubreyzheng/iomnlloao7lotn6794kcvpic/image_1c0bj5ht865hct4ldhhi216itna.png
[52]: http://static.zybuluo.com/aubreyzheng/anfqcfnxteyf7x4fcganot1y/image_1c0bj5sd11s1o38b1nmg1pr3i4nn.png
[53]: http://static.zybuluo.com/aubreyzheng/wh6off1jy40ejnqdf0ytsp8r/image_1c0bj67giohb36b71s13ad1j6po4.png
[54]: http://static.zybuluo.com/aubreyzheng/b02611prwrby38mbobj8c0yl/image_1c0bj6ivthkr1io7106r1fj2vtoh.png
[55]: http://static.zybuluo.com/aubreyzheng/wazpjygag4zpps7u0vy7fnd3/image_1c0bj6uhrr4vhhh1b7fjf15a5ou.png
[56]: http://static.zybuluo.com/aubreyzheng/cc0ncu5fbpzmxzwcg58k63lf/image_1c0bj8q52kj31hgh7j6aii18sopb.png
[57]: http://static.zybuluo.com/aubreyzheng/ji47st72indkdt17sihfdfz0/image_1c0bj96gs7pf19q535813hk1720po.png
[58]: http://static.zybuluo.com/aubreyzheng/rorcdp0xt60ekucc6r73349p/image_1c0bjac20lmcubf17sj1p4hjl2q5.png
[59]: http://static.zybuluo.com/aubreyzheng/2a2bxbo566rqm426so6w9tnu/image_1c0bjaqd1aaplif1eqh7q1unkqi.png
[60]: http://static.zybuluo.com/aubreyzheng/i77f5alssy5sky7tiswlpvm3/image_1c0bjbbhm1rp1g5b1ja31n811eqjqv.png
[61]: http://static.zybuluo.com/aubreyzheng/9k7tu25cy8cn08ovstct6rif/image_1c0bjce57l1b27a1ptj1ieatnors.png
[62]: http://static.zybuluo.com/aubreyzheng/9g7p6qxmzebimxl2znuxmsat/image_1c0bjet2f14qbkr416vb17io12p2s9.png
[63]: http://static.zybuluo.com/aubreyzheng/2y0fo7ciiz2a24291tdsa1ci/image_1c0bjf7g71tr21746s0h1u2t12pnsm.png
[64]: http://static.zybuluo.com/aubreyzheng/6yosalwe8me7oz9ri0j3gqai/image_1c0bjgf4j1q7eu04c1r1v2uu0lt3.png
[65]: http://static.zybuluo.com/aubreyzheng/zdb8w0fhurq7p5r73xbnxc8e/image_1c0bjguheji37n6g2r1m07594tg.png
[66]: http://static.zybuluo.com/aubreyzheng/g46z3g2ga44hf5xdx6bg5kvr/image_1c0bjha236ln1ckt1ups1kqoqqstt.png
[67]: http://static.zybuluo.com/aubreyzheng/4glkir7nkxlbwo7kb0t0ql2q/image_1c0bji91j1kg81f69154j10s71nagua.png
[68]: http://static.zybuluo.com/aubreyzheng/1dkkc6byzjbgaa6oald6xdo3/image_1c0bjmetm1v2eg3m10kbsf4qv2v7.png
[69]: http://static.zybuluo.com/aubreyzheng/ul0uhdmibd4y9yk94577lwk3/image_1c0bjn1en19mb1dtg10fh1rgm1et1vk.png
[70]: http://static.zybuluo.com/aubreyzheng/2fnvoagglviqkdslmpnsuny8/image_1c0bjn7at9mg1hkm1aceb0k15pt101.png
[71]: http://static.zybuluo.com/aubreyzheng/9mxo06ikjufrfw90s2yzfguh/image_1c0bjnjkf57o1nu2vce14jitl10e.png
[72]: http://static.zybuluo.com/aubreyzheng/77nrvmonwibdft458f6guliq/image_1c0bjo3dgsa21lqq12i21bsq1v5210r.png
[73]: http://static.zybuluo.com/aubreyzheng/qhon57jrxexpmekruk5cy0nt/image_1c0bjo8tr1t61v3ni3o5ee1hjj118.png
[74]: http://static.zybuluo.com/aubreyzheng/3vucp1d8qnukra8wv0ednfvw/image_1c0bjoiqr1fgcc48flo15mo1sgg11l.png
[75]: http://static.zybuluo.com/aubreyzheng/kaj13x61oclclj9gxnccb6z4/image_1c0bjp4qm1dkr1qfks8kjnl2j2122.png
[76]: http://static.zybuluo.com/aubreyzheng/srkppai6qzgcci43x8nan9mx/image_1c0bjpfd5asvrjb1j8joh188h12f.png
[77]: http://static.zybuluo.com/aubreyzheng/qeb0erxrt1c8ee3ceujek0zv/image_1c0bjpmb812ja17m31buts8hqtg12s.png
[78]: http://static.zybuluo.com/aubreyzheng/ecuj5yojde6qy10dvjq6bvqf/image_1c0bk16o75am1kb91dnr1gf31mie139.png
[79]: http://static.zybuluo.com/aubreyzheng/24wwxotvly4nlshcz4aceqq0/image_1c0bk1qviaeq1giv12il1ovu1lsv13m.png
[80]: http://static.zybuluo.com/aubreyzheng/akw62ujww1m8aod8fwmjf2m2/image_1c0bk2ruq11a21014kkf1dli12cv143.png
[81]: http://static.zybuluo.com/aubreyzheng/v4392yefguighsb87ucbf2i0/image_1c0bk31imjaqi9k20enh8pr714g.png
[82]: http://static.zybuluo.com/aubreyzheng/l772n0eanhow3y23t0j91epe/image_1c0bk3g9sssm1v2l4601tvb50314t.png
[83]: http://static.zybuluo.com/aubreyzheng/sypytsgrymgrfdzegzjb84s9/image_1c0bk4kh21kev18nh8qa1m8d8do15q.png
[84]: http://static.zybuluo.com/aubreyzheng/u30l7nrfwolqw37ubmqkv6xv/image_1c0bk53bv1kkcic2mu8ukm412167.png
[85]: http://static.zybuluo.com/aubreyzheng/h5vpq3fmhvwn9ieiyykiimcn/image_1c0bk5omclpk1gdo1qrq1h5lf16k.png
[86]: http://static.zybuluo.com/aubreyzheng/jxh90gbgz02n11y7nbsqcof2/image_1c0bk67dp15ah11031umb1bvo1tvs171.png
[87]: http://static.zybuluo.com/aubreyzheng/tcnql7ie5m38nqm72qauyeby/image_1c0bk9b29q2j1fvqi51jtqep818r.png
[88]: http://static.zybuluo.com/aubreyzheng/6ye6u17aik43y7nuvp0kftic/image_1c0bk91cmoa41peh4g1n8p7aj18e.png
[89]: http://static.zybuluo.com/aubreyzheng/3fa0hjfz7cdu5e8kxzzgvpu0/image_1c0bkari3boj1m7n1k8k1k5l1ato198.png
[90]: http://static.zybuluo.com/aubreyzheng/cpzvqhmg0mcscnw9oaiawzil/image_1c0bkc815nst6m1e661a9oe741a5.png
[91]: http://static.zybuluo.com/aubreyzheng/08p3qwmedotjunoxa8smczmy/image_1c0bkcl3mqjm76t1shv17rfp641ai.png
[92]: http://static.zybuluo.com/aubreyzheng/pik58kv5be7mrth6178jvsue/image_1c0bkd6vlfq01pebk4v18vnmlt1av.png
[93]: http://static.zybuluo.com/aubreyzheng/9tkffy7i2ctgmyqcgyi00svf/image_1c0bkds20b5pcj516111e3o10uo1bc.png
[94]: http://static.zybuluo.com/aubreyzheng/wzdkhf38vzi4x2orycay95bh/image_1c0bke7bg1u7r1r6t1fv21hlj1jh11bp.png
[95]: http://static.zybuluo.com/aubreyzheng/9jzd99ccin4anc7brc8l09oi/image_1c0bkepk356oc721kmo1di115it1c6.png
[96]: http://static.zybuluo.com/aubreyzheng/g81znbbe6bqkujcqie7cck6o/image_1c0bkfkun1anc10kljrq19io1pgq1cj.png
[97]: http://static.zybuluo.com/aubreyzheng/6p2t2xnyeh4qzyzuacxgihku/image_1c0bkg34d1psdvb7ivm2hk1bpt1d0.png
[98]: http://static.zybuluo.com/aubreyzheng/a1wdk240h5vnazhes7mta65h/image_1c0bkg9efd92t111umb1asp79b1dd.png
[99]: http://static.zybuluo.com/aubreyzheng/4eakksn7kbhnnq9wxic0doe8/image_1c0bkgeo816sl1hp2jenspbkv41dq.png
[100]: http://static.zybuluo.com/aubreyzheng/3zn0yi0xfyq3v8712nr9ya1p/image_1c0bkgsljgjv127ntjd1lk3pac1e7.png
[101]: http://static.zybuluo.com/aubreyzheng/425j9z54d150m8aa0cbtsvj4/image_1c0bkh7i3t251lccs4i11bsohv1ek.png
[102]: http://static.zybuluo.com/aubreyzheng/yhdm313y3bk8l7yqmn80uxy8/image_1c0bki7b07ro17qo1ln5pl91l1a1f1.png
[103]: http://static.zybuluo.com/aubreyzheng/j0oppgjrdx7vru77v5taecfq/image_1c0bkithj173f3g1up9q1a10p51fe.png
[104]: http://static.zybuluo.com/aubreyzheng/wxmelxq8rb2paf2vvdbnsofk/image_1c0bkl9qgk8b1ua1aon5jk13791fr.png
[105]: http://static.zybuluo.com/aubreyzheng/lplbwf33izyixp2pq6jb9pzp/image_1c0bkm4gf19dk1h1c1hncdr0gfq1g8.png
[106]: http://static.zybuluo.com/aubreyzheng/y2tojmt5efuqci5obcwahfye/image_1c0bkmfto1o8tnj1lm61l1r13jf1gl.png
[107]: http://static.zybuluo.com/aubreyzheng/abyu9zqidq1pnbeocry9rus8/image_1c0bkmpdn1bf7e1m6oc1tkuue21h2.png
[108]: http://static.zybuluo.com/aubreyzheng/72gf1iwbnw67w734jtth293i/image_1c0bkoe9f138a1na9chb13ar1b761hf.png
[109]: http://static.zybuluo.com/aubreyzheng/f6tvgkho7f3s6l1a7cb7ci20/image_1c0bkrbqa85l1fgp1l1a866sri1k9.png
[110]: http://static.zybuluo.com/aubreyzheng/9s20gvlbd5l7i0xy11jbcxb7/image_1c0bkr6gptgcde569016kas521js.png
[111]: http://static.zybuluo.com/aubreyzheng/m1po7v0stqang0b9g036waj0/image_1c0bkrjeb1gjsni19bt147i1pvg1km.png
[112]: http://static.zybuluo.com/aubreyzheng/98104blqgy4bqn9asgenzslq/image_1c0bkrqmc12861usn1k81180icta1l3.png
[113]: http://static.zybuluo.com/aubreyzheng/dxmekpz7mlhmzrjfl09sqz23/image_1c0bks4ih1o511rvi1ihl1q9mtq31lg.png
[114]: http://static.zybuluo.com/aubreyzheng/jl7t9j2olo40f7cov4aruz0q/image_1c0bkshlk18rvi6n12ea1iq45901lt.png
[115]: http://static.zybuluo.com/aubreyzheng/6u9mfb41yrdwt9ptyd2frs1m/image_1c0bkssbuj2p19hhajt17be2r21ma.png
[116]: http://static.zybuluo.com/aubreyzheng/sq7z9p0aaxb4xcrgnsnza6pc/image_1c0bkt6lduufgsr1lon3n9maa1mn.png
[117]: http://static.zybuluo.com/aubreyzheng/ni5ume94g1lt696l6pu3db97/image_1c0bktgim1iodlkj1786umi18us1n4.png
[118]: http://static.zybuluo.com/aubreyzheng/szzrvino4b03au2io5q44z0w/image_1c0bktoukd4sj751dmu18npjqd1nh.png
[119]: http://static.zybuluo.com/aubreyzheng/mzy90dmmka28k39m94gb2lxe/image_1c0bl46en1i8g5cad4t13r31f821qb.png
[120]: http://static.zybuluo.com/aubreyzheng/b0v6vin4mck1hhuq45jxqwif/image_1c0bl4fl5ab7l2u801vloam71qo.png
[121]: http://static.zybuluo.com/aubreyzheng/z42kohkuapcyo7je98qc1ya4/image_1c0bl5cqkr4oshurnh1tr9qgh1r5.png
[122]: http://static.zybuluo.com/aubreyzheng/mzq2tiuu8n1g6icm9iznbchk/image_1c0bl5m6nmvp1stm1mve7du1u151ri.png
[123]: http://static.zybuluo.com/aubreyzheng/amlkjdtguagxbaqh63nnkc42/image_1c0bl638t1274b47u0ov7uihe1rv.png
[124]: http://static.zybuluo.com/aubreyzheng/gtxyxqkjun0764bvvd3np55o/image_1c0bl79c51sc5197p10et1bm619ps1sc.png
[125]: http://static.zybuluo.com/aubreyzheng/tnjx5pq8hwzjstpkkhfsp3f5/image_1c0bl8htnbsm16lhccj1ado14901sp.png
[126]: http://static.zybuluo.com/aubreyzheng/or3lur7t0ag87ocwznw7mol5/image_1c0bl9gdj11rt1pn6g0p1pli1ngt1t6.png
[127]: http://static.zybuluo.com/aubreyzheng/wxu79oa5lssudbh7glangeb2/image_1c0bl9vv9nsojf1r7h5og12gf1tj.png
[128]: http://static.zybuluo.com/aubreyzheng/5e14hr679co12lu69mkuf8ee/image_1c0blaf8qeve1rl51vuf3871ib21u0.png
[129]: http://static.zybuluo.com/aubreyzheng/6rnjncjrh1k1i023pyu9nfhd/image_1c0blatem1mfg1c0s1lja153c1jui1ud.png
[130]: http://static.zybuluo.com/aubreyzheng/8941bkawpocgw2qo9pm95rei/image_1c0blb49d1dfo2tm1vi31n3f17gi1uq.png
[131]: http://static.zybuluo.com/aubreyzheng/z7itz04crxwcfhkw1bdano5n/image_1c0blbpa6nmv9q0tsp12nn19rn1v7.png
[132]: http://static.zybuluo.com/aubreyzheng/73r2bln7v5uvg05miq0kwow4/image_1c0blc05bg5svc7chv1ssq73c1vk.png
[133]: http://static.zybuluo.com/aubreyzheng/5md1ckbxnudwmu7bsewnjl9i/image_1c0bldjoj1qic1i6375d1lsh154v21h.png
[134]: http://static.zybuluo.com/aubreyzheng/kh8niqgn16ng4n1sezfmomyd/image_1c0blducmgd8qa217mp1ul01on021u.png
[135]: http://static.zybuluo.com/aubreyzheng/cvsruqhcfqv70q8uid4gsxh7/image_1c0blev5v12ess0ied86rjja722b.png
[136]: http://static.zybuluo.com/aubreyzheng/klj4zklbf5xnm7zucdfzzbkd/image_1c0blfk381h8s1f5s1vbf1egcvn022o.png
[137]: http://static.zybuluo.com/aubreyzheng/xdszn23w5s5o6qrbgz27v9ht/image_1c0blg77913urboo1sv3c7c1k40235.png
[138]: http://static.zybuluo.com/aubreyzheng/ydnfymyamfppic6nic386qsh/image_1c0blgqhrmmc1pci1s13hl0mmh23i.png
[139]: http://static.zybuluo.com/aubreyzheng/5hem9ntu4epfdyqb5fw1cze6/image_1c0blhhnd5j2194s1bst1lpc1st523v.png
[140]: http://static.zybuluo.com/aubreyzheng/e059hu6h38j93x7pklf97s3c/image_1c0bllfe512of1k01sa11e14102424c.png
[141]: http://static.zybuluo.com/aubreyzheng/jk51wragrmsmfto8g8yprepl/image_1c0blm0mddub11jg1ef6c1u1oe824p.png
[142]: http://static.zybuluo.com/aubreyzheng/w3g9c2c628r3ctnj1vmpvu6v/image_1c0blmmi310n71b951rimoo41pa9256.png
[143]: http://static.zybuluo.com/aubreyzheng/6r7vlt027t6d7kc3bvg4ve0b/image_1c0blnhr51jo1gd8rj5gld4ll25j.png
[144]: http://static.zybuluo.com/aubreyzheng/vr16os9gewfc585panvfytuv/image_1c0blo0mka38741h8l1cth65k260.png
[145]: http://static.zybuluo.com/aubreyzheng/6vrgwx924uiw7gouz9gi4srp/image_1c0blot4i1hku1ng6g9n14p5qem26d.png
[146]: http://static.zybuluo.com/aubreyzheng/pfc0lclttnaxuszf7quf88ey/image_1c0blpcfad3o12ct7f51722e4l26q.png
[147]: http://static.zybuluo.com/aubreyzheng/snqkob9t2eqcf2rxkahphmp7/image_1c0blq4o0b293161a42fd11bs9277.png
[148]: http://static.zybuluo.com/aubreyzheng/25red0rawbg0ay2y3b1nkb8e/image_1c0blqv1h15uljmv3q1m8og7s27k.png
[149]: http://static.zybuluo.com/aubreyzheng/5y2dqb57q9qbhrloo73orxg8/image_1c0blrqj61c51cps1omd1lkr7bd281.png
[150]: http://static.zybuluo.com/aubreyzheng/ezlparxosb61exm7eqpnbrje/image_1c0blst921gpudlh6u51mth6gv28e.png
[151]: http://static.zybuluo.com/aubreyzheng/s847do97hbqct2pn2dzy2yyn/image_1c0bltm7d13on5bc1ou627o1q9p28r.png
[152]: http://static.zybuluo.com/aubreyzheng/samzeoql2isq5w52utvrrvmm/image_1c0bm05dg16056fl15c7c961arm2b8.png
[153]: http://static.zybuluo.com/aubreyzheng/7dwgypobxm4hocl0t6rrjfi1/image_1c0bm0026igglte16si1n6q1sn52ar.png |
|