目錄
一. 常用模塊 - hashlib
二. 常用模塊 - hmac
三. 常用模塊 - logging
四. 常用模塊 - re
五. 常用模塊 - requests
六. 常用模塊 - paramiko
?
一. 常用模塊 - hashlib
hash: 一種算法, 3.x里代替了md5模塊和sha模塊, 主要提供 SHA1, SHA224, SHA256, SHA384, SHA512, MD5 算法
特點:
- 內容相同則hash運算結果相同, 內容稍微改變則hash值則變
- 不可逆推
- 相同算法: 無論校驗多長的數據, 得到的哈希值長度固定.
1 import hashlib 2 3 m=hashlib.md5()# m=hashlib.sha256() 4 m.update('hello'.encode('utf8')) 5 print(m.hexdigest()) #5d41402abc4b2a76b9719d911017c592 6 m.update('alvin'.encode('utf8')) 7 print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af 8 9 m2=hashlib.md5() 10 m2.update('helloalvin'.encode('utf8')) 11 print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af 12 13 ''' 14 注意: 把一段很長的數據update多次, 與一次update這段長數據, 得到的結果一樣 15 但是update多次為校驗大文件提供了可能. 16 '''
以上加密算法雖然依然非常厲害, 但時候存在缺陷, 即: 通過撞庫可以反解. 所以, 有必要對加密算法中添加自定義key再來做加密.
1 import hashlib 2 # ######## 256 ######## 3 hash = hashlib.sha256('898oaFs09f'.encode('utf8')) 4 hash.update('alvin'.encode('utf8')) 5 print (hash.hexdigest()) 6 #e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
?
二. 常用模塊 - hmac
HMAC的應用
hmac主要應用在身份驗證中,它的使用方法是這樣的:
- (1) 客戶端發出登錄請求(假設是瀏覽器的GET請求)
- (2) 服務器返回一個隨機值,并在會話中記錄這個隨機值
- (3) 客戶端將該隨機值作為密鑰,用戶密碼進行hmac運算,然后提交給服務器
- (4) 服務器讀取用戶數據庫中的用戶密碼和步驟2中發送的隨機值做與客戶端一樣的hmac運算,然后與用戶發送的結果比較,如果結果一致則驗證用戶合法
在這個過程中,可能遭到安全攻擊的是服務器發送的隨機值和用戶發送的hmac結果,而對于截獲了這兩個值的黑客而言這兩個值是沒有意義的,絕無獲取用戶密碼的可能性,隨機值的引入使hmac只在當前會話中有效,大大增強了安全性和實用性。大多數的語言都實現了hmac算法,比如php的mhash、python的hmac.py、java的MessageDigest類,在web驗證中使用hmac也是可行的,用js進行md5運算的速度也是比較快的。
1 import hmac 2 h = hmac.new('alvin'.encode('utf8')) 3 h.update('hello'.encode('utf8')) 4 print (h.hexdigest()) 5 #320df9832eab4c038b6c1d7ed73a5940
?
三. 常用模塊 - logging
很多程序都有記錄日志的需求,并且日志中包含的信息即有正常的程序訪問日志,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標準的日志接口,你可以通過它存儲各種格式的日志,logging的日志可以分為?debug()
,?info()
,?warning()
,?error()
?and?critical()?5個級別,
下面我們看一下怎么用。
1 import logging 2 3 logging.warning("user [alex] attempted wrong password more than 3 times") 4 logging.critical("server is down") 5 6 #輸出 7 WARNING:root:user [alex] attempted wrong password more than 3 times 8 CRITICAL:root:server is down
上面是最簡單的應用. 但明顯還不足以與nginx, apache等成熟軟件的日志媲美. 如果想達到nginx這種日志的效果我們需要深入了解一下這個模塊.
logging : https://docs.python.org/3.6/library/logging.html
這個包中包含了以下幾個類:
- Logger 日志類, 日志的公開接口, 應用程序代碼直接使用.?
- Handler 處理類,?處理程序發送日志記錄到相應的目的地。比如將日志輸入到終端/文件/內存等.
- Formatter 格式類,?最終的輸出日志記錄以格式器指定的格式輸出。
- Filter 過濾類,?過濾器提供更細粒度的功能確定哪些日志記錄輸出。
- LogRecord XX類
- LoggerAdapter XX類
由于個人能力問題, 目前只說明Logger Handler Formatter 三個類的關系與用法. 其余三種等日后在更新.
Logger Handler Formatter
他們的關系請看下圖.
Formatter 可以綁定給 Handler, Handler 可以綁定給Logger
如圖上所示, Logger1 擁有 Handler1與Handler2的處理配置, 還擁有 Formatter 的格式配置. Logger2 擁有 Handler2與Handler3 的處理配置, 還擁有 Formatter 的格式配置.
那我們現在來看一下每個類到底都有什么功能.
Logger
1 Logger.propagate 2 若為True, 日志信息除了傳遞給該logger的handler之外, 也被傳遞給上游logger的handler, 不會考慮上游logger的級別與filter限制 3 若為False, 日志信息不會傳遞給上游logger的handler 4 構造函數設置該屬性為True 5 6 Logger.setLevel(lvl) 7 設置該logger級別為lvl. 低于lvl的日志信息將被忽略. 8 當創建一個根logger時, 默認級別為WARNING 9 當創建一個非根logger時, 默認級別為NOTSET 10 11 Logger.isEnabledFor(lvl) 12 表明lvl級別的信息是否會被該logger處理. 該方法首先檢查由logging.disable(lvl)設置的模塊級的級別, 然后檢查由getEffective()決定的該logger的有效級別. 13 判斷這個級別的信息是否會被處理. 14 15 Logger.getEffectiveLevel() 16 獲取該logger處理信息的級別 17 18 Logger.getChild(suffix) 19 20 Logger.debug(msg, *args, **kwargs) 21 給該logger記錄一條級別為 DEBUG 的信息, msg為消息格式字符串,args為通過字符串格式操作符合并到msg的參數。(注意這意味著可以在格式字符串中使用關鍵字和一個字典參數。) 22 23 kwargs中有兩個關鍵字參數會被檢查:第一個是exc_info,如果它不為false,異常信息會被添加到日志消息。如果有提供異常元組(格式為sys.exc_info()返回值的格式),使用該元組;否則調用sys.exc_info()來得到異常信息。 24 第二個檢查的關鍵字參數是extra,可以給它傳遞一個字典,用來填充LogRecord的__dict__,LogRecord用以表示日志事件,且有自定義屬性。你可以隨意使用這些自定義屬性。例如,它們可以合并到日志消息中。示例: 25 26 FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s' 27 logging.basicConfig(format=FORMAT) 28 d = {'clientip': '192.168.0.1', 'user': 'fbloggs'} 29 logger = logging.getLogger('tcpserver') 30 logger.warning('Protocol problem: %s', 'connection reset', extra=d) 31 將會打印 32 2006-02-08 22:20:02,165 192.168.0.1 fbloggs Protocol problem: connection reset 33 34 extra的字典的鍵不應該與日志系統使用的鍵沖突。(參見Formatter文檔了解日志系統所用鍵的信息。) 35 如果決定要在日志消息中使用這些屬性,使用時要小心。拿上面的例子,Formatter的格式字符串期待LogRecord的屬性字典中有'clientip'和'user'。如果缺失的話,該消息就不會被記錄,因為會發生字符串格式異常。在這種情況下,你總是要傳遞帶這些鍵的extra字典。 36 這可能有些麻煩,它主要在一些特定的環境下使用。如有一個多線程服務器,相同的代碼會在許多上下文執行,而感興趣的條件在上下文才會出現(如上例中的遠端客戶端IP地址和已認證用戶名)。在這種環境下,很可能對特殊的Handler使用特定的Formatter。 37 38 Logger.info(msg, *args, **kwargs) 39 給該logger記錄一條級別為 INFO 的信息 40 41 Logger.warning(msg, *args, **kwargs) 42 給該logger記錄一條級別為 WARNING 的信息 43 44 Logger.error(msg, *args, **kwargs) 45 給該logger記錄一條級別為 ERROR 的信息 46 47 Logger.critical(msg, *args, **kwargs) 48 給該logger記錄一條級別為 CRITICAL 的信息 49 50 Logger.log(lvl, msg, *args, **kwargs) 51 給該logger記錄一條級別為 lvl 的信息。 52 53 Logger.exception(msg, *args, **kwargs) 54 給該logger記錄一條級別為 ERROR 的信息。異常信息將添加到日志信息中。該方法應該只在異常處理器調用。 55 56 Logger.addFilter(filt) 57 添加指定的filter filt 到該logger。 58 59 Logger.removeFilter(filt) 60 刪除該logger中的filter filt。 61 62 Logger.filter(record) 63 對record應用該logger的filters,如果該record應該被處理,返回真。輪流調用filters,直到有一個返回假。如果沒有filter返回假值,該record將會被處理(傳遞給handlers)。如果有一個返回了假值,將不會對record做進一步的處理。 64 65 Logger.addHandler(hdlr) 66 將指定的handlerhdlr添加到logger中。 67 68 Logger.removeHandler(hdlr) 69 從logger中移除指定的handler hdlr。 70 71 Logger.findCaller(stack_info=False) 72 查找調用者的源碼文件名和行號。以3元組的形式返回文件名,行號和函數名。 73 2.4版本中的變動: 函數名被加入進來。在早期版本中,以2元組形式返回文件名和行號。 74 75 Logger.handle(record) 76 處理一個record,將它傳給該logger及其祖先的所有的handler(直到propagate為假為止)。該方法用于從套接字接收到的反序列化的record,以及那些本地創建的。使用filter()日志級別過濾會應用。 77 78 Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None) 79 這是一個工廠方法,可以在子類中覆蓋它來創建特定的LogRecord實例。 80 版本2.5中的改變:添加func 和extra 參數。 81 82 Logger.hasHandlers() 83 檢查是否此日志記錄器已配置的任何處理程序。這是通過尋找此日志記錄器中的處理程序和其父母記錄器層次結構中。如果處理程序被發現,否則錯誤將返回 True。方法停止搜索層次結構中向上,每當與 '傳播' 屬性設置為 false 的記錄器發現 — — 這將是最后一個記錄器,檢查存在的處理程序。 84 3.2 版中的新增功能。
?
Handlers
Handlers是個基類, 在他下面有很多子類來實現了各種handlers的配置方向
StreamHandler | 流Handler |
FileHandler | 文件Handler |
NullHandler | 空Handler |
WatchedFileHandler | 守衛文件Handler |
BaseRotatingHandler | 基本輪詢Handler |
RotatingFileHandler | 輪詢文件Handler |
TimedRotatingFileHandler | 時間輪詢文件Handler |
SocketHandler | Socket Handler |
DatagramHandler | 數據報Handler |
SysLogHandler | 系統日志Handler |
NTEventLogHandler | Windows事件日志Handler |
SMTPHandler | SMTP協議Handler |
MemoryHandler | 內存Handler |
HTTPHandler | HTTP協議Handler |
QueueHandler | 隊列Handler |
QueueListener | 隊列監聽器 |
# 每個Handler具體使用方法, 請參考:?http://python.usyiyi.cn/translate/python_278/library/logging.handlers.html#module-logging.handlers
# logging模塊中文文檔:?http://python.usyiyi.cn/python_278/library/logging.html
# 待整理文檔內容到博客中.
?
按天分割日志, 并保留最近七天的配置:?
1 # /usr/bin/env python 2 # -*- coding: utf-8 -*- 3 # @Author: kys1230 4 # @Email: kys1230@126.com 5 # @Date: 2017-02-22 14:36:25 6 7 8 import logging 9 import logging.handlers 10 11 filename = "access.log" 12 13 # 創建logger對象, 設置logger的日志級別 14 acc_log = logging.getLogger("access") 15 acc_log.setLevel(logging.INFO) 16 17 # 創建文件Handler 18 fh = logging.handlers.TimedRotatingFileHandler(filename, when='D', interval=1, backupCount=7) 19 20 # 創建格式 21 fmt = logging.Formatter("%(asctime)s - %(name)s %(filename)s:%(funcName)s:%(lineno)d %(levelname)s %(message)s") 22 23 # 將格式綁定到Handler 24 fh.setFormatter(fmt) 25 26 # 將Handler綁定到Logger 27 acc_log.addHandler(fh) 28 29 # 使用Logger 30 acc_log.debug("debug") 31 acc_log.info("info") 32 acc_log.warning("warning") 33 acc_log.error("error") 34 acc_log.critical("critical")
?
四. 常用模塊 - re
下圖列出了Python支持的正則表達式元字符和語法:?
數量詞的貪婪模式與非貪婪模式
正則表達式通常用于在文本中查找匹配的字符串. Python里數量詞默認是貪婪的(在少數語言里也可能是默認非貪婪), 總是嘗試匹配盡可能多的字符;非貪婪的則相反, 總是嘗試匹配盡可能少的字符. 例如: 正則表達式"ab*"如果用于查找"abbbc", 將找到"abbb". 而如果使用非貪婪的數量詞"ab*?", 將找到"a".
反斜杠的困擾
與大多數編程語言相同, 正則表達式里使用"\"作為轉義字符, 這就可能造成反斜杠困擾. 假如你需要匹配文本中的字符"\", 那么使用編程語言表示的正則表達式里將需要4個反斜杠"\\\\": 前兩個和后兩個分別用于在編程語言里轉義成反斜杠, 轉換成兩個反斜杠后再在正則表達式里轉義成一個反斜杠. Python里的原生字符串很好地解決了這個問題, 這個例子中的正則表達式可以使用r"\\"表示. 同樣, 匹配一個數字的"\\d"可以寫成r"\d". 有了原生字符串, 你再也不用擔心是不是漏寫了反斜杠, 寫出來的表達式也更直觀.
匹配模式
正則表達式提供了一些可用的匹配模式, 比如忽略大小寫、多行匹配等, 這部分內容將在Pattern類的工廠方法re.compile(pattern[, flags])中一起介紹.
?
re模塊方法
re.compile(pattern, flags=0) ?#?將字符串形式的正則表達式編譯為 Pattern對象
- strPattern ?字符串形式的正則表達式
- flag ?匹配模式, 可以使用'|'表示同時生效, 比如re.I | re.M.
1 prog = re.compile(pattern) 2 result = prog.match(string) 3 # 上面用法等價于下面的用法, 區別在于可以將正則表達式的規則保存到對象中, 以便之后重復使用. 4 result = re.match(pattern, string)
Flags:
- re.A & re.ASCII ?# 待更新
- re.DEBUG ? # 顯示調試信息
- re.I & re.IGNORECASE ?# 忽略大小寫進行匹配
- re.L & re.LOCALE ?# 待更新
- re.M & re.MULTILINE # 多好模式, 自行測試
- re.S & re.DOTALL # 默認. 是不匹配換行符的, 如果加上 re.S 那么. 會匹配換行符
- re.X & re.VERBOSE # 詳細模式. 這個模式下正則表達式可以是多行, 忽略空白字符, 并可以加入注釋


