hashlib加密
hashlib主要提供字元加密功能,将md5和sha子產品整合到了一起,支援md5,sha1, sha224, sha256, sha384, sha512等算法
具體應用



#!/usr/bin/env python#-*- coding: UTF-8 -*-#pyversion:python3.5#owner:fuzj
importhashlib
######### md5 ########
string = "beyongjie"md5 =hashlib.md5()
md5.update(string.encode('utf-8')) #注意轉碼
res =md5.hexdigest()
print("md5加密結果:",res)
######### sha1 ########
sha1 =hashlib.sha1()
sha1.update(string.encode('utf-8'))
res =sha1.hexdigest()
print("sha1加密結果:",res)
######### sha256 ########
sha256 =hashlib.sha256()
sha256.update(string.encode('utf-8'))
res =sha256.hexdigest()
print("sha256加密結果:",res)
######### sha384 ########
sha384 =hashlib.sha384()
sha384.update(string.encode('utf-8'))
res =sha384.hexdigest()
print("sha384加密結果:",res)
######### sha512 ########
sha512=hashlib.sha512()
sha512.update(string.encode('utf-8'))
res =sha512.hexdigest()
print("sha512加密結果:",res)



輸出結果:



md5加密結果: 0e725e477851ff4076f774dc312d4748
sha1加密結果: 458d32be8ea38b66300174970ab0a8c0b734252f
sha256加密結果: 1e62b55bfd02977943f885f6a0998af7cc9cfb95c8ac4a9f30ecccb7c05ec9f4
sha384加密結果: e91cdf0d2570de5c96ee84e8a12cddf16508685e7a03b3e811099cfcd54b7f52183e20197cff7c07f312157f0ba4875b
sha512加密結果: 3f0020a726e9c1cb5d22290c967f3dd1bcecb409a51a8088db520750c876aaec3f17a70d7981cd575ed4b89471f743f3f24a146a39d59f215ae3e208d0170073



注意:hashlib 加密啊的字元串類型為二進制編碼,直接加密字元串會報如下錯誤:



sha1 =hashlib.sha1()
sha1.update(string)
res =sha1.hexdigest()
print("sha1加密結果:",res)
TypeError: Unicode-objects must be encoded before hashing



可以使用encode進行轉換
shaa1 =hashlib.sha1()
shaa1.update(string.encode('utf-8'))
res =shaa1.hexdigest()
print("sha1采用encode轉換加密結果:",res)
或者使用byte轉換為二進制
shab1 =hashlib.sha1()
shab1.update(bytes(string,encoding='utf-8'))
res =shab1.hexdigest()
print("sha1采用byte轉換的結果:",res)
以上輸出:
sha1采用encode轉換加密結果: 458d32be8ea38b66300174970ab0a8c0b734252f
sha1采用byte轉換的結果: 458d32be8ea38b66300174970ab0a8c0b734252f
常用方法
hash.update(arg) 更新哈希對象以字元串參數, 注意:如果同一個hash對象重複調用該方法,則m.update(a); m.update(b) 等效于 m.update(a+b),看下面例子



m =hashlib.md5()
m.update('a'.encode('utf-8'))
res =m.hexdigest()
print("第一次a加密:",res)
m.update('b'.encode('utf-8'))
res =m.hexdigest()
print("第二次b加密:",res)
m1 =hashlib.md5()
m1.update('b'.encode('utf-8'))
res =m1.hexdigest()
print("b單獨加密:",res)
m2 =hashlib.md5()
m2.update('ab'.encode('utf-8'))
res =m2.hexdigest()
print("ab單獨加密:",res)
輸出結果:
第一次a加密: 0cc175b9c0f1b6a831c399e269772661
第二次b加密: 187ef4436122d1cc2f40dc2b92f0eba0
b單獨加密: 92eb5ffee6ae2fec3ad71c777531578f
ab單獨加密: 187ef4436122d1cc2f40dc2b92f0eba0



hash.digest() 傳回摘要,作為二進制資料字元串值,
hash.hexdigest() 傳回摘要,作為十六進制資料字元串值,
hash.copy() 複制
進階加密
以上加密算法雖然依然非常厲害,但時候存在缺陷,即:通過撞庫可以反解。是以,有必要對加密算法中添加自定義key再來做加密。



low =hashlib.md5()
low.update('ab'.encode('utf-8'))
res =low.hexdigest()
print("普通加密:",res)
high = hashlib.md5(b'beyondjie')
high.update('ab'.encode('utf-8'))
res =high.hexdigest()
print("采用key加密:",res)
輸出結果:
普通加密: 187ef4436122d1cc2f40dc2b92f0eba0
采用key加密: 1b073f6b8cffe609751e4c98537b7653



附加HMAC-SHA1各語言版本實作

在各大開放平台大行其道的網際網路開發潮流中,調用各平台的API接口過程中,無一例外都會用到計算簽名值(sig值)。而在各種計算簽名的方法中,經常被采用的就是HMAC-SHA1,現對HMAC-SHA1做一個簡單的介紹:
HMAC,散列消息驗證碼,基于密鑰的Hash算法認證協定。實作原理為:利用已經公開的Hash函數和私有的密鑰,來生成固定長度的消息驗證碼;
SHA1、MD5等Hash算法是比較常用的不可逆Hash簽名計算方法;
BASE64,将任意序列的8位元組字元轉換為人眼無法直接識别的符号編碼的一種方法;
各個語言版本的實作為:
Python版:
importhmac
importhashlib
importbase64
hmac.new(Token,data,hashlib.sha1).digest().encode('base64').rstrip()
Token:即接口的key
data:要加密的資料
PHP版:
base64_encode(hash_hmac("SHA1",clientStr,Token , true))
C++版(Openssl):
HMAC( EVP_sha1(),
strKey.data(),
strKey.size(),
(unsigned char*) strRandom.data(),
strRandom.size(), digest, &digest_len))
Shell版:
echo -n '3f88a95c532bea70' | openssl dgst -hmac '123' -sha1 -binary | base64
1 logging子產品簡介
logging子產品是Python内置的标準子產品,主要用于輸出運作日志,可以設定輸出日志的等級、日志儲存路徑、日志檔案復原等;相比print,具備如下優點:
可以通過設定不同的日志等級,在release版本中隻輸出重要資訊,而不必顯示大量的調試資訊;
print将所有資訊都輸出到标準輸出中,嚴重影響開發者從标準輸出中檢視其它資料;logging則可以由開發者決定将資訊輸出到什麼地方,以及怎麼輸出;
2 logging子產品使用
2.1 基本使用
配置logging基本的設定,然後在控制台輸出日志,




import logging
logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")




