stdin , stdout , 以及stderr 變量包含與標準I/O 流對應的流對象. 若是須要更好地控制輸出,而print 不能知足你的要求, 它們就是你所須要的. 你也能夠替換它們, 這時候你就能夠重定向輸出和輸入到其它設備( device ), 或者以非標準的方式處理它們
hashlib加密
hashlib主要提供字符加密功能,將md5和sha模塊整合到了一塊兒,支持md5,sha1, sha224, sha256, sha384, sha512等算法
具體應用
#!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj import hashlib # ######## 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函數和私有的密鑰,來生成固定長度的消息鑑別碼;
SHA一、MD5等Hash算法是比較經常使用的不可逆Hash簽名計算方法;
BASE64,將任意序列的8字節字符轉換爲人眼沒法直接識別的符號編碼的一種方法;
各個語言版本的實現爲:
Python版:
import hmac import hashlib import base64 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(), /*key data*/ strKey.data(), /*key len*/ strKey.size(), /*data */(unsigned char*) strRandom.data(), /*data len*/ 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能夠輸出不少有用的信息,
參數:做用
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 <module> 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 <module> 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 管道,並獲取它們的返回(狀態)碼。這個模塊的目的在於替換幾個舊的模塊和方法,如:
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"])
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 桌面 0 >>> 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 桌面 0 >>> subprocess.call(['ls', '-l'], stdout=subprocess.DEVNULL) 0 >>> 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 桌面 0 >>> 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 桌面 0 >>> subprocess.check_call('ls -l /test', shell=True) ls: 沒法訪問/test: 沒有那個文件或目錄 Traceback (most recent call last): File "<stdin>", line 1, in <module> 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) 0 >>> 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: 沒有那個文件或目錄
3、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
實例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
4、總結
那麼咱們到底該用哪一個模塊、哪一個函數來執行命令與系統及系統進行交互呢?下面咱們來作個總結:
- 首先應該知道的是,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(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是必需要的參數 """
示例代碼:
>>> import json >>> 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'}
import json 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"?>
<data>
<country name="Liechtenstein">
<rank>1</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank>68</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
如今是解析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"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
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()
或者能夠直接讀字典
>>> 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']
獲取指定 section 的 keys & values
>>> config.items('topsecret.com') >>>> [('port', '50022'), ('forwardx11', 'no')]
獲取指定 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')
刪除
>>> config.remove_option('Section_1', 'key_1') True >>> config.remove_section('Section_1') True >>> config.clear()
關於 [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.random
random.random()用於生成一個0到1的隨機符點數: 0 <= n < 1.0
random.uniform
random.uniform(a, b),用於生成一個指定範圍內的隨機符點數,兩個參數其中一個是上限,一個是下限。若是a > b,則生成的隨機數n: a <= n <= b。若是 a <b, 則 b <= n <= a
print random.uniform(10, 20)
print random.uniform(20, 10)
# 18.7356606526
# 12.5798298022
random.randint
random.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.randrange
random.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.choice
random.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.shuffle
random.shuffle(x[, random]),用於將一個列表中的元素打亂。如:
p = ["Python", "is", "powerful", "simple", "and so on..."]
random.shuffle(p)
print p
# ['powerful', 'simple', 'is', 'Python', 'and so on...']
random.sample
random.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
注意:文件夾不存在會新建文件夾
功能:獲取當前系統已註冊的歸檔文件格式(後綴)
格式:shutil.get_archive_formats()
返回值:列表 [(後綴,解釋),(後綴,解釋),(後綴,解釋)...]
功能:獲取當前系統已經註冊的解包文件格式(後綴)
格式:shutil.get_unpack_formats()
返回值:列表 [(後綴,解釋),(後綴,解釋),(後綴,解釋)...]
paramiko
paramiko是一個用於作遠程控制的模塊,使用該模塊能夠對遠程服務器進行命令或文件操做,值得一說的是,fabric和ansible內部的遠程管理就是使用的paramiko來現實。
一、下載安裝
1
2
3
|
pycrypto,因爲 paramiko 模塊內部依賴pycrypto,因此先下載安裝pycrypto
pip3 install pycrypto
pip3 install paramiko
|
二、模塊使用
#!/usr/bin/env python #coding:utf-8 import paramiko 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') print stdout.read() ssh.close();
import paramiko 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') print stdout.read() ssh.close()
import os,sys import paramiko 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() import os,sys import paramiko 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()
import paramiko 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() import paramiko 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 太渣了。它是爲另外一個時代、另外一個互聯網所建立的。它須要巨量的工做,甚至包括各類方法覆蓋,來完成最簡單的任務。
import urllib.request f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508') result = f.read().decode('utf-8')
import urllib.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能夠垂手可得的完成瀏覽器可有的任何操做。
一、安裝模塊
二、使用模塊
# 一、無參數實例 import requests ret = requests.get('https://github.com/timeline.json') print(ret.url) print(ret.text) # 二、有參數實例 import requests payload = {'key1': 'value1', 'key2': 'value2'} ret = requests.get("http://httpbin.org/get", params=payload) print(ret.url) print(ret.text)
# 一、基本POST實例 import requests payload = {'key1': 'value1', 'key2': 'value2'} ret = requests.post("http://httpbin.org/post", data=payload) print(ret.text) # 二、發送請求頭和數據實例 import requests import json 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/
三、Http請求和XML實例
實例:檢測QQ帳號是否在線
import urllib import requests from xml.etree import ElementTree 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("離線")
實例:查看火車停靠信息
import urllib import requests from xml.etree import ElementTree 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模塊
import paramiko # 建立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文件中的內容。
2、實現SFTP功能
import paramiko # 鏈接虛擬機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
3、使用祕鑰實現SSH功能
import paramiko 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()
4、使用祕鑰實現SFTP功能
import paramiko 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()