1 a = re.compile(r"""\d + # the integral part 2 \. # the decimal point 3 \d * # some fractional digits""", re.X) 4 b = re.compile(r"\d+\.\d*")
re.search(pattern, string, flags=0) ?# 從頭開始將內容與pattern進行匹配, 如果匹配則返回一個 匹配對象, 如果匹配不到, 最終返回None
re.match(pattern, string, flags=0)? # match 相當于 search的正則表達式前加了個^, 他僅從數據的開始位置開始匹配.
re.fullmatch(pattern, string, flags=0) ?# 將string與pattern進行匹配, 如果完全匹配則返回 匹配對象, 否則 返回None, 這個方法是3.4中新增加的.


1 pattern = "o[gh]" 2 print(re.fullmatch(pattern, "dog")) # 返回None,沒有og|oh開頭 3 print(re.fullmatch(pattern, "ohr")) # 返回None,不是整串完全匹配,雖然有Oh開頭,但是還包含字母r 4 print(re.fullmatch(pattern, "og")) # 返回og,完全匹配
re.split(pattern, string, maxsplit=0, flags=0) ? # str.split只能按照某個分隔符分割, re.split 可以按照正則規則分割. 在3.1版本后 添加了flags參數
- maxsplit ?最大分割次數
re.findall(pattern, string, flags=0)? # 獲取全部的匹配字符,返回一個所有匹配字符串的列表
re.finditer(pattern, string, flags=0)? # findall類似,只是 finditer 返回的是一個迭代器