運作時,控制台輸出,
2016-10-09 19:11:19,434 - __main__ - INFO - Start print log
2016-10-09 19:11:19,434 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:11:19,434 - __main__ - INFO - Finish
logging中可以選擇很多消息級别,如debug、info、warning、error以及critical。通過賦予logger或者handler不同的級别,開發者就可以隻輸出錯誤資訊到特定的記錄檔案,或者在調試時隻記錄調試資訊。
例如,我們将logger的級别改為DEBUG,再觀察一下輸出結果,
logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
控制台輸出,可以發現,輸出了debug的資訊。
2016-10-09 19:12:08,289 - __main__ - INFO - Start print log
2016-10-09 19:12:08,289 - __main__ - DEBUG - Do something
2016-10-09 19:12:08,289 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:12:08,289 - __main__ - INFO - Finish
logging.basicConfig函數各參數:
filename:指定日志檔案名;
filemode:和file函數意義相同,指定日志檔案的打開模式,'w'或者'a';
format:指定輸出的格式和内容,format可以輸出很多有用的資訊,
參數:作用
%(levelno)s:列印日志級别的數值
%(levelname)s:列印日志級别的名稱
%(pathname)s:列印目前執行程式的路徑,其實就是sys.argv[0]
%(filename)s:列印目前執行程式名
%(funcName)s:列印日志的目前函數
%(lineno)d:列印日志的目前行号
%(asctime)s:列印日志的時間
%(thread)d:列印線程ID
%(threadName)s:列印線程名稱
%(process)d:列印程序ID
%(message)s:列印日志資訊
datefmt:指定時間格式,同time.strftime();
level:設定日志級别,預設為logging.WARNNING;
stream:指定将日志的輸出流,可以指定輸出到sys.stderr,sys.stdout或者檔案,預設輸出到sys.stderr,當stream和filename同時指定時,stream被忽略;
2.2 将日志寫入到檔案
2.2.1 将日志寫入到檔案
設定logging,建立一個FileHandler,并對輸出消息的格式進行設定,将其添加到logger,然後将日志寫入到指定的檔案中,




import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")




log.txt中日志資料為,
2016-10-09 19:01:13,263 - __main__ - INFO - Start print log
2016-10-09 19:01:13,263 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:01:13,263 - __main__ - INFO - Finish
2.2.2 将日志同時輸出到螢幕和日志檔案
logger中添加StreamHandler,可以将日志輸出到螢幕上,




import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")




可以在log.txt檔案和控制台中看到,
2016-10-09 19:20:46,553 - __main__ - INFO - Start print log
2016-10-09 19:20:46,553 - __main__ - WARNING - Something maybe fail.
2016-10-09 19:20:46,553 - __main__ - INFO - Finish
可以發現,logging有一個日志處理的主對象,其他處理方式都是通過addHandler添加進去,logging中包含的handler主要有如下幾種,
handler名稱:位置;作用
StreamHandler:logging.StreamHandler;日志輸出到流,可以是sys.stderr,sys.stdout或者檔案
FileHandler:logging.FileHandler;日志輸出到檔案
BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志復原方式
RotatingHandler:logging.handlers.RotatingHandler;日志復原方式,支援日志檔案最大數量和日志檔案復原
TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志復原方式,在一定時間區域内復原日志檔案
SocketHandler:logging.handlers.SocketHandler;遠端輸出日志到TCP/IP sockets
DatagramHandler:logging.handlers.DatagramHandler;遠端輸出日志到UDP sockets
SMTPHandler:logging.handlers.SMTPHandler;遠端輸出日志到郵件位址
SysLogHandler:logging.handlers.SysLogHandler;日志輸出到syslog
NTEventLogHandler:logging.handlers.NTEventLogHandler;遠端輸出日志到Windows NT/2000/XP的事件日志
MemoryHandler:logging.handlers.MemoryHandler;日志輸出到記憶體中的指定buffer
HTTPHandler:logging.handlers.HTTPHandler;通過"GET"或者"POST"遠端輸出到HTTP伺服器
2.2.3 日志復原
使用RotatingFileHandler,可以實作日志復原,




import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
#定義一個RotatingFileHandler,最多備份3個日志檔案,每個日志檔案最大1K
rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3)
rHandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
rHandler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(rHandler)
logger.addHandler(console)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")




可以在工程目錄中看到,備份的日志檔案,
2016/10/09 19:36 732 log.txt
2016/10/09 19:36 967 log.txt.1
2016/10/09 19:36 985 log.txt.2
2016/10/09 19:36 976 log.txt.3
2.3 設定消息的等級
可以設定不同的日志等級,用于控制日志的輸出,
日志等級:使用範圍
FATAL:緻命錯誤
CRITICAL:特别糟糕的事情,如記憶體耗盡、磁盤空間為空,一般很少使用
ERROR:發生錯誤時,如IO操作失敗或者連接配接問題
WARNING:發生很重要的事件,但是并不是錯誤時,如使用者登入密碼錯誤
INFO:處理請求或者狀态變化等日常事務
DEBUG:調試過程中使用DEBUG等級,如算法中每個循環的中間狀态
2.4 捕獲traceback
Python中的traceback子產品被用于跟蹤異常傳回資訊,可以在logging中記錄下traceback,
代碼,




import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
logger.addHandler(handler)
logger.addHandler(console)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
try:
open("sklearn.txt","rb")
except (SystemExit,KeyboardInterrupt):
raise
except Exception:
logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
logger.info("Finish")




控制台和日志檔案log.txt中輸出,
Start print log
Something maybe fail.
Faild to open sklearn.txt from logger.error
Traceback (most recent call last):
File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in
open("sklearn.txt","rb")
IOError: [Errno 2] No such file or directory: 'sklearn.txt'
Finish
也可以使用logger.exception(msg,_args),它等價于logger.error(msg,exc_info = True,_args),
将
logger.error("Faild to open sklearn.txt from logger.error",exc_info = True)
替換為,
logger.exception("Failed to open sklearn.txt from logger.exception")
控制台和日志檔案log.txt中輸出,
Start print log
Something maybe fail.
Failed to open sklearn.txt from logger.exception
Traceback (most recent call last):
File "G:\zhb7627\Code\Eclipse WorkSpace\PythonTest\test.py", line 23, in
open("sklearn.txt","rb")
IOError: [Errno 2] No such file or directory: 'sklearn.txt'
Finish
2.5 多子產品使用logging
主子產品mainModule.py,




import logging
import subModule
logger = logging.getLogger("mainModule")
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("log.txt")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(formatter)
logger.addHandler(handler)
logger.addHandler(console)
logger.info("creating an instance of subModule.subModuleClass")
a = subModule.SubModuleClass()
logger.info("calling subModule.subModuleClass.doSomething")
a.doSomething()
logger.info("done with subModule.subModuleClass.doSomething")
logger.info("calling subModule.some_function")
subModule.som_function()
logger.info("done with subModule.some_function")




子子產品subModule.py,




import logging
module_logger = logging.getLogger("mainModule.sub")
class SubModuleClass(object):
def __init__(self):
self.logger = logging.getLogger("mainModule.sub.module")
self.logger.info("creating an instance in SubModuleClass")
def doSomething(self):
self.logger.info("do something in SubModule")
a = []
a.append(1)
self.logger.debug("list a = " + str(a))
self.logger.info("finish something in SubModuleClass")
def som_function():
module_logger.info("call function some_function")




