1、 time模塊
時間表示形式
在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() #--------------返回當前時間的時間戳 1493136727.099066 # <2> 時間字符串
>>> time.strftime("%Y-%m-%d %X") '2017-04-26 00:32:18' # <3> 時間元組
>>> 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)
小結:時間戳是計算機能夠識別的時間;時間字符串是人能夠看懂的時間;元組則是用來操作時間的
幾種時間形式的轉換
(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 # 線程推遲指定的時間運行,單位為秒。
2、 random模塊
>>> import random >>> random.random() # 大於0且小於1之間的小數 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 v_code(): code = '' for i in range(5): num=random.randint(0,9) alf=chr(random.randint(65,90)) add=random.choice([num,alf]) code="".join([code,str(add)]) return code print(v_code())
3、 hashlib
3.1 算法介紹
Python的hashlib提供了常見的摘要算法,如MD5,SHA1等等。
什么是摘要算法呢?摘要算法又稱哈希算法、散列算法。它通過一個函數,把任意長度的數據轉換為一個長度固定的數據串(通常用16進制的字符串表示)。
摘要算法就是通過摘要函數f()對任意長度的數據data計算出固定長度的摘要digest,目的是為了發現原始數據是否被人篡改過。
摘要算法之所以能指出數據是否被篡改過,就是因為摘要函數是一個單向函數,計算f(data)很容易,但通過digest反推data卻非常困難。而且,對原始數據做一個bit的修改,都會導致計算出的摘要完全不同。
我們以常見的摘要算法MD5為例,計算出一個字符串的MD5值:
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib?') print md5.hexdigest() 計算結果如下: d26a53750bc40b38b65a520292f69306
如果數據量很大,可以分塊多次調用update(),最后計算的結果是一樣的:
md5 = hashlib.md5() md5.update('how to use md5 in ') md5.update('python hashlib?') print md5.hexdigest()
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,不過越安全的算法越慢,而且摘要長度更長。
3.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。
摘要算法在很多地方都有廣泛的應用。要注意摘要算法不是加密算法,不能用於加密(因為無法通過摘要反推明文),只能用於防篡改,但是它的單向計算特性決定了可以在不存儲明文口令的情況下驗證用戶口令。
4、 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下為"\t\n",Linux下為"\n" 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、os.stat('path/filename') 獲取文件/目錄信息


stat 結構: st_mode: inode 保護模式 st_ino: inode 節點號。 st_dev: inode 駐留的設備。 st_nlink: inode 的鏈接數。 st_uid: 所有者的用戶ID。 st_gid: 所有者的組ID。 st_size: 普通文件以字節為單位的大小;包含等待某些特殊文件的數據。 st_atime: 上次訪問的時間。 st_mtime: 最后一次修改的時間。 st_ctime: 由操作系統報告的"ctime"。在某些系統上(如Unix)是最新的元數據更改的時間,在其它系統上(如Windows)是創建時間(詳細信息參見平台的文檔)。
5、 sys模塊
sys.argv 命令行參數List,第一個元素是程序本身路徑
sys.exit(n) 退出程序,正常退出時exit(0)
sys.version 獲取Python解釋程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform 返回操作系統平台名稱
6、 logging模塊
6.1 函數式簡單配置
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') 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用戶輸出的消息
6.2 logger對象配置
import logging logger = logging.getLogger() # 創建一個handler,用於寫入日志文件 fh = logging.FileHandler('test.log') # 再創建一個handler,用於輸出到控制台 ch = logging.StreamHandler() 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)設置級別,當然,也可以通過
fh.setLevel(logging.Debug)單對文件流設置某個級別。
7、 序列化模塊
之前我們學習過用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]' print(json_str4) #'[3, 5, 7]' print(json_str5) #'{"name": "yuan"}'
python在文本中的使用:
#----------------------------序列化 import json dic={'name':'alvin','age':23,'sex':'male'} print(type(dic))#<class 'dict'> data=json.dumps(dic) print("type",type(data))#<class 'str'> print("data",data) f=open('序列化對象','w') f.write(data) #-------------------等價於json.dump(dic,f) f.close() #-----------------------------反序列化<br> 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'])
8、 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 configfile:
config.write(configfile)
查找文件
import configparser config = configparser.ConfigParser() #---------------------------查找文件內容,基於字典的形式 print(config.sections()) # [] config.read('example.ini') print(config.sections()) # ['bitbucket.org', 'topsecret.server.com'] print('bytebong.com' in config) # False 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會默認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"))
9、 subprocess模塊
當我們需要調用系統的命令的時候,最先考慮的os模塊。用os.system()和os.popen()來進行操作。但是這兩個命令過於簡單,不能完成一些復雜的操作,如給運行的命令提供輸入或者讀取命令的輸出,判斷該命令的運行狀態,管理多個命令的並行等等。這時subprocess中的Popen命令就能有效的完成我們需要的操作。
The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.
This module intends to replace several other, older modules and functions, such as: os.system、os.spawn*、os.popen*、popen2.*、commands.*
這個模塊只一個類:Popen。
簡單命令
import subprocess # 創建一個新的進程,與主進程不同步 if in win: s=subprocess.Popen('dir',shell=True) s=subprocess.Popen('ls') s.wait() # s是Popen的一個實例對象 print('ending...')
命令帶參數
linux:
import subprocess subprocess.Popen('ls -l',shell=True) #subprocess.Popen(['ls','-l'])
控制子進程
當我們想要更個性化我們的需求的時候,就要轉向Popen類,該類生成的對象用來代表子進程。剛才我們使用到了一個wait方法
此外,你還可以在父進程中對子進程進行其它操作:
s.poll() # 檢查子進程狀態 s.kill() # 終止子進程 s.send_signal() # 向子進程發送信號 s.terminate() # 終止子進程 s.pid:子進程號
子進程的文本流控制
可以在Popen()建立子進程的時候改變標准輸入、標准輸出和標准錯誤,並可以利用subprocess.PIPE將多個子進程的輸入和輸出連接在一起,構成管道(pipe):
import subprocess # s1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) # print(s1.stdout.read()) #s2.communicate() s1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE) s2 = subprocess.Popen(["grep","0:0"],stdin=s1.stdout, stdout=subprocess.PIPE) out = s2.communicate() print(out)
ubprocess.PIPE實際上為文本流提供一個緩存區。s1的stdout將文本輸出到緩存區,隨后s2的stdin從該PIPE中將文本讀取走。s2的輸出文本也被存放在PIPE中,直到communicate()方法從PIPE中讀取出PIPE中的文本。
注意:communicate()是Popen對象的一個方法,該方法會阻塞父進程,直到子進程完成
快捷API
''' subprocess.call() 父進程等待子進程完成 返回退出信息(returncode,相當於Linux exit code) subprocess.check_call() 父進程等待子進程完成 返回0,檢查退出信息,如果returncode不為0,則舉出錯誤subprocess.CalledProcessError,該對象包含 有returncode屬性,可用try…except…來檢查 subprocess.check_output() 父進程等待子進程完成 返回子進程向標准輸出的輸出結果 檢查退出信息,如果returncode不為0,則舉出錯誤subprocess.CalledProcessError,該對象包含 有returncode屬性和output屬性,output屬性為標准輸出的輸出結果,可用try…except…來檢查。 '''
10、 re模塊
就其本質而言,正則表達式(或 RE)是一種小型的、高度專業化的編程語言,(在Python中)它內嵌在Python中,並通過 re 模塊實現。正則表達式模式被編譯成一系列的字節碼,然后由用 C 編寫的匹配引擎執行。
字符匹配(普通字符,元字符):
1 普通字符:大多數字符和字母都會和自身匹配
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
['alvin']
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
元字符
. ^ $
import re ret1=re.findall('李.','李爽\nalex\n李四\negon\nalvin\n李二') ret2=re.findall('^李.','李爽\nalex\n李四\negon\nalvin\n李二') ret3=re.findall('李.$','李爽\nalex\n李四\negon\nalvin\n李二')
* + ? { }
import re ret1=re.findall('李.*','李傑\nalex\n李蓮英\negon\nalvin\n李二棍子') ret2=re.findall('李.+','李傑\nalex\n李蓮英\negon\nalvin\n李二棍子') ret3=re.findall('(李.{1,2})\n','李傑\nalex\n李蓮英\negon\nalvin\n李二棍子') # 設定優先級的原因 # 匹配一個數字包括整型和浮點型 ret4=re.findall('\d+\.?\d*','12.45,34,0.05,109') print(ret4)
注意:前面的*,+,?等都是貪婪匹配,也就是盡可能匹配,后面加?號使其變成惰性匹配
ret=re.findall('131\d+?','1312312312') print(ret) ['1312']
轉義符 \
1、反斜杠后邊跟元字符去除特殊功能,比如\.
2、反斜杠后邊跟普通字符實現特殊功能,比如\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_] \b 匹配一個特殊字符邊界,比如空格 ,&,#等
讓我們看一下\b的應用:
ret=re.findall(r'I\b','I am LIST') print(ret)#['I']
接下來我們試着匹配下“abc\le”中的‘c\l’:
import re ret=re.findall('c\l','abc\le') print(ret)#[] ret=re.findall('c\\l','abc\le') print(ret)#[] ret=re.findall('c\\\\l','abc\le') print(ret)#[] ret=re.findall(r'c\\l','abc\le') print(ret)#[] # \b是特殊符號所以,'abc\be'前面需要加r ret=re.findall(r'c\\b',r'abc\be') print(ret)#[]
分組 ()
m = re.findall(r'(ad)+', 'add') print(m) ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com') print(ret.group())#23/com print(ret.group('id'))#23
元字符之|
ret=re.search('(ab)|\d','rabhdg8sd') print(ret.group())#ab
字符集[]
#--------------------------------------------字符集[] ret=re.findall('a[bc]d','acd') print(ret)#['acd'] ret=re.findall('[a-z]','acd') print(ret)#['a', 'c', 'd'] ret=re.findall('[.*+]','a.cd+') print(ret)#['.', '+'] #在字符集里有功能的符號: - ^ \ ret=re.findall('[1-9]','45dha3') print(ret)#['4', '5', '3'] ret=re.findall('[^ab]','45bdha3') print(ret)#['4', '5', 'd', 'h', '3'] ret=re.findall('[\d]','45bdha3') print(ret)#['4', '5', '3']
貪婪匹配
貪婪匹配:在滿足匹配時,匹配盡可能長的字符串,默認情況下,采用貪婪匹配
string pattern1 = @"a.*c"; // greedy match Regex regex = new Regex(pattern1); regex.Match("abcabc"); // return "abcabc" 非貪婪匹配:在滿足匹配時,匹配盡可能短的字符串,使用?來表示非貪婪匹配 string pattern1 = @"a.*?c"; // non-greedy match Regex regex = new Regex(pattern1); regex.Match("abcabc"); // return "abc"
幾個常用的非貪婪匹配Pattern
*? 重復任意次,但盡可能少重復 +? 重復1次或更多次,但盡可能少重復 ?? 重復0次或1次,但盡可能少重復 {n,m}? 重復n到m次,但盡可能少重復 {n,}? 重復n次以上,但盡可能少重復
.*?的用法:
-------------------------------- . 是任意字符 * 是取 0 至 無限長度 ? 是非貪婪模式。 何在一起就是 取盡量少的任意字符,一般不會這么單獨寫,他大多用在: .*?x 就是取前面任意長度的字符,直到一個x出現
re模塊下的常用方法
import re re.findall('a','alvin yuan') #返回所有滿足匹配條件的結果,放在列表里 re.search('a','alvin yuan').group() #函數會在字符串內查找模式匹配,只到找到第一個匹配然后返回一個包含匹配信息的對象,該對象可以 # 通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None。 re.match('a','abc').group() #同search,不過盡在字符串開始處進行匹配 ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在對''和'bcd'分別按'b'分割 print(ret)#['', '', 'cd'] ret=re.sub('\d','abc','alvin5yuan6',1) ret=re.subn('\d','abc','alvin5yuan6') obj=re.compile('\d{3}') ret=obj.search('abc123eeee') print(ret.group())#123 import re ret=re.finditer('\d','ds3sy4784a') print(ret) #<callable_iterator object at 0x10195f940> print(next(ret).group()) print(next(ret).group())
注意:
1 findall的優先級查詢:
import re ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com') print(ret)#['oldboy'] 這是因為findall會優先把匹配結果組里內容返回,如果想要匹配結果,取消權限即可 ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') print(ret)#['www.oldboy.com']
2 split的優先級查詢
ret=re.split("\d+","yuan2egon56alex") print(ret) ret=re.split("(\d+)","yuan2egon56alex") print(ret)
練習
1、匹配標簽


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>"))
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)
3、數字匹配