1 import re 2 data = "My name is Kys1230" 3 for i in re.finditer("\w+", data): 4 print(i.group()) 5 # 執行結果 6 My 7 name 8 is 9 Kys1230
re.sub(pattern, repl, string, count=0, flags=0)? # 將正則表達式匹配的字符串替換為新字符串
- repl ?新字符串 或 函數地址
- count ?替換幾次, 0為不限制次數


1 >>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', 2 ... r'static PyObject*\npy_\1(void)\n{', 3 ... 'def myfunc():') 4 'static PyObject*\npy_myfunc(void)\n{'
如果repl是個函數, 會將正則匹配到的字符串逐一傳遞給函數執行, 將函數的返回值加入到結果中. 例如:


1 >>> def dashrepl(matchobj): 2 ... if matchobj.group(0) == '-': return ' ' 3 ... else: return '-' 4 >>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 5 'pro--gram files'
re.subn(pattern, repl, string, count=0, flags=0)? # 與re.sub類似, 返回的是元組(新字符串, 替換的次數)
re.escape(string)? # 用于將string中的正則表達式元字符如 * + ? 等之前加上轉義符再返回, 在需要大量匹配元字符時有那么一點用. 3.3版本后 "_" 不再進行轉移
re.purge()? # 清空緩存中的正則表達式
?
正則表達式對象的 方法 與 屬性:
regex.search(string[, pos[, endpos]])? # 從字符串string的開始位置pos開始匹配正則表達式, 到位置endpos結束匹配. 匹配成功返回 match對象, 否則返回None
- pos 從字符串string的開始位置pos開始匹配正則表達式
- endpos 到位置endpos結束匹配


1 >>> pattern = re.compile("d") 2 >>> pattern.search("dog") # Match at index 0 3 <_sre.SRE_Match object; span=(0, 1), match='d'> 4 >>> pattern.search("dog", 1) # No match; search doesn't include the "d"
regex.match(string[, pos[, endpos]]) ?# 指定從字符串string頭部或者指定位置的頭部匹配


1 >>> pattern = re.compile("o") 2 >>> pattern.match("dog") # No match as "o" is not at the start of "dog". 3 >>> pattern.match("dog", 1) # Match as "o" is the 2nd character of "dog". 4 <_sre.SRE_Match object; span=(1, 2), match='o'>
regex.fullmatch(string[, pos[, endpos]]) ?# 當整個string與正則表達式匹配時返回match對象, 否則返回None, 3.4版本中新增方法


1 >>> pattern = re.compile("o[gh]") 2 >>> pattern.fullmatch("dog") # No match as "o" is not at the start of "dog". 3 >>> pattern.fullmatch("ogre") # No match as not the full string matches. 4 >>> pattern.fullmatch("doggie", 1, 3) # Matches within given limits. 5 <_sre.SRE_Match object; span=(1, 3), match='og'>
regex.split(string, maxsplit=0) ?# 本方法與re.split()一樣
regex.findall(string[, pos[, endpos]]) ?# 與re.findall()一樣, 本方法接收參數pos與endpos參數, 可以指定開始位置和結束位置
regex.finditer(string[, pos[, endpos]]) ?# 與re.finditer()一樣, 本方法接收參數pos與endpos參數, 可以指定開始位置和結束位置
regex.sub(repl, string, count=0) ?# 與re.sub()一樣
regex.subn(repl, string, count=0) ?# 與re.subn()一樣
regex.flags ? # 待更新


The regex matching flags. This is a combination of the flags given to compile(), any (?...) inline flags in the pattern, and implicit flags such as UNICODE if the pattern is a Unicode string.
regex.groups ? # 正則表達式匹配分組的數量


pattern = re.compile('(?P<style>[^|]*)\|(?P<tags>[^|]*)') print(pattern.findall('OL|AAAAA')) print(pattern.groups) # 結果輸出如下: [('OL', 'AAAAA')] 2
regex.groupindex ?# 返回分組的名稱和序號, 以字典方式返回. 如果沒有返回空字典


pattern = re.compile('(?P<style>[^|]*)\|(?P<tags>[^|]*)') print(pattern.findall('OL|AAAAA')) print(pattern.groupindex) # 結果輸出如下: [('OL', 'AAAAA')] {'style': 1, 'tags': 2}
regex.pattern ?# 已經編譯的正則表達式的字符串


pattern = re.compile('(?P<style>[^|]*)\|(?P<tags>[^|]*)') print(pattern.findall('OL|AAAAA')) print(pattern.pattern) # 結果輸出如下: regex.pattern [('OL', 'AAAAA')] (?P<style>[^|]*)\|(?P<tags>[^|]*)
?
Match(匹配)對象
match對象 是通過正則表達式匹配成功之后返回的對象, 如果不成功也會返回, 不過其布爾值為False. 因此, 判斷是否匹配成功, 只要判斷match對象的布爾值就可以, 簡單的就是使用if語句來判斷.


match = re.search(pattern, string) if match:process(match)
match對象支持下面的方法和屬性:
match.expand(template)? # 在模板字符串template中指定位置替換為指定分組的內容, 可能過索引(\1,\2)或組名稱(\g<1>, \g<name>)來引用.


pattern = re.compile('(?P<style>[^|]*)\|(?P<tags>[^|]*)') match = pattern.match('OL|AAAAA') print(pattern.groups) print(pattern.groupindex) print(match.expand(r'這是一個測試\2, 沒錯')) # 輸出結果如下: 2 {'style': 1, 'tags': 2} 這是一個測試AAAAA, 沒錯
match.group([group1, ...]) ?#?返回分組中子分組的結果. 如果只有一個參數, 當作一個字符串返回. 如果有多個參數, 使用元組返回. 如果沒有參數輸入, 默認返回第一組的結果. 組號的范圍在[1, 99]之間. 如果輸入組號為負數, 或者大于匹配的分組最大值, 就拋出IndexError異常.


>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist") >>> m.group(0) # The entire match 'Isaac Newton' >>> m.group(1) # The first parenthesized subgroup. 'Isaac' >>> m.group(2) # The second parenthesized subgroup. 'Newton' >>> m.group(1, 2) # Multiple arguments give us a tuple. ('Isaac', 'Newton')>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.group('first_name') 'Malcolm' >>> m.group('last_name') 'Reynolds' >>> m.group(1) 'Malcolm' >>> m.group(2) 'Reynolds'>>> m = re.match(r"(..)+", "a1b2c3") # Matches 3 times. >>> m.group(1) # Returns only the last match. 'c3'
match.groups(default=None) ?# 使用元組返回所有匹配的分組, 如果有分組沒有匹配, 就返回None. 如果有設置參數, 就會使用參數來替換相應沒有匹配到的分組.


>>> m = re.match(r"(\d+)\.(\d+)", "24.1632") >>> m.groups() ('24', '1632')>>> m = re.match(r"(\d+)\.?(\d+)?", "24") >>> m.groups() # Second group defaults to None. ('24', None) >>> m.groups('0') # Now, the second group defaults to '0'. ('24', '0')
match.groupdict(default=None) ?# 以字典的方式返回分組命名的匹配結果. 如果沒有匹配成的分組, 以參數替換, 如果沒有參數, 就默認為None替換.


>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.groupdict() {'first_name': 'Malcolm', 'last_name': 'Reynolds'}
match.start([group])
match.end([group]) ?#?返回匹配組的開始位置和結束位置. 參數是group組號, 默認為0, 就所有組都返回.


>>> email = "tony@tiremove_thisger.net" >>> m = re.search("remove_this", email) >>> email[:m.start()] + email[m.end():] 'tony@tiger.net'
match.span([group]) ?# 返回匹配對象組的開始位置和結束位置(m.start(group), m.end(group)), 格式是元組方式. 如果沒有匹配任何組返回(-1, -1).
match.pos
match.endpos? # 在search和match里使用開始位置和結束位置.
match.lastindex? # 保存最后分組的值. 如果沒有組, 返回None.
match.lastgroup ?# 待更新


The name of the last matched capturing group, or None if the group didn’t have a name, or if no group was matched at all.
match.re ? # 在search和match中使用的正則表達式對象.
match.string ? # 傳給search或match進行匹配的字符串.
?
五. 常用模塊 - requests
# 待更新
六. 常用模塊 - paramiko
# 待更新