執行之後,在控制和日志檔案log.txt中輸出,
2016-10-09 20:25:42,276 - mainModule - INFO - creating an instance of subModule.subModuleClass
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - creating an instance in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - do something in SubModule
2016-10-09 20:25:42,279 - mainModule.sub.module - INFO - finish something in SubModuleClass
2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.subModuleClass.doSomething
2016-10-09 20:25:42,279 - mainModule - INFO - calling subModule.some_function
2016-10-09 20:25:42,279 - mainModule.sub - INFO - call function some_function
2016-10-09 20:25:42,279 - mainModule - INFO - done with subModule.some_function
首先在主子產品定義了logger'mainModule',并對它進行了配置,就可以在解釋器程序裡面的其他地方通過getLogger('mainModule')得到的對象都是一樣的,不需要重新配置,可以直接使用。定義的該logger的子logger,都可以共享父logger的定義和配置,所謂的父子logger是通過命名來識别,任意以'mainModule'開頭的logger都是它的子logger,例如'mainModule.sub'。
實際開發一個application,首先可以通過logging配置檔案編寫好這個application所對應的配置,可以生成一個根logger,如'PythonAPP',然後在主函數中通過fileConfig加載logging配置,接着在application的其他地方、不同的子產品中,可以使用根logger的子logger,如'PythonAPP.Core','PythonAPP.Web'來進行log,而不需要反複的定義和配置各個子產品的logger。
3 通過JSON或者YAML檔案配置logging子產品
盡管可以在Python代碼中配置logging,但是這樣并不夠靈活,最好的方法是使用一個配置檔案來配置。在Python 2.7及以後的版本中,可以從字典中加載logging配置,也就意味着可以通過JSON或者YAML檔案加載日志的配置。
3.1 通過JSON檔案配置
JSON配置檔案,
{
"version":1,
"disable_existing_loggers":false,
"formatters":{
"simple":{
"format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
},
"handlers":{
"console":{
"class":"logging.StreamHandler",
"level":"DEBUG",
"formatter":"simple",
"stream":"ext://sys.stdout"
},
"info_file_handler":{
"class":"logging.handlers.RotatingFileHandler",
"level":"INFO",
"formatter":"simple",
"filename":"info.log",
"maxBytes":"10485760",
"backupCount":20,
"encoding":"utf8"
},
"error_file_handler":{
"class":"logging.handlers.RotatingFileHandler",
"level":"ERROR",
"formatter":"simple",
"filename":"errors.log",
"maxBytes":10485760,
"backupCount":20,
"encoding":"utf8"
}
},
"loggers":{
"my_module":{
"level":"ERROR",
"handlers":["info_file_handler"],
"propagate":"no"
}
},
"root":{
"level":"INFO",
"handlers":["console","info_file_handler","error_file_handler"]
}
}
通過JSON加載配置檔案,然後通過logging.dictConfig配置logging,




import json
import logging.config
import os
def setup_logging(default_path = "logging.json",default_level = logging.INFO,env_key = "LOG_CFG"):
path = default_path
value = os.getenv(env_key,None)
if value:
path = value
if os.path.exists(path):
with open(path,"r") as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level = default_level)
def func():
logging.info("start func")
logging.info("exec func")
logging.info("end func")
if __name__ == "__main__":
setup_logging(default_path = "logging.json")
func()




3.2 通過YAML檔案配置
通過YAML檔案進行配置,比JSON看起來更加簡介明了,
version: 1
disable_existing_loggers: False
formatters:
simple:
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: simple
filename: info.log
maxBytes: 10485760
backupCount: 20
encoding: utf8
error_file_handler:
class: logging.handlers.RotatingFileHandler
level: ERROR
formatter: simple
filename: errors.log
maxBytes: 10485760
backupCount: 20
encoding: utf8
loggers:
my_module:
level: ERROR
handlers: [info_file_handler]
propagate: no
root:
level: INFO
handlers: [console,info_file_handler,error_file_handler]
通過YAML加載配置檔案,然後通過logging.dictConfig配置logging,




import yaml
import logging.config
import os
def setup_logging(default_path = "logging.yaml",default_level = logging.INFO,env_key = "LOG_CFG"):
path = default_path
value = os.getenv(env_key,None)
if value:
path = value
if os.path.exists(path):
with open(path,"r") as f:
config = yaml.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level = default_level)
def func():
logging.info("start func")
logging.info("exec func")
logging.info("end func")
if __name__ == "__main__":
setup_logging(default_path = "logging.yaml")
func()




