經常使用模塊介紹python
模塊本質就是一個.py文件。能夠理解成是把一堆相關類型的函數寫進一個py文件裏面,直接拿出來使用就能夠了 分爲三部分:內置模塊、第三方模塊、自定義模塊(模塊調用、包)linux
###Time模塊web
在Python中,一般有這三種方式來表示時間:時間戳、元組(struct_time)、格式化的時間字符串。正則表達式
(1)時間戳(timestamp) :一般來講,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。咱們運行「type(time.time())」,返回的是float類型。算法
(2)格式化的時間字符串(Format String): ‘1988-03-16’shell
(3)結構化時間元組(struct_time) :struct_time元組共有9個元素共九個元素:(年,月,日,時,分,秒,一年中第幾周,一年中第幾天等)數據庫
<1>時間戳編程
import time
In [16]: time.time() #返回當前時間的時間戳(給計算機看 ),從Unix元年到如今通過的秒
Out[16]: 1498030482.9540176
In [17]: c = time.time()
In [18]: c/3600/24/365
Out[18]: 47.502235409268984
<2>格式化時間字符串json
time.strftime("%Y-%m-%d %X")
'2017-04-26 00:32:18'
<3> 結構化時間元組windows
time.localtime()
time.struct_time(tm_year=2017, tm_mon=4, tm_mday=26,
tm_hour=0, tm_min=32, tm_sec=42, tm_wday=2,
tm_yday=116, tm_isdst=0)
In [12]: c = time.localtime()
In [13]: c.tm_year
Out[13]: 2017
小結:時間戳是計算機可以識別的時間;時間字符串是人可以看懂的時間;元組則是用來操做時間的
幾種時間形式的轉換:
1.時間戳------》結構化時間: localtime/gmtime
In [19]: time.localtime() #不給參數默認當前時間戳
Out[19]: time.struct_time(tm_year=2017, tm_mon=6, tm_mday=21, tm_hour=15, tm_min=45, tm_sec=44, tm_wday=2, tm_yday=172, tm_isdst=0)
In [20]: time.gmtime() #不給參數默認當前時間戳
Out[20]: time.struct_time(tm_year=2017, tm_mon=6, tm_mday=21, tm_hour=7, tm_min=45, tm_sec=56, tm_wday=2, tm_yday=172, tm_isdst=0)
備註:gmtime是時間是標準時間UTC。
2.結構化時間-----》時間戳:mktime
In [21]: time.mktime() #不給參數就報錯
TypeError Traceback (most recent call last)
<ipython-input-21-68ccb7b7a629> in <module>()
----> 1 time.mktime()
TypeError: mktime() takes exactly one argument (0 given)
In [22]: time.mktime(time.localtime())
Out[22]: 1498031424.0
3.結構化時間:----》字符串時間: strftime
In [24]: time.strftime("%Y-%m-%d %X", time.localtime())
Out[24]: '2017-06-21 15:56:14'
In [25]: time.strftime('%Y-%m-%d',time.localtime(time.time()-365*24*3600))
Out[25]: '2016-06-21'
4.字符串時間-----》結構化時間 strptime
In [29]: time.strptime("2017-03-16","%Y-%m-%d")
Out[29]: time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1)
In [31]: time.strptime("2017-06-21 16:05:45","%Y-%m-%d %X")
Out[31]: time.struct_time(tm_year=2017, tm_mon=6, tm_mday=21, tm_hour=16, tm_min=5, tm_sec=45, tm_wday=2, tm_yday=172, tm_isdst=-1)
其他兩種直接轉換成字符串時間格式
1.時間戳------》字符串時間格式
In [32]: time.ctime() #不給參數默認爲當前時間戳 等同於 time.ctime(time.time())
Out[32]: 'Wed Jun 21 16:10:57 2017'
In [33]: time.ctime(2315554656)
Out[33]: 'Mon May 18 17:37:36 2043'
2.結構化時間------》字符串時間格式
In [34]: time.asctime() #不給參數默認爲當前結構化時間 等同於time.asctime(time.localtime())
Out[34]: 'Wed Jun 21 16:16:11 2017'
其餘方法
sleep(secs) #至關於一個IO,不佔用CPU,線程推遲指定的時間運行,單位爲秒。
###random模塊
>>> import random
>>> random.random() # 大於0且小於1之間的小數,float類型
0.7664338663654585
>>> random.randint(1,5) # 大於等於1且小於等於5之間的整數
2
>>> random.randrange(1,3) # 大於等於1且小於3之間的整數,顧頭不顧尾
1
>>> random.choice([1,'23',[4,5]]) # 1或者23或者[4,5],隨機一次取列表中任意一個元素。
1
>>> random.sample([1,'23',[4,5]],2) #列表元素任意2個組合成列表顯
[[4, 5], '23']
>>> random.uniform(1,3) #隨機取一個大於1小於3的小數
1.6270147180533838
>>> item=[1,3,5,7,9]
>>> random.shuffle(item) # 打亂次序
>>> item
[5, 1, 3, 7, 9]
>>> random.shuffle(item)
>>> item
[5, 9, 7, 1, 3]
例子:隨機生成一個包含數字,大小寫字母的五位隨機數:
import random
def vadate_code():
ret = ''
for i in range(5):
num =random.randint(0,9)
alfa = chr(random.randint(97,122))
alfa2 = chr(random.randint(65,90))
s = random.choice([str(num),alfa,alfa2])
ret = ret + s
return ret
print(vadate_code())
注意一點:寫py文件時必定不要跟咱們模塊重名,一旦重名就會致使模塊沒法使用!!!
------
###hashlib 模塊
3.1 算法介紹
Python的hashlib提供了常見的摘要算法,如MD5,SHA1等等。 什麼是摘要算法呢?摘要算法又稱哈希算法、散列算法。它經過一個函數,把任意長度的數據轉換爲一個長度固定的數據串(一般用16進制的字符串表示)。 摘要算法就是經過摘要函數f()對任意長度的數據data計算出固定長度的摘要digest,目的是爲了發現原始數據是否被人篡改過。 摘要算法之因此能指出數據是否被篡改過,就是由於摘要函數是一個單向函數,計算f(data)很容易,但經過digest反推data卻很是困難。並且,對原始數據作一個bit的修改,都會致使計算出的摘要徹底不一樣。
咱們以常見的摘要算法MD5爲例,計算出一個字符串的MD5值:
md5(string=b'')
Return a new MD5 hash object; optionally initialized with a string.
In [37]: import hashlib
In [39]: m = hashlib.md5()
In [41]: print(m) #返回的是一個hash對象
<_md5.md5 object at 0x7fc266746030>
In [49]: m1 = hashlib.md5(b'hello')
In [50]: m1
Out[50]: <_md5.md5 at 0x7fc2667069d0>
In [51]: m1.hexdigest()
Out[51]: '5d41402abc4b2a76b9719d911017c592'
In [52]: m = hashlib.md5()
In [54]: m.update(b'hello') #update至關於更新
In [56]: m.hexdigest()
Out[56]: '5d41402abc4b2a76b9719d911017c592'
In [57]: m.update(b'hello') #此次是在上次的基礎上更新至關於b’hellohello‘,因此兩次生成的結果是不相同的
In [58]: m.hexdigest()
Out[58]: '23b431acfeb41e15d466d75de822307c'
In [59]: n = hashlib.md5()
In [60]: n.update(b'hellohello') #這個跟上面update兩次hello的結果是相同的
In [61]: n.hexdigest()
Out[61]: '23b431acfeb41e15d466d75de822307c'
其他算法
m = hashlib.sha1() #只要把咱們上面md5換成sha1就能夠了,其他的跟上面同樣。
摘要算法應用:
任何容許用戶登陸的網站都會存儲用戶登陸的用戶名和口令。如何存儲用戶名和口令呢?方法是存到數據庫表中:
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模塊:跟文件系統打交道接口,跨系統的API.
經常使用:
os.getcwd() 獲取當前工做目錄,即當前python腳本工做的目錄路徑 至關於linux pwd
In [4]: os.getcwd()
Out[4]: '/root'
os.chdir("dirname") 改變當前腳本工做目錄;至關於shell下cd
os.makedirs('dirname1/dirname2') 可生成多層遞歸目錄, 至關於shell中mkdir -p dirname
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') 獲取文件/目錄信息
In [5]: os.stat('aaa')
Out[5]: os.stat_result(st_mode=33188, st_ino=136945, st_dev=2051, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1494057367, st_mtime=1494057367, st_ctime=1494057367)
os.path.abspath(path) 返回path規範化的絕對路徑
os.path.dirname(path) 返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path) 返回path最後的文件名。如何path以/或\結尾,那麼就會返回空值。即
os.path.exists(path) 若是path存在,返回True;若是path不存在,返回False
os.path.join(path1[, path2[, ...]]) 將多個路徑組合後返回,第一個絕對路徑以前的參數將被忽略
os.path.getatime(path) 返回path所指向的文件或者目錄的最後存取時間
os.path.getmtime(path) 返回path所指向的文件或者目錄的最後修改時間
os.path.getsize(path) 返回path的大小
os.symlink = symlink(src, dst, target_is_directory=False, *, dir_fd=None) 建立連接文件
os.symlink('test2.txt','test.syslink')
os.utime() 更新文件時間戳
os.tmpfile() 建立並打開(w+b)一個新的臨時文件
os.walk() 目錄樹生成器,至關於shell的tree命令。
不經常使用:
os.chroot():設定當前進程的根目錄
os.curdir 返回當前目錄: ('.')
os.pardir 獲取當前目錄的父目錄字符串名:('..')
os.sep 輸出操做系統特定的路徑分隔符,win下爲"\",Linux下爲"/"
os.linesep 輸出當前平臺使用的行終止符,win下爲"\t\n",Linux下爲"\n"
os.pathsep 輸出用於分割文件路徑的字符串 win下爲;,Linux下爲:
os.name 輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'
os.system("bash command") 運行shell命令,直接顯示
os.mkfifo() 建立命名管道
os.mknod 建立設備文件
os.unlink 刪除連接文件
os.environ 獲取系統環境變量
os.path.split(path) 將path分割成目錄和文件名二元組返回
os.path.splitext(path) 返回(filename,extension)元組
os.path.isabs(path) 若是path是絕對路徑,返回True
os.path.isfile(path) 若是path是一個存在的文件,返回True。不然返回False
os.path.isdir(path) 若是path是一個存在的目錄,則返回True。不然返回False
os.path.islink(path) 若是path是一個存在的連接文件,則返回True。不然返回False
os.path.ismount(path) 若是path是一個掛載點,則返回True。不然返回False
os.access('test2.txt',0) 斷定某用戶對文件是否有訪問權限,返回布爾值。
os.chmod() 修改權限
os.chown() 修改屬主屬組
os.umask() 設置默認權限模式
------
### sys模塊:跟python解釋器打交道的
sys.argv 命令行參數List,第一個元素是程序自己路徑
sys.exit(n) 退出程序,正常退出時exit(0)
sys.version 獲取Python解釋程序的版本信息
sys.maxint 最大的Int值 python沒有這個
sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform 返回操做系統平臺名稱
###logging模塊
函數式簡單配置
import logging
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
默認狀況下Python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置爲WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG),默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息
靈活配置日誌級別,日誌格式,輸出位置:
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S', 改變默認輸出格式
filename='/tmp/test.log', #輸出到文件,不在在屏幕輸出。
filemode='w') #寫文件模式,大部分是a追加模式寫
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
配置參數:
logging.basicConfig()函數中可經過具體參數來更改logging模塊默認行爲,可用參數有
filename:用指定的文件名建立FiledHandler,這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲「a」還可指定爲「w」。
format:指定handler使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設置rootlogger(後邊會講解具體概念)的日誌級別
stream:用指定的stream建立StreamHandler。能夠指定輸出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默認爲sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。
format參數中可能用到的格式化串:
%(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:45,896」。逗號後面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s用戶輸出的消息
logger對象配置
import logging
logger = logging.getLogger() #建立一個對象,對象就必定有對應的方法
fh = logging.FileHandler('test.log') # 建立一個handler,用於寫入日誌文件
ch = logging.StreamHandler() # 再建立一個handler,用於輸出到控制檯
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) #logger對象能夠添加多個fh和ch對象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程序可直接使用的接口,Handler發送日誌到適當的目的地,Filter提供了過濾日誌信息的方法,Formatter指定日誌顯示格式。另外,能夠經過:logger.setLevel(logging.Debug)設置級別。
-----
###序列化模塊
以前咱們學習過用eval內置方法能夠將一個字符串轉成python對象,不過,eval方法是有侷限性的,對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就無論用了,因此eval的重點仍是一般用來執行一個字符串表達式,並返回表達式的值。
轉換類型
d={"name":"yuan"}
s=str(d)
print(type(s))
d2=eval(s)
print(d2[1])
with open("test") as f:
for i in f :
if type(eval(i.strip()))==dict:
print(eval(i.strip())[1])
計算
print(eval("12*7+5-3"))
什麼是序列化?
咱們把對象(變量)從內存中變成可存儲或傳輸的過程稱之爲序列化,在Python中叫pickling,在其餘語言中也被稱之爲serialization,marshalling,flattening等等,都是一個意思。序列化以後,就能夠把序列化後的內容寫入磁盤,或者經過網絡傳輸到別的機器上。反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化,即unpickling。
#### json模塊
若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,由於JSON表示出來就是一個字符串,能夠被全部語言讀取,也能夠方便地存儲到磁盤或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。 JSON表示的對象就是標準的JavaScript語言的對象一個子集,JSON和Python內置的數據類型對應以下:
import json
i=10
s='hello'
t=(1,4,6)
l=[3,5,7]
d={'name':"yuan"}
json_str1=json.dumps(i)
json_str2=json.dumps(s)
json_str3=json.dumps(t)
json_str4=json.dumps(l)
json_str5=json.dumps(d)
print(json_str1) #'10'
print(json_str2) #'"hello"'
print(json_str3) #'[1, 4, 6]' #元組在json裏面存的形式是跟列表存的相似的。
print(json_str4) #'[3, 5, 7]'
print(json_str5) #'{"name": "yuan"}'
python在文本中的使用:
#序列化
第一寫法:
import json
dic={'name':'alvin','age':23,'sex':'male'}
f=open('a.txt','w')
data=json.dumps(dic)
f.write(data)
f.close()
第二種寫法:
import json
dic={'name':'alvin','age':23,'sex':'male'}
f=open('a.txt','w')
json.dump(dic,f)
f.close()
#反序列化
import json
f=open('序列化對象')
new_data=json.loads(f.read())# 等價於data=json.load(f)
print(type(new_data))
-------
#### pickle模塊
#序列化
import pickle
dic={'name':'alvin','age':23,'sex':'male'}
print(type(dic)) #<class 'dict'>
j=pickle.dumps(dic)
print(type(j)) #<class 'bytes'>
f=open('序列化對象_pickle','wb') #注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j) #等價於pickle.dump(dic,f) 推薦使用這種
f.close()
#反序列化
import pickle
f=open('序列化對象_pickle','rb')
data=pickle.loads(f.read())# 等價於data=pickle.load(f)
print(data['age'])
------
### shelve模塊
shelve模塊比pickle模塊簡單,只有一個open函數,返回相似字典的對象,可讀可寫;key必須爲字符串,而值能夠是python所支持的數據類型
import shelve
f = shelve.open(r'shelve.txt')
f['stu1_info']={'name':'alex','age':'18'}
f['stu2_info']={'name':'alvin','age':'20'}
f['school_info']={'website':'oldboyedu.com','city':'beijing'}
f.close()
print(f.get('stu_info')['age'])
------
###re模塊
就其本質而言,正則表達式(或 RE)是一種小型的、高度專業化的編程語言,(在Python中)它內嵌在Python中,並經過 re 模塊實現。正則表達式模式被編譯成一系列的字節碼,而後由用 C 編寫的匹配引擎執行。
相似shell擴展正則表達式:
元字符:
. 通配 任意單個字符,除\n不能匹配。最後加re.S就是使.通配任意字符,包括\n.
In [1]: s = 'aaass1234\n112klljl'
In [2]: import re
In [3]: re.findall("ss.*k",s)
Out[3]: []
In [4]: re.findall("ss.*k",s,re.S)
Out[4]: ['ss1234\n112k']
[...]任意單個字符 # 在字符集裏有功能的符號: - ^ \
In [18]: re.findall(r"a[\d]c","asda2c1231asd31121as") #\d在[]中也可使用。
Out[18]: ['a2c']
[^....]不在範圍內任意單個字符
次數匹配:
* 任意次
+ 【1,+00】
\?【0,1】
{} {n,m}
{m} m次
{0,n } 最多n次
{m,} 最少m次
錨定:
^ 行首
$ 行尾
\b 詞首,詞尾,匹配一個特殊字符邊界,好比空格 ,&,#等
分組:
In [5]: re.findall('(123)+','asd123adsa123123123asd')
Out[5]: ['123', '123'] #findall分組中優先級高顯示
In [6]: re.findall('(?:123)+','asd123adsa123123123asd')
Out[6]: ['123', '123123123'] #?:在分組中能夠去掉分組的優先級
(?P<xx>...):命名分組
In [8]: ret = re.search(r"-blog-aticles-(?P<year>20[01]\d)-(?P<month>\d+)","-blog-aticles-2005-12")
In [9]: ret.group("year")
Out[9]: '2005'
In [10]: ret.group("month")
Out[10]: '12'
轉義符號 \ ,加r原生轉義,因此使用轉義符時儘可能使用r
一、反斜槓後邊跟元字符去除特殊功能,好比.
二、反斜槓後邊跟普通字符實現特殊功能,好比\d
\d 匹配任何十進制數;它至關於類 [0-9]。
\D 匹配任何非數字字符;它至關於類 [^0-9]。
\s 匹配任何空白字符;它至關於類 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它至關於類 [^ \t\n\r\f\v]。
\w 匹配任何字母數字字符;它至關於類 [a-zA-Z0-9_]。
\W 匹配任何非字母數字字符;它至關於類 [^a-zA-Z0-9_]
\nn:後項引用
|或者:path1 | path
貪婪匹配:在知足匹配時,匹配儘量長的字符串,默認狀況下,採用貪婪匹配
In [34]: re.findall("abc{2,5}","abcccccasd")
Out[34]: ['abccccc']
非貪婪匹配:在知足匹配時,匹配儘量短的字符串,在次數匹配後加?
In [35]: re.findall("abc{2,5}?","abcccccasd")
Out[35]: ['abcc']
*? 重複任意次,但儘量少重複
+? 重複1次或更屢次,但儘量少重複
?? 重複0次或1次,但儘量少重複
{n,m}? 重複n到m次,但儘量少重複
{n,}? 重複n次以上,但儘量少重複
.*?的用法:
. 是任意字符
* 是取 0 至 無限長度
? 是非貪婪模式。
何在一塊兒就是 取儘可能少的任意字符,通常不會這麼單獨寫,他大多用在:
.*?x
就是取前面任意長度的字符,直到一個x出現
非貪婪匹配一個小例子:
In [36]: s = "<div>zeng<img></div><a href=""></div>"
In [37]: re.findall("<div>.*?</div>",s)
Out[37]: ['<div>zeng<img></div>']
re模塊的經常使用方法:
findall(): # 返回全部知足匹配條件的結果,放在列表裏
re.findall('a','alvin yuan')
search():只到找到第一個匹配而後返回一個包含匹配信息的對象,經過調用group()方法獲得匹配的字符串,若是字符串沒有匹配,則返回None。
In [20]: re.search('a','alvin yuan').group()
Out[20]: 'a'
match(): #同search,不過是從字符串開始處進行匹配 ,至關於行首錨定匹配
In [23]: re.match('a','bbabc') #沒匹配到不返回結果
In [24]: re.match('a','abc')
Out[24]: <_sre.SRE_Match object; span=(0, 1), match='a'>
In [25]: re.match('a','abc').group()
Out[25]: 'a'
split(): #分割,以列表返回分隔結果
In [26]: re.split("\d+","dff12hjsg1jkhsd145jhasdj")
Out[26]: ['dff', 'hjsg', 'jkhsd', 'jhasdj']
In [27]: re.split("\d+","dff12hjsg1jkhsd145jhasdj",2) #最多分隔2次
Out[27]: ['dff', 'hjsg', 'jkhsd145jhasdj']
In [38]: re.split("(\d+)","dff12hjsg1jkhsd145jhasdj") #模式括號括起來也能夠把分隔符一塊兒拿到。
Out[38]: ['dff', '12', 'hjsg', '1', 'jkhsd', '145', 'jhasdj']
sub():替換
In [28]: re.sub("\d+","xxx","kdfjkj2132js1jkh112")
Out[28]: 'kdfjkjxxxjsxxxjkhxxx'
In [29]: re.sub("\d+","xxx","kdfjkj2132js1jkh112",1) #最後1表明咱們須要替換幾回
Out[29]: 'kdfjkjxxxjs1jkh112'
補充:字符串的替換使用replace
subn():替換並把替換的次數返回給咱們
In [30]: re.subn("\d+","xxx","kdfjkj2132js1jkh112")
Out[30]: ('kdfjkjxxxjsxxxjkhxxx', 3)
In [31]: re.subn("\d+","xxx","kdfjkj2132js1jkh112",2)
Out[31]: ('kdfjkjxxxjsxxxjkh112', 2)
compile():編譯,好處是若是匹配屢次相同模式,咱們編譯一次,後續直接調用該編譯模式就可使用,不用每次重複去寫模式。
In [32]: c = re.compile("\d+")
In [33]: c.findall("jashd11jkasjhd45jkd12")
Out[33]: ['11', '45', '12']
finditer(): #返回的是一個迭代器對象
In [39]: ret = re.finditer("\d+","asds123shd145shghd1jshdj45hjshg778jksj225jhsdhh445jskhd5")
In [40]: type(ret)
Out[40]: builtins.callable_iterator
In [41]: next(ret)
Out[41]: <_sre.SRE_Match object; span=(4, 7), match='123'>
In [42]: next(ret).group()
Out[42]: '145'
In [43]: next(ret).group()
Out[43]: '1'
In [44]: next(ret).group()
Out[44]: '45'
正則匹配幾個小練習:
一、 匹配一段文本中的每行的郵箱
import re
res = re.findall(r"\w+\@\w{2,3}\.com","asdfg,aas1233@qq.com,hjghgjj,4444,jhgjgs1233@163.com,1112")
print(res)
二、 匹配一段文本中的每行的時間字符串,好比:‘1990-07-12’;
import re
res = re.findall(r"(?:1[0-9]{3}|20[10][1-9])-(?:0?[1-9]|1[0-2])-(?:0?[1-9]|[1,2][0-9]|3[01])","asdd,1990-07-12,aaasd1992-05-05asasdd,aaasddf")
print(res)
三、 匹配一段文本中全部的身份證數字。
import re
res = re.findall("\d{17}[0-9X]","ksdjkljlk421182199005046552lkfllkdk,slkklkliofjoifa")
print(res)
四、 匹配qq號。(騰訊QQ號從10000開始)
import re
res = re.findall("[1-9][0-9]{4,}","10000,12255546,140000222,854905819")
print(res)
五、 匹配一個浮點數。
import re
res = re.findall(r"-?[0-9]+\.[0-9]+","11224,5588,5.223,412.235,1025,0.125,-12.12")
print(res)
六、 匹配漢字。
import re
res = re.findall(r"[\u4e00-\u9fa5]+","鋼蛋,122,xxx,曾")
print(res)
七、 匹配出全部整數
import re
res = re.findall(r"-?[1-9][0-9]*","11224,-5588,dddfff,klkjlkj")
print(res)
使用正則爬豆瓣電影
import requests
import re
def init(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
next(res)
return res
return wrapper
def getPage(target):
count = 0
for i in range(10):
respase_str = requests.get("https://movie.douban.com/top250?start=%d&filter="%count)
# print(respase_str.text)
count +=25
target.send(respase_str.text)
@init
def run():
l2 = [ ]
while True:
resonse = yield
# print(resonse)
obj = re.compile('<div class="item">.*?<em.*?>(\d+)</em>.*?<span class="title">(.*?)</span>'\
'.*?<p.*?>.*?(導演:.*?) .*?<span class="rating_num".*?>(.*?)</span>'\
'.*?<span>(.*?)</span>',re.S)
ret = obj.findall(resonse)
# print(ret)
l1 = [ ]
for i in ret:
dic1 = dict(zip(('ID','片名','導演','評分','評論數'),i))
l1.append(dic1)
for i in l1:
date = str(i)+'\n'
with open('dianying.txt','a',encoding='utf8') as f:
f.write(date)
getPage(run())
使用正則實現計算器功能:
# 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等相似公式的計算器程序
import re
s = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
def fun2(res): #計算括號裏面匹配出來的式子
res = res.strip('()')
res = res.replace(' ','')
find1 = re.search("[*/]",res)
if find1:
find2 = re.search(r"(?P<a>-?\d+\.?\d*)[*/](?P<b>-?\d+\.?\d*)", res)
# print(find2.group())
if find1.group() == '/':
res2 = float(find2.group("a"))/float(find2.group("b"))
res = res.replace(find2.group(),str(res2))
# print(res)
return fun2(res)
if find1.group() == '*':
res2 = float(find2.group("a")) * float(find2.group("b"))
res = res.replace(find2.group(),str(res2))
return fun2(res)
find3 = re.search("[+\-]",res)
if find3:
find4 = re.search(r"(?P<a>-?\d+\.?\d*)(?P<c>[+\-])(?P<b>-?\d+\.?\d*)", res)
if find4: # 若是找到不是一個表達式不執行
if find4.group("c") == '+':
res4 = float(find4.group("a")) + float(find4.group("b"))
res = res.replace(find4.group(),str(res4))
return fun2(res)
if find4.group("c") == '-':
res4 = float(find4.group("a")) - float(find4.group("b"))
res = res.replace(find4.group(),str(res4))
return fun2(res)
return res
def fun1(s):
s = s.replace(' ','')
if '(' in s or ')' in s: #判斷式子是否有括號
res = re.search(r"\([^()]+\)", s).group()
res2 = fun2(res)
s = s.replace(res,res2)
# print(s)
return fun1(s)
else:
res3 = fun2(s)
return res3
print(fun1(s))
----
###subprocess模塊
當咱們須要調用系統的命令的時候,最早考慮的os模塊。用os.system()和os.popen()來進行操做。可是這兩個命令過於簡單,不能完成一些複雜的操做,如給運行的命令提供輸入或者讀取命令的輸出,判斷該命令的運行狀態,管理多個命令的並行等等。這時subprocess中的Popen命令就能有效的完成咱們須要的操做。
#win下
import subprocess
s = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)
print(s.stdout.read().decode('gbk'))
#linux下
import subprocess
s = subprocess.Popen('ls')
s = subprocess.Popen('ls -l',shell=True)
s = subprocess.Popen(['ls','-l'])
備註:s.wait() 執行完子進程再去執行父進程後面的程序。
----
### configparser模塊
該模塊適用於配置文件的格式與windows ini文件相似,能夠包含一個或多個節(section),每一個節能夠有多個參數(鍵=值)。
來看一個好多軟件的常見文檔格式以下:
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = hg
[topsecret.server.com]
Port = 50022
ForwardX11 = no
若是想用python生成一個這樣的文檔怎麼作呢?
建立文件:
import configparser
config = configparser.ConfigParser() #建立一個對象,當作一個字典
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9',
'ForwardX11':'yes'
}
config['bitbucket.org'] = {'User':'hg'}
config['topsecret.server.com'] = {'Host Port':'50022','ForwardX11':'no'}
with open('example.ini', 'w') as f:
config.write(f) #格式就是這樣把咱們的config對象寫進文件f。
查找文件
import configparser
config = configparser.ConfigParser()
#查找文件內容,基於字典的形式
print(config.sections()) # sections打印配置文件的字段信息,想當於最最外層字典key。此時還沒讀文件爲空。
config.read('example.ini') #要先把文件讀出來
print(config.sections()) # ['bitbucket.org', 'topsecret.server.com'],還有一個DEFAULT沒有顯示出來,這個項至關於公共的,每一個裏面都有
print('bytebong.com' in config) # False 跟判斷某個字符串是否是字典的key相似
print('bitbucket.org' in config) # True
print(config['bitbucket.org']["user"]) # hg
print(config['DEFAULT']['Compression']) #yes
print(config['topsecret.server.com']['ForwardX11']) #no
print(config['bitbucket.org']) #<Section: bitbucket.org>拿的是一個對象
for key in config['bitbucket.org']: # 注意,有default會把默認裏面的鍵也取出來。
print(key)
print(config.options('bitbucket.org')) # 同for循環,找到'bitbucket.org'下全部鍵
print(config.items('bitbucket.org')) #找到'bitbucket.org'下全部鍵值對
print(config.get('bitbucket.org','compression')) # yes get方法取深層嵌套的值
增刪改操做
import configparser config = configparser.ConfigParser() config.read('example.ini') config.add_section('yuan') config.remove_section('bitbucket.org') config.remove_option('topsecret.server.com',"forwardx11") config.set('topsecret.server.com','k1','11111') config.set('yuan','k2','22222') config.write(open('new2.ini', "w"))