1、 匹配一段文本中的每行的郵箱 2、 匹配一段文本中的每行的時間字符串,比如:‘1990-07-12’; 分別取出1年的12個月(^(0?[1-9]|1[0-2])$)、 一個月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 3、 匹配一段文本中所有的身份證數字。 4、 匹配qq號。(騰訊QQ號從10000開始) [1,9][0,9]{4,} 5、 匹配一個浮點數。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d* 6、 匹配漢字。 ^[\u4e00-\u9fa5]{0,}$ 7、 匹配出所有整數
4、爬蟲練習


import requests import re import json def getPage(url): response=requests.get(url) return response.text def parsePage(s): com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)評價</span>',re.S) ret=com.finditer(s) for i in ret: yield { "id":i.group("id"), "title":i.group("title"), "rating_num":i.group("rating_num"), "comment_num":i.group("comment_num"), } def main(num): url='https://movie.douban.com/top250?start=%s&filter='%num response_html=getPage(url) ret=parsePage(response_html) print(ret) f=open("move_info7","a",encoding="utf8") for obj in ret: print(obj) data=json.dumps(obj,ensure_ascii=False) f.write(data+"\n") if __name__ == '__main__': count=0 for i in range(10): main(count) count+=25
作業
實現能計算類似
1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式的計算器程序