subprocess子產品
subprocess是Python 2.4中新增的一個子產品,它允許你生成新的程序,連接配接到它們的 input/output/error 管道,并擷取它們的傳回(狀态)碼。這個子產品的目的在于替換幾個舊的子產品和方法,如:
os.system
os.spawn*
1. subprocess子產品中的常用函數
函數描述
subprocess.run()
Python 3.5中新增的函數。執行指定的指令,等待指令執行完成後傳回一個包含執行結果的CompletedProcess類的執行個體。
subprocess.call()
執行指定的指令,傳回指令執行狀态,其功能類似于os.system(cmd)。
subprocess.check_call()
Python 2.5中新增的函數。 執行指定的指令,如果執行成功則傳回狀态碼,否則抛出異常。其功能等價于subprocess.run(..., check=True)。
subprocess.check_output()
Python 2.7中新增的的函數。執行指定的指令,如果執行狀态碼為0則傳回指令執行結果,否則抛出異常。
subprocess.getoutput(cmd)
接收字元串格式的指令,執行指令并傳回執行結果,其功能類似于os.popen(cmd).read()和commands.getoutput(cmd)。
subprocess.getstatusoutput(cmd)
執行cmd指令,傳回一個元組(指令執行狀态, 指令執行結果輸出),其功能類似于commands.getstatusoutput()。
說明:
在Python 3.5之後的版本中,官方文檔中提倡通過subprocess.run()函數替代其他函數來使用subproccess子產品的功能;
在Python 3.5之前的版本中,我們可以通過subprocess.call(),subprocess.getoutput()等上面列出的其他函數來使用subprocess子產品的功能;
subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通過對subprocess.Popen的封裝來實作的進階函數,是以如果我們需要更複雜功能時,可以通過subprocess.Popen來完成。
subprocess.getoutput()和subprocess.getstatusoutput()函數是來自Python 2.x的commands子產品的兩個遺留函數。它們隐式的調用系統shell,并且不保證其他函數所具有的安全性和異常處理的一緻性。另外,它們從Python 3.3.4開始才支援Windows平台。
2. 上面各函數的定義及參數說明
函數參數清單:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
subprocess.getstatusoutput(cmd)
subprocess.getoutput(cmd)
參數說明:
args: 要執行的shell指令,預設應該是一個字元串序列,如['df', '-Th']或('df', '-Th'),也可以是一個字元串,如'df -Th',但是此時需要把shell參數的值置為True。
shell: 如果shell為True,那麼指定的指令将通過shell執行。如果我們需要通路某些shell的特性,如管道、檔案名通配符、環境變量擴充功能,這将是非常有用的。當然,python本身也提供了許多類似shell的特性的實作,如glob、fnmatch、os.walk()、os.path.expandvars()、os.expanduser()和shutil等。
check: 如果check參數的值是True,且執行指令的程序以非0狀态碼退出,則會抛出一個CalledProcessError的異常,且該異常對象會包含 參數、退出狀态碼、以及stdout和stderr(如果它們有被捕獲的話)。
stdout, stderr:
run()函數預設不會捕獲指令執行結果的正常輸出和錯誤輸出,如果我們向擷取這些内容需要傳遞subprocess.PIPE,然後可以通過傳回的CompletedProcess類執行個體的stdout和stderr屬性或捕獲相應的内容;
call()和check_call()函數傳回的是指令執行的狀态碼,而不是CompletedProcess類執行個體,是以對于它們而言,stdout和stderr不适合指派為subprocess.PIPE;
check_output()函數預設就會傳回指令執行結果,是以不用設定stdout的值,如果我們希望在結果中捕獲錯誤資訊,可以執行stderr=subprocess.STDOUT。
input: 該參數是傳遞給Popen.communicate(),通常該參數的值必須是一個位元組序列,如果universal_newlines=True,則其值應該是一個字元串。
universal_newlines: 該參數影響的是輸入與輸出的資料格式,比如它的值預設為False,此時stdout和stderr的輸出是位元組序列;當該參數的值設定為True時,stdout和stderr的輸出是字元串。
3. subprocess.CompletedProcess類介紹
需要說明的是,subprocess.run()函數是Python3.5中新增的一個進階函數,其傳回值是一個subprocess.CompletedPorcess類的執行個體,是以,subprocess.completedPorcess類也是Python 3.5中才存在的。它表示的是一個已結束程序的狀态資訊,它所包含的屬性如下:
args: 用于加載該程序的參數,這可能是一個清單或一個字元串
returncode: 子程序的退出狀态碼。通常情況下,退出狀态碼為0則表示程序成功運作了;一個負值-N表示這個子程序被信号N終止了
stdout: 從子程序捕獲的stdout。這通常是一個位元組序列,如果run()函數被調用時指定universal_newlines=True,則該屬性值是一個字元串。如果run()函數被調用時指定stderr=subprocess.STDOUT,那麼stdout和stderr将會被整合到這一個屬性中,且stderr将會為None
stderr: 從子程序捕獲的stderr。它的值與stdout一樣,是一個位元組序列或一個字元串。如果stderr滅有被捕獲的話,它的值就為None
check_returncode(): 如果returncode是一個非0值,則該方法會抛出一個CalledProcessError異常。
4. 執行個體
subprocess.run()
>>> subprocess.run(["ls", "-l"]) # doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
subprocess.call()
>>> subprocess.call(['ls', '-l'])
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> subprocess.call('ls -l', shell=True)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> subprocess.call(['ls', '-l'], stdout=subprocess.DEVNULL)
>>> subprocess.call(['ls', '-l', '/test'])
ls: 無法通路/test: 沒有那個檔案或目錄
2
suprocess.check_call()
>>> subprocess.check_call(['ls', '-l'])
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> subprocess.check_call('ls -l', shell=True)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> subprocess.check_call('ls -l /test', shell=True)
ls: 無法通路/test: 沒有那個檔案或目錄
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/subprocess.py", line 557, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'ls -l /test' returned non-zero exit status 2
sbuprocess.check_output()
>>> ret = subprocess.check_output(['ls', '-l'])
>>> print(ret)
b' \xe5\x85\xac\xe5\x85\xb1\xe7\x9a\x84\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe6\xa8\xa1\xe6\x9d\xbf\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe8\xa7\x86\xe9\xa2\x91\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe5\x9b\xbe\xe7\x89\x87\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe6\x96\x87\xe6\xa1\xa3\ndrwxr-xr-x 2 wader wader 4096 4\xe6\x9c\x88 13 2016 \xe4\xb8\x8b\xe8\xbd\xbd\ndrwxr-xr-x 2 wader wader 4096 12\xe6\x9c\x88 7 2015 \xe9\x9f\xb3\xe4\xb9\x90\ndrwxr-xr-x 7 wader wader 4096 5\xe6\x9c\x88 26 2016 \xe6\xa1\x8c\xe9\x9d\xa2\n'
>>> ret = subprocess.check_output(['ls', '-l'], universal_newlines=True)
>>> print(ret)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
subprocess.getoutput()與subprocess.getstatusoutput()
>>> ret = subprocess.getoutput('ls -l')
>>> print(ret)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> retcode, output = subprocess.getstatusoutput('ls -l')
>>> print(retcode)
>>> print(output)
總用量 160
drwxr-xr-x 2 wader wader 4096 12月 7 2015 公共的
drwxr-xr-x 2 wader wader 4096 12月 7 2015 模闆
drwxr-xr-x 2 wader wader 4096 12月 7 2015 視訊
drwxr-xr-x 2 wader wader 4096 12月 7 2015 圖檔
drwxr-xr-x 2 wader wader 4096 12月 7 2015 文檔
drwxr-xr-x 2 wader wader 4096 4月 13 2016 下載下傳
drwxr-xr-x 2 wader wader 4096 12月 7 2015 音樂
drwxr-xr-x 7 wader wader 4096 5月 26 2016 桌面
>>> retcode, output = subprocess.getstatusoutput('ls -l /test')
>>> print(retcode)
2
>>> print(output)
ls: 無法通路/test: 沒有那個檔案或目錄
三、subprocess.Popen介紹
該類用于在一個新的程序中執行一個子程式。前面我們提到過,上面介紹的這些函數都是基于subprocess.Popen類實作的,通過使用這些被封裝後的進階函數可以很方面的完成一些常見的需求。由于subprocess子產品底層的程序建立和管理是由Popen類來處理的,是以,當我們無法通過上面哪些進階函數來實作一些不太常見的功能時就可以通過subprocess.Popen類提供的靈活的api來完成。
1.subprocess.Popen的構造函數
class subprocess.Popen(args,bufsize=-1,executable=None,stdin=None,stdout=None,stderr=None,preexec_fn=None,close_fds=True,shell=False,cwd=None,env=None,universal_newlines=False,startup_info=None,creationflags=0,restore_signals=True,start_new_session=False,pass_fds=())
參數說明:
args: 要執行的shell指令,可以是字元串,也可以是指令各個參數組成的序列。當該參數的值是一個字元串時,該指令的解釋過程是與平台相關的,是以通常建議将args參數作為一個序列傳遞。
bufsize: 指定緩存政策,0表示不緩沖,1表示行緩沖,其他大于1的數字表示緩沖區大小,負數 表示使用系統預設緩沖政策。
stdin, stdout, stderr: 分别表示程式标準輸入、輸出、錯誤句柄。
preexec_fn: 用于指定一個将在子程序運作之前被調用的可執行對象,隻在Unix平台下有效。
close_fds: 如果該參數的值為True,則除了0,1和2之外的所有檔案描述符都将會在子程序執行之前被關閉。
shell: 該參數用于辨別是否使用shell作為要執行的程式,如果shell值為True,則建議将args參數作為一個字元串傳遞而不要作為一個序列傳遞。
cwd: 如果該參數值不是None,則該函數将會在執行這個子程序之前改變目前工作目錄。
env: 用于指定子程序的環境變量,如果env=None,那麼子程序的環境變量将從父程序中繼承。如果env!=None,它的值必須是一個映射對象。
universal_newlines: 如果該參數值為True,則該檔案對象的stdin,stdout和stderr将會作為文本流被打開,否則他們将會被作為二進制流被打開。
startupinfo和creationflags: 這兩個參數隻在Windows下有效,它們将被傳遞給底層的CreateProcess()函數,用于設定子程序的一些屬性,如主視窗的外觀,程序優先級等。
2. subprocess.Popen類的執行個體可調用的方法
方法描述
Popen.poll()
用于檢查子程序(指令)是否已經執行結束,沒結束傳回None,結束後傳回狀态碼。
Popen.wait(timeout=None)
等待子程序結束,并傳回狀态碼;如果在timeout指定的秒數之後程序還沒有結束,将會抛出一個TimeoutExpired異常。
Popen.communicate(input=None, timeout=None)
該方法可用來與程序進行互動,比如發送資料到stdin,從stdout和stderr讀取資料,直到到達檔案末尾。
Popen.send_signal(signal)
發送指定的信号給這個子程序。
Popen.terminate()
停止該子程序。
Popen.kill()
殺死該子程序。
關于communicate()方法的說明:
該方法中的可選參數 input 應該是将被發送給子程序的資料,或者如沒有資料發送給子程序,該參數應該是None。input參數的資料類型必須是位元組串,如果universal_newlines參數值為True,則input參數的資料類型必須是字元串。
該方法傳回一個元組(stdout_data, stderr_data),這些資料将會是位元組穿或字元串(如果universal_newlines的值為True)。
如果在timeout指定的秒數後該程序還沒有結束,将會抛出一個TimeoutExpired異常。捕獲這個異常,然後重新嘗試通信不會丢失任何輸出的資料。但是逾時之後子程序并沒有被殺死,為了合理的清除相應的内容,一個好的應用應該手動殺死這個子程序來結束通信。
需要注意的是,這裡讀取的資料是緩沖在記憶體中的,是以,如果資料大小非常大或者是無限的,就不應該使用這個方法。
3. subprocess.Popen使用執行個體
執行個體1:
>>> import subprocess
>>>
>>> p = subprocess.Popen('df -Th', stdout=subprocess.PIPE, shell=True)>>> print(p.stdout.read())
Filesystem Type Size Used Avail Use% Mounted on
/dev/vda1 ext4 40G 12G 26G 31% /
devtmpfs devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs tmpfs 3.9G 386M 3.5G 10% /runtmpfs tmpfs3.9G03.9G0% /sys/fs/cgrouptmpfs tmpfs 783M 0 783M 0% /run/user/0tmpfs tmpfs 783M 0 783M 0% /run/user/1000
執行個體2:
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> obj.stdin.write('print(1) \n')
>>> obj.stdin.write('print(2) \n')
>>> obj.stdin.write('print(3) \n')
>>> out,err = obj.communicate()
>>> print(out)
1
2
3
>>> print(err)
執行個體3:
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> out,err = obj.communicate(input='print(1) \n')
>>> print(out)
1
>>> print(err)
執行個體4:
實作類似df -Th | grep data指令的功能,實際上就是實作shell中管道的共功能。
>>>
>>>p1 = subprocess.Popen(['df', '-Th'], stdout=subprocess.PIPE)
>>>p2 = subprocess.Popen(['grep', 'data'], stdin=p1.stdout, stdout=subprocess.PIPE)
>>>out,err = p2.communicate()
>>>print(out)
/dev/vdb1 ext4 493G 4.8G 463G 2% /data
/dev/vdd1 ext4 1008G 420G 537G 44% /data1
/dev/vde1 ext4 985G 503G 432G 54% /data2
>>>print(err)
None
四、總結
那麼我們到底該用哪個子產品、哪個函數來執行指令與系統及系統進行互動呢?下面我們來做個總結:
首先應該知道的是,Python2.4版本引入了subprocess子產品用來替換os.system()、os.popen()、os.spawn*()等函數以及commands子產品;也就是說如果你使用的是Python 2.4及以上的版本就應該使用subprocess子產品了。
如果你的應用使用的Python 2.4以上,但是是Python 3.5以下的版本,Python官方給出的建議是使用subprocess.call()函數。Python 2.5中新增了一個subprocess.check_call()函數,Python 2.7中新增了一個subprocess.check_output()函數,這兩個函數也可以按照需求進行使用。
如果你的應用使用的是Python 3.5及以上的版本(目前應該還很少),Python官方給出的建議是盡量使用subprocess.run()函數。
當subprocess.call()、subprocess.check_call()、subprocess.check_output()和subprocess.run()這些進階函數無法滿足需求時,我們可以使用subprocess.Popen類來實作我們需要的複雜功能。
json ,pickle子產品
JSON(JavaScript Object Notation, JS 對象标記) 是一種輕量級的資料交換格式。JSON的資料格式其實就是python裡面的字典格式,裡面可以包含方括号括起來的數組,也就是python裡面的清單。
在python中,有專門處理json格式的子產品—— json 和 picle子產品
Json 子產品提供了四個方法: dumps、dump、loads、load
pickle 子產品也提供了四個功能:dumps、dump、loads、load
一. dumps 和 dump:
dumps和dump 序列化方法
dumps隻完成了序列化為str,
dump必須傳檔案描述符,将序列化的str儲存到檔案中
檢視源碼:
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
#Serialize ``obj`` to a JSON formatted ``str``.
#序列号 “obj” 資料類型 轉換為 JSON格式的字元串

def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
default=None, sort_keys=False, **kw):
"""Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
``.write()``-supporting file-like object).
我了解為兩個動作,一個動作是将”obj“轉換為JSON格式的字元串,還有一個動作是将字元串寫入到檔案中,也就是說檔案描述符fp是必須要的參數 """

示例代碼:



>>> importjson
>>> json.dumps([]) #dumps可以格式化所有的基本資料類型為字元串
'[]'
>>> json.dumps(1) #數字
'1'
>>> json.dumps('1') #字元串
'"1"'
>>> dict = {"name":"Tom", "age":23}
>>> json.dumps(dict) #字典
'{"name": "Tom", "age": 23}'



a = {"name":"Tom", "age":23}
with open("test.json", "w", encoding='utf-8') as f:
#indent 超級好用,格式化儲存字典,預設為None,小于0為零個空格
f.write(json.dumps(a, indent=4))
#json.dump(a,f,indent=4) # 和上面的效果一樣
儲存的檔案效果:
二. loads 和 load
loads和load 反序列化方法
loads 隻完成了反序列化,
load 隻接收檔案描述符,完成了讀取檔案和反序列化
檢視源碼:
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
"""Deserialize ``s`` (a ``str`` instance containing a JSON document) to a Python object.
将包含str類型的JSON文檔反序列化為一個python對象"""
def load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
"""Deserialize ``fp`` (a ``.read()``-supporting file-like object containing a JSON document) to a Python object.
将一個包含JSON格式資料的可讀檔案飯序列化為一個python對象"""
執行個體:
>>> json.loads('{"name":"Tom", "age":23}')
{'age': 23, 'name': 'Tom'}



importjson
with open("test.json", "r", encoding='utf-8') as f:
aa =json.loads(f.read())
f.seek(0)
bb = json.load(f) #與 json.loads(f.read())
print(aa)
print(bb)
#輸出:
{'name': 'Tom', 'age': 23}
{'name': 'Tom', 'age': 23}



三. json 和 pickle 子產品
json子產品和pickle子產品都有 dumps、dump、loads、load四種方法,而且用法一樣。
不用的是json子產品序列化出來的是通用格式,其它程式設計語言都認識,就是普通的字元串,
而picle子產品序列化出來的隻有python可以認識,其他程式設計語言不認識的,表現為亂碼
不過picle可以序列化函數,但是其他檔案想用該函數,在該檔案中需要有該檔案的定義(定義和參數必須相同,内容可以不同)
四. python對象(obj) 與json對象的對應關系



+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+



五. 總結
1. json序列化方法:
dumps:無檔案操作 dump:序列化+寫入檔案
2. json反序列化方法:
loads:無檔案操作 load: 讀檔案+反序列化
3. json子產品序列化的資料 更通用
picle子產品序列化的資料 僅python可用,但功能強大,可以序列号函數
4. json子產品可以序列化和反序列化的 資料類型 見 python對象(obj) 與json對象的對應關系表
5. 格式化寫入檔案利用 indent = 4
ElementTree是python的XML處理子產品
ElementTree是python的XML處理子產品,它提供了一個輕量級的對象模型。它在Python2.5以後成為Python标準庫的一部分,但是Python2.4之前需要單獨安裝。在使用ElementTree子產品時,需要import xml.etree.ElementTree的操作。
ElementTree表示整個XML節點樹,而Element表示節點數中的一個單獨的節點。
建構
ElementTree(tag),其中tag表示根節點,初始化一個ElementTree對象。
Element(tag, attrib={}, **extra)函數用來構造XML的一個根節點,其中tag表示根節點的名稱,attrib是一個可選項,表示節點的屬性。
SubElement(parent, tag, attrib={}, **extra)用來構造一個已經存在的節點的子節點
Element.text和SubElement.text表示element對象的額外的内容屬性,Element.tag和Element.attrib分别表示element對象的标簽和屬性。
ElementTree.write(file, encoding='us-ascii', xml_declaration=None,
default_namespace=None, method='xml'),函數建立一個XML檔案,并且将節點數資料寫入XML檔案中。
#encoding=utf-8
import xml.etree.ElementTree as ET
#建立xml檔案
def buildNewsXmlFile():
#設定一個新節點,并設定其标簽為root
root = ET.Element("root")
#在root下建立兩個子節點,設定其名稱分别為sina和chinabyte
sina = ET.SubElement(root, "sina")
chinabyte = ET.SubElement(root, "chinabyte")
#在sina下建立兩個子節點,設定其節點名稱分别為number和first
sina_number = ET.SubElement(sina, "number")
sina_number.text = "1"
sina_first = ET.SubElement(sina, "first")
sina_first.text = "http://roll.tech.sina.com.cn/internet_all/index_1.shtml"
#在chinabyte下建立兩個子節點,設定其節點名稱為number和first
chinabyte_number = ET.SubElement(chinabyte, "number")
chinabyte_number.text = "1"
chinabyte_first = ET.SubElement(chinabyte, "first")
chinabyte_first.text = "http://www.chinabyte.com/more/124566.shtml"
#将節點數資訊儲存在ElementTree中,并且儲存為XML格式檔案
tree = ET.ElementTree(root)
tree.write("urlfile.xml")
解析和修改XML檔案
ElementTree.parse(source, parser=None),将xml檔案加載并傳回ElementTree對象。parser是一個可選的參數,如果為空,則預設使用标準的XMLParser解析器。
ElementTree.getroot(),得到根節點。傳回根節點的element對象。
Element.remove(tag),删除root下名稱為tag的子節點
以下函數,ElementTree和Element的對象都包含。
find(match),得到第一個比對match的子節點,match可以是一個标簽名稱或者是路徑。傳回個element
findtext(match,default=None),得到第一個配置的match的element的内容
findall(match),得到比對match下的所有的子節點,match可以是一個标簽或者是路徑,它會傳回一個list,包含比對的elements的資訊
iter(tag),建立一個以目前節點為根節點的iterator。
這裡有一個xml檔案
<?xml version="1.0"?>
1
2008
141100
4
2011
59900
68
2011
13600
現在是解析xml檔案的代碼
#解析Xml檔案
def parseXmlFile(xml_name):
#将XMl檔案加載并傳回一個ELementTree對象
tree = ET.parse(xml_name)
#得到第一個比對sina标簽的Element對象
sina = tree.find("contry")
#得到sina的SubElement
for sub_tag in sina:
print sub_tag.text
#得到所有比對sina标簽的Element對象的list集合
list_contry = tree.findall("contry")
for contry in list_contry:
for sub_tag in contry:
print sub_tag.text
#修改xml檔案
for rank in tree.iter('rank')
new_rank = int(rank.text)+1
rank.text = str(new_rank)
rank.set('updated', 'yes')
tree.write(xml_name)
第一次的輸出是:1,2008,14100
第二次的輸出是:1,2008,14100,4,2011,59900,68,2011,13600
修改後的xml檔案為
<?xml version="1.0"?>
2
2008
141100
5
2011
59900
69
2011
13600
configparser 簡介
configparser 是 Pyhton 标準庫中用來解析配置檔案的子產品,并且内置方法和字典非常接近。Python2.x 中名為 ConfigParser,3.x 已更名小寫,并加入了一些新功能。
配置檔案的格式如下:
[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
[bitbucket.org]
User = Tom
[topsecret.com]
Port: 50022
ForwardX11: no
“[ ]”包含的為 section,section 下面為類似于 key - value 的配置内容;
configparser 預設支援 ‘=’ ‘:’ 兩種分隔。
configparser 常用方法
初始化執行個體
使用 configparser 首先需要初始化執行個體,并讀取配置檔案:
>>>import configparser
>>>config = configparser.ConfigParser() # 注意大小寫
>>>config.read("config.ini") # 配置檔案的路徑
["config.ini"]
或者可以直接讀字典
>>> parser = configparser.ConfigParser()
>>> parser.read_dict({'section1': {'key1': 'value1',
... 'key2': 'value2',
... 'key3': 'value3'},
... 'section2': {'keyA': 'valueA',
... 'keyB': 'valueB',
... 'keyC': 'valueC'},
... 'section3': {'foo': 'x',
... 'bar': 'y',
... 'baz': 'z'}
... })
擷取所有 sections
>>>config.sections()
['bitbucket.org', 'topsecret.com'] # 注意會過濾掉[DEFAULT]
擷取指定 section 的 keys & values
>>>config.items('topsecret.com')
>>>> [('port', '50022'), ('forwardx11', 'no')] # 注意items()傳回的字元串會全變成小寫
擷取指定 section 的 keys
>>>config.options('topsecret.com')
['Port', 'ForwardX11']
>>> for option in config['topsecret.com']:
... print(option)
Port
ForwardX11
擷取指定 key 的 value
>>> config['bitbucket.org']['User']
'Tom'
>>>config.get('bitbucket.org', 'User')
'Tom'
>>>config.getint('topsecret.com', 'Port')
50022
檢查
>>>'DEFAULT' in config
True
>>>'test' in config['section_test']
False
>>>'Tom' in config['bitbucket.org']['User']
True
>>>config.has_section('bitbucket.org')
True
>>>config.has_option('section_test', 'test')
False
添加
>>>config.add_section('Section_1')
>>>config.set('Section_1', 'key_1', 'value_1') # 注意鍵值是用set()方法
>>>config.write(open('config.ini', 'w')) # 一定要寫入才生效
删除
>>>config.remove_option('Section_1', 'key_1')
True
>>>config.remove_section('Section_1')
True
>>>config.clear() # 清空除[DEFAULT]之外所有内容
>>>config.write(open('config.ini', 'w'))
關于 [DEFAULT]
[DEFAULT] 一般包含 ini 格式配置檔案的預設項,是以 configparser 部分方法會自動跳過這個 section 。
前面已經提到 sections() 是擷取不到的,還有删除方法對 [DEFAULT] 也無效:
>>>config.remove_section('DEFAULT')
False
>>>config.clear()
>>>'DEFAULT' in config
True
>>>'ForwardX11' in config['DEFAULT']
True
>>>config.sections()
[]
但指定删除和修改 [DEFAULT] 裡的 keys & values 是可以的:
>>>config.remove_option('DEFAULT', 'ForwardX11')
True
>>>config.set('DEFAULT', 'ForwardX11','no')
>>>config['DEFAULT']['ForwardX11']
'no'
還有個特殊的是,has_section() 也無效,可以和 in 差別使用
>>>config.has_section('DEFAULT')
False
>>>'DEFAULT' in config
True
更多用法請看官方文檔:https://docs.python.org/3.6/library/configparser.html
randmon(擷取随機數)
random.randomrandom.random()用于生成一個0到1的随機符點數: 0 <= n < 1.0
random.uniformrandom.uniform(a, b),用于生成一個指定範圍内的随機符點數,兩個參數其中一個是上限,一個是下限。如果a > b,則生成的随機數n: a <= n <= b。如果 a
複制代碼 代碼如下:
print random.uniform(10, 20)
print random.uniform(20, 10)
# 18.7356606526
# 12.5798298022
random.randintrandom.randint(a, b),用于生成一個指定範圍内的整數。其中參數a是下限,參數b是上限,生成的随機數n: a <= n <= b
複制代碼 代碼如下:
print random.randint(12, 20) # 生成的随機數 n: 12 <= n <= 20
print random.randint(20, 20) # 結果永遠是20
# print random.randint(20, 10) # 該語句是錯誤的。下限必須小于上限
random.randrangerandom.randrange([start], stop[,
step]),從指定範圍内,按指定基數遞增的集合中 擷取一個随機數。如:random.randrange(10, 100,
2),結果相當于從[10, 12, 14, 16, ... 96, 98]序列中擷取一個随機數。random.randrange(10,
100, 2)在結果上與 random.choice(range(10, 100, 2) 等效
random.choicerandom.choice從序列中擷取一個随機元素。其函數原型為:random.choice(sequence)。參數sequence表示一個有序類型。這裡要說明
一下:sequence在python不是一種特定的類型,而是泛指一系列的類型。list, tuple,
字元串都屬于sequence。有關sequence可以檢視python手冊資料模型這一章。下面是使用choice的一些例子:
複制代碼 代碼如下:
print random.choice("學習Python")
print random.choice(["JGood", "is", "a", "handsome", "boy"])
print random.choice(("Tuple", "List", "Dict"))
random.shufflerandom.shuffle(x[, random]),用于将一個清單中的元素打亂。如:
複制代碼 代碼如下:
p = ["Python", "is", "powerful", "simple", "and so on..."]
random.shuffle(p)
print p
# ['powerful', 'simple', 'is', 'Python', 'and so on...']
random.samplerandom.sample(sequence, k),從指定序列中随機擷取指定長度的片斷。sample函數不會修改原有序列
複制代碼 代碼如下:
list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
slice = random.sample(list, 5) # 從list中随機擷取5個元素,作為一個片斷傳回
print slice
print list # 原有序列并沒有改變
随機整數:
複制代碼 代碼如下:
>>> import random
>>> random.randint(0,99)
# 21
随機選取0到100間的偶數:
複制代碼 代碼如下:
>>> import random
>>> random.randrange(0, 101, 2)
# 42
随機浮點數:
複制代碼 代碼如下:
>>> import random
>>> random.random()
0.85415370477785668
>>> random.uniform(1, 10)
# 5.4221167969800881
随機字元:
複制代碼 代碼如下:
>>> import random
>>> random.choice('abcdefg%^*f')
# 'd'
多個字元中選取特定數量的字元:
複制代碼 代碼如下:
>>> import random
random.sample('abcdefghij', 3)
# ['a', 'd', 'b']
多個字元中選取特定數量的字元組成新字元串:
複制代碼 代碼如下:
>>> import random
>>> import string
>>> string.join( random.sample(['a','b','c','d','e','f','g','h','i','j'], 3) ).replace(" ","")
# 'fih'
随機選取字元串:
複制代碼 代碼如下:
>>> import random
>>> random.choice ( ['apple', 'pear', 'peach', 'orange', 'lemon'] )
# 'lemon'
洗牌:
複制代碼 代碼如下:
>>> import random
>>> items = [1, 2, 3, 4, 5, 6]
>>> random.shuffle(items)
>>> items
# [3, 2, 5, 6, 4, 1]
shutil子產品
引入: import shutil
copy()
功能:複制檔案
格式:shutil.copy('來源檔案','目标位址')
傳回值:複制之後的路徑
copy2()
功能:複制檔案,保留中繼資料
格式:shutil.copy2('來源檔案','目标位址')
傳回值:複制之後的路徑
copyfileobj()
将一個檔案的内容拷貝的另外一個檔案當中
格式:shutil.copyfileobj(open(來源檔案,'r'),open('目标檔案','w'))
傳回值:無
copyfile()
功能:将一個檔案的内容拷貝的另外一個檔案當中
格式:shutil.copyfile(來源檔案,目标檔案)
傳回值:目标檔案的路徑
copytree()
功能:複制整個檔案目錄
格式:shutil.copytree(來源目錄,目标目錄)
傳回值:目标目錄的路徑
注意:無論檔案夾是否為空,均可以複制,而且會複制檔案夾中的所有内容
copymode()
功能:拷貝權限
copystat()
功能:拷貝中繼資料(狀态)
rmtree()
功能:移除整個目錄,無論是否空
格式:shutil.rmtree(目錄路徑)
傳回值:無
move()
功能:移動檔案或者檔案夾
格式:shutil.move(來源位址,目标位址)
傳回值:目标位址
which()
功能:檢測指令對應的檔案路徑
格式:shutil.which(‘指令字元串’)
傳回值:指令檔案所在位置
注意:window和linux不太一樣。 window的指令都是.exe結尾,linux則不是
disk_usage()
功能:檢測磁盤使用資訊
格式:disk_usage(‘盤符’)
傳回值:元組
歸檔和解包操作
歸檔:将多個檔案合并到一個檔案當中,這種操作方式就是歸檔。
解包:将歸檔的檔案進行釋放。
壓縮:壓縮時将多個檔案進行有損或者無損的合并到一個檔案當中。
解壓縮:就是壓縮的反向操作,将壓縮檔案中的多個檔案,釋放出來。
注意:壓縮屬于歸檔!
make_archive()
功能:歸檔函數,歸檔操作
格式:shutil.make_archive('目标檔案路徑','歸檔檔案字尾','需要歸檔的目錄')
傳回值:歸檔檔案的最終路徑
unpack_archive()
功能:解包操作
格式:shutil.unpack_archive('歸檔檔案路徑','解包目标檔案夾')
傳回值:None
注意:檔案夾不存在會建立檔案夾
get_archive_formats()
功能:擷取目前系統已注冊的歸檔檔案格式(字尾)
格式:shutil.get_archive_formats()
傳回值:清單 [(字尾,解釋),(字尾,解釋),(字尾,解釋)...]
get_unpack_formats()
功能:擷取目前系統已經注冊的解封包件格式(字尾)
格式:shutil.get_unpack_formats()
傳回值:清單 [(字尾,解釋),(字尾,解釋),(字尾,解釋)...]
paramiko
paramiko是一個用于做遠端控制的子產品,使用該子產品可以對遠端伺服器進行指令或檔案操作,值得一說的是,fabric和ansible内部的遠端管理就是使用的paramiko來現實。
1、下載下傳安裝
1
2
3
pycrypto,由于 paramiko 子產品内部依賴pycrypto,是以先下載下傳安裝pycrypto
pip3 install pycrypto
pip3 install paramiko
2、子產品使用



#!/usr/bin/env python#coding:utf-8
importparamiko
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.1.108', 22, 'alex', '123')
stdin, stdout, stderr = ssh.exec_command('df')
printstdout.read()
ssh.close();






importparamiko
private_key_path = '/home/auto/.ssh/id_rsa'key =paramiko.RSAKey.from_private_key_file(private_key_path)
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('主機名 ', 端口, '使用者名', key)
stdin, stdout, stderr = ssh.exec_command('df')
printstdout.read()
ssh.close()






importos,sys
importparamiko
t = paramiko.Transport(('182.92.219.86',22))
t.connect(username='wupeiqi',password='123')
sftp =paramiko.SFTPClient.from_transport(t)
sftp.put('/tmp/test.py','/tmp/test.py')
t.close()
importos,sys
importparamiko
t = paramiko.Transport(('182.92.219.86',22))
t.connect(username='wupeiqi',password='123')
sftp =paramiko.SFTPClient.from_transport(t)
sftp.get('/tmp/test.py','/tmp/test2.py')
t.close()






importparamiko
pravie_key_path = '/home/auto/.ssh/id_rsa'key =paramiko.RSAKey.from_private_key_file(pravie_key_path)
t = paramiko.Transport(('182.92.219.86',22))
t.connect(username='wupeiqi',pkey=key)
sftp =paramiko.SFTPClient.from_transport(t)
sftp.put('/tmp/test3.py','/tmp/test3.py')
t.close()
importparamiko
pravie_key_path = '/home/auto/.ssh/id_rsa'key =paramiko.RSAKey.from_private_key_file(pravie_key_path)
t = paramiko.Transport(('182.92.219.86',22))
t.connect(username='wupeiqi',pkey=key)
sftp =paramiko.SFTPClient.from_transport(t)
sftp.get('/tmp/test3.py','/tmp/test4.py')
t.close()



requests
Python标準庫中提供了:urllib等子產品以供Http請求,但是,它的 API 太渣了。它是為另一個時代、另一個網際網路所建立的。它需要巨量的工作,甚至包括各種方法覆寫,來完成最簡單的任務。

importurllib.request
f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')
result = f.read().decode('utf-8')




importurllib.request
req = urllib.request.Request('http://www.example.com/')
req.add_header('Referer', 'http://www.python.org/')
r =urllib.request.urlopen(req)
result = f.read().decode('utf-8')



注:更多見Python官方文檔:https://docs.python.org/3.5/library/urllib.request.html#module-urllib.request
Requests 是使用 Apache2 Licensed 許可證的 基于Python開發的HTTP 庫,其在Python内置子產品的基礎上進行了高度的封裝,進而使得Pythoner進行網絡請求時,變得美好了許多,使用Requests可以輕而易舉的完成浏覽器可有的任何操作。
1、安裝子產品
1
pip3 install requests
2、使用子產品



#1、無參數執行個體
importrequests
ret = requests.get('https://github.com/timeline.json')
print(ret.url)
print(ret.text)
#2、有參數執行個體
importrequests
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)
print(ret.url)
print(ret.text)






#1、基本POST執行個體
importrequests
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
print(ret.text)
#2、發送請求頭和資料執行個體
importrequests
importjson
url = 'https://api.github.com/some/endpoint'payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
ret = requests.post(url, data=json.dumps(payload), headers=headers)
print(ret.text)
print(ret.cookies)






requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
#以上方法均是在此方法的基礎上建構
requests.request(method, url, **kwargs)



更多requests子產品相關的文檔見:http://cn.python-requests.org/zh_CN/latest/
3、Http請求和XML執行個體
執行個體:檢測QQ賬号是否線上



importurllib
importrequests
from xml.etree importElementTree as ET
#使用内置子產品urllib發送HTTP請求,或者XML格式内容
"""f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')
result = f.read().decode('utf-8')
"""
#使用第三方子產品requests發送HTTP請求,或者XML格式内容
r = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')
result =r.text
#解析XML格式内容
node =ET.XML(result)
#擷取内容
if node.text == "Y":
print("線上")
else:
print("離線")



執行個體:檢視火車停靠資訊



importurllib
importrequests
from xml.etree importElementTree as ET
#使用内置子產品urllib發送HTTP請求,或者XML格式内容
"""f = urllib.request.urlopen('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result = f.read().decode('utf-8')
"""
#使用第三方子產品requests發送HTTP請求,或者XML格式内容
r = requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result =r.text
#解析XML格式内容
root =ET.XML(result)
for node in root.iter('TrainDetailInfo'):
print(node.find('TrainStation').text,node.find('StartTime').text,node.tag,node.attrib)



注:更多接口猛擊這裡
paramiko子產品



importparamiko
#建立SSH對象
ssh =paramiko.SSHClient()
#允許連接配接不在known_hosts檔案上的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#連接配接伺服器
ssh.connect(hostname="192.168.0.99", port=22, username="root", password="rootroot")
#執行指令
stdin, stdout, stderr = ssh.exec_command('df')
#擷取結果
result =stdout.read().decode()
#擷取錯誤提示(stdout、stderr隻會輸出其中一個)
err =stderr.read()
#關閉連接配接
ssh.close()
print(stdin, result, err)



注:如果注釋“ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())”這句,會報錯。
類似問題可以為linux系統中~/.ssh/known_hosts檔案中的内容。
二、實作SFTP功能



importparamiko
#連接配接虛拟機centos上的ip及端口
transport = paramiko.Transport(("192.168.0.99", 22))
transport.connect(username="root", password="rootroot")
#将執行個體化的Transport作為參數傳入SFTPClient中
sftp =paramiko.SFTPClient.from_transport(transport)
#将“calculator.py”上傳到filelist檔案夾中
sftp.put('D:\python庫\Python_shell\day05\calculator.py', '/filelist/calculator.py')
#将centos中的aaa.txt檔案下載下傳到桌面
sftp.get('/filedir/aaa.txt', r'C:\Users\duany_000\Desktop\test_aaa.txt')
transport.close()



注:如果遇到Windows中路徑問題,連結如下網址http://blog.csdn.net/elang6962/article/details/68068126
三、使用秘鑰實作SSH功能



importparamiko
private_key = paramiko.RSAKey.from_private_key_file('id_rsa31')
#建立SSH對象
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#連接配接伺服器
ssh.connect(hostname='192.168.79.9', port=22, username='root', pkey=private_key)
stdin, stdout, stderr = ssh.exec_command('ifconfig')
res_out =stdout.read()
print(res_out.decode())
ssh.close()



四、使用秘鑰實作SFTP功能

importparamiko
private_key = paramiko.RSAKey.from_private_key_file('id_rsa31')
#連接配接虛拟機centos上的ip及端口
transport = paramiko.Transport(("192.168.79.9", 22))
transport.connect(username="root", pkey=private_key)
#将執行個體化的Transport作為參數傳入SFTPClient中
sftp =paramiko.SFTPClient.from_transport(transport)
#将“calculator.py”上傳到filelist檔案夾中
sftp.put('D:\python庫\Python_shell\day05\calculator.py', '/filedir/calculator.py')
#将centos中的aaa.txt檔案下載下傳到桌面
sftp.get('/filedir/oldtext.txt', r'C:\Users\duany_000\Desktop\oldtext.txt')
transport.close()