您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)如何在python中使用paramiko第三方庫(kù),文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
Python是一種跨平臺(tái)的、具有解釋性、編譯性、互動(dòng)性和面向?qū)ο蟮哪_本語(yǔ)言,其最初的設(shè)計(jì)是用于編寫自動(dòng)化腳本,隨著版本的不斷更新和新功能的添加,常用于用于開(kāi)發(fā)獨(dú)立的項(xiàng)目和大型項(xiàng)目。
paramiko 的三種常用方式如下:
使用密碼進(jìn)行登錄
使用密鑰免密碼登錄
SFTP 傳輸文件
其中最割裂的就是SFTP 傳輸文件,很多文章登陸使用SSHClient類,傳輸文件使用Transport類,我也是這樣用了很長(zhǎng)時(shí)間。
如果你也是這么用的,你沒(méi)有啥想法嗎?用python就是節(jié)約心智,怎么一個(gè)變形還能出來(lái)兩種東西呢,沒(méi)有辦法統(tǒng)一嗎?
網(wǎng)上的統(tǒng)一就是實(shí)例化Transport類然后實(shí)例化SSHClient類,再把實(shí)例化的Transport類添加到實(shí)例化SSHClient類??偸怯幸环N別扭的感覺(jué)。
重點(diǎn):查看源碼可以發(fā)現(xiàn),SSHClient類直接提供了 SFTP 傳輸文件的實(shí)例化方法,直接用就行了,世界頓時(shí)清爽了很多
import paramiko hostname = 'localhost' port = 22 username = 'aaron' # 看密碼就知道我是用的redhat系linux系統(tǒng) password = 'redhat' # 實(shí)例化SSHClient類 ssh = paramiko.SSHClient() # 遠(yuǎn)程主機(jī)沒(méi)有本地密鑰時(shí)的處理規(guī)則,主要有三個(gè) # AutoAddPolicy:直接建立連接,不進(jìn)行yes/no的確認(rèn) # WarningPolicy:直接建立連接,但是會(huì)提示是新連接 # RejectPolicy:拒絕未知的連接,依賴系統(tǒng)密鑰的信息。默認(rèn)選項(xiàng)。 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 連接到服務(wù)器 ssh.connect(hostname, port, username, password) # 執(zhí)行命令,獲取標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤輸出,均為流式輸入輸出 # 函數(shù)原型為 exec_command(self, command, bufsize=-1, timeout=None, get_pty=False, environment=None, ) # 理論上可以通過(guò)標(biāo)準(zhǔn)輸入,也就是下面的額stdin變量完成連續(xù)輸入 # 同時(shí)參數(shù)中有布爾型參數(shù) get_pty 可以指定是否獲取 tty 通道,這樣阻塞輸入,比如sudo輸入密碼什么的都能做。貌似就可以做成你想要的任何東西。 # 但是以上兩點(diǎn)沒(méi)有驗(yàn)證,貌似比較麻煩,我太懶了-_-||| # # 另外,exec_command方法每次都是新開(kāi)一個(gè)通道執(zhí)行命令,執(zhí)行完成后狀態(tài)消失。SSHClient類還提供一個(gè)invoke_shell方法,這個(gè)方法可以連續(xù)輸入命令。 # 這兩個(gè)的區(qū)別主要是 invoke_shell使用SSH shell通道,而exec_command使用SSH exec通道。 # shell通道就是常用的終端軟件登陸的通道,登陸變量都會(huì)進(jìn)行加載比如 ~/bashrc 等 # 而 exec通道 則不進(jìn)行加載登陸文件,相當(dāng)于linux桌面系統(tǒng)上右鍵開(kāi)terminal一樣。 # 如果你還是不懂,沒(méi)關(guān)系,invoke_shell nb就完事了 stdin, stdout, stderr = ssh.exec_command('df') # 打印輸出 print(stdout.read().decode()) # 不要忘記關(guān)閉連接 ssh.close()
這里使用密鑰文件,但是為了一般情況,我給密鑰文件設(shè)置了密碼,如果你只是想免密碼,不設(shè)置密碼即可.
在客戶機(jī)上生成密鑰對(duì),將公鑰傳遞給服務(wù)器
ssh-keygen -t rsa # 這里設(shè)置密碼為redhat_rsa,這里是給密鑰設(shè)置密碼,如果想免密,不設(shè)置密碼即可 ssh-copy-id -i ~/.ssh/id_rsa.pub aaron@localhost
import paramiko hostname = 'localhost' port = 22 username = 'aaron' # 這里是密鑰文件的密碼 password = 'redhat_rsa' # 密鑰文件的位置,可以是列表,paramiko會(huì)把列表里文件順序嘗試,登陸上位置 private_key_path = '/home/aaron/.ssh/id_rsa' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 這里網(wǎng)上很多先設(shè)置pkey傳入,但是直接傳文件路徑也可以,還簡(jiǎn)單。 # 我使用的和網(wǎng)上不同,另一個(gè)版本請(qǐng)自行搜索,資料n多 # 如果沒(méi)有密鑰,則不需添加password # look_for_keys默認(rèn)為True,就是會(huì)找你 .ssh 目錄下有沒(méi)有合適的密鑰文件 # 也就是說(shuō)如果密鑰文件存在,但是你傳 key_filename 時(shí)傳錯(cuò)了,不影響,paramiko已經(jīng)替你想好了,這才是正經(jīng) python 應(yīng)有的待遇,舒服! ssh.connect(hostname, port, username=username, password=password, key_filename=private_key_path, look_for_keys=False) stdin, stdout, stderr = ssh.exec_command('ip a') print(stdout.read().decode()) ssh.close()
import paramiko hostname = 'localhost' port = 22 username = 'aaron' password = 'redhat' # 還是SSHClient登陸,以上兩種方式都可以。 ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname, port, username, password) # 重頭戲,直接使用打開(kāi)方法即可 sftp = ssh.open_sftp() # do something # 從這里到下面的ssh.close()為止都是sftp能做的事情,具體能做啥,請(qǐng)看下一個(gè)代碼段,這里只列舉上傳(put) 下載(get) 文件,這兩個(gè)也比較重要 # 回調(diào)函數(shù),沒(méi)想到吧,上傳下載還能有回調(diào)函數(shù) # 參數(shù)一定,都是傳入的兩個(gè)size,int型數(shù)據(jù) # size 已傳輸文件累計(jì)大小 # file_size 文件總大小 def callback(size, file_size): print(f"目前傳輸文件比例: {size} / {file_size}") # 上傳文件,參數(shù)都給你們了,看看啥意思就行了 # 主要就是這個(gè)confirm, 如果定義會(huì)檢測(cè)一下上傳到服務(wù)器文件大小和本地大小是否一致,默認(rèn)False stat = sftp.put(localpath='/tmp/s.avi', remotepath='/tmp/a.avi', callback=callback, confirm=True) print(stat) # 下載文件,同樣參數(shù)都給你們了,看看啥意思就行了 sftp.get(localpath='/tmp/s.avi', remotepath='/tmp/a.avi', callback=callback) ssh.close()
stfp 能 do 的 something
# 列出當(dāng)前路徑下有什么文件,默認(rèn)path="." print(sftp.listdir()) # 列出當(dāng)前路徑下文件屬性,默認(rèn)path="." attrs = sftp.listdir_attr() print(attrs) print("="*20) # listdir函數(shù)就是遍歷的每個(gè)屬性的filename print(attrs[0].filename) print(attrs[0].longname) print(attrs[0].st_atime) print(attrs[0].st_mtime) print(attrs[0].st_gid) print(attrs[0].st_uid) print(attrs[0].st_mode) # 就是 listdir_attr 的迭代器版本 attrs = sftp.listdir_iter() print("="*20) for i in attrs: print(i.filename) print(i.longname) print(i.st_atime) print(i.st_mtime) print(i.st_gid) print(i.st_uid) print(i.st_mode) # 和內(nèi)置open用法基本相同,只不過(guò)是打開(kāi)外部文件 with sftp.open("a.txt", "w") as f: f.write("aaa") # 刪除文件,只能刪除文件,刪除目錄使用rmdir函數(shù)。文件不存在則報(bào)錯(cuò)。 sftp.remove("/home/aaron/a.txt") # 文件改名,類似于move sftp.rename("/home/aaron/as.txt", "/tmp/soon.txt",) # 符合posix標(biāo)準(zhǔn)的改名,沒(méi)有測(cè)試 sftp.posix_rename("/home/aaron/as.txt", "/tmp/soon.txt",) # 新建目錄 sftp.mkdir("/home/aaron/as") # 刪除目錄,類似rmdir,刪除的必須為空目錄 sftp.rmdir("/home/aaron/as") # 返回單個(gè)文件的attr信息,如果是軟連接則直接返回真實(shí)文件信息 stat = sftp.stat("/tmp/soon.txt") print(stat) # 測(cè)試和stat差不多,如果是軟鏈接則返回軟鏈接文件信息 stat = sftp.lstat("/tmp/soon.txt") print(stat) # 修改權(quán)限,權(quán)限為八進(jìn)制數(shù),需要把權(quán)限換算為十進(jìn)制數(shù)。比如下面的例子就是權(quán)限333 sftp.chmod("/tmp/soon.txt", 219) # 修改屬主和屬組,屬主和屬組為gid和uid表示。需要有權(quán)限。 sftp.chown("/tmp/soon.txt", 0, 0) # 設(shè)置atime和mtime,如果傳入None,則設(shè)置為當(dāng)前時(shí)間。否則必須傳入兩個(gè)元素的元組或數(shù)組,分別為 (atime, mtime) sftp.utime("/tmp/soon.txt", None) import time sftp.utime("/tmp/soon.txt", (time.time(), time.time())) # 讀取軟鏈接指定的目標(biāo) print(sftp.readlink("/etc/rc.local")) # 讀取軟連接制定目標(biāo)的絕對(duì)路徑 print(sftp.normalize("/etc/rc.local")) # 切換工作路徑。SFTP沒(méi)有工作路徑的概念,但是paramiko進(jìn)行了模擬。如果設(shè)置了路徑,所有的相對(duì)路徑都是根據(jù)這個(gè)路徑來(lái)的。如果想要切換回去傳入None即可。 sftp.chdir("/tmp") # 獲取當(dāng)前的工作路徑。如果沒(méi)有使用chdir切換過(guò),則會(huì)返回None print(sftp.getcwd())
自己一直想做一個(gè)類似xshell的東西,尤其是mac本的iterm或者iterm2是啥垃圾,還被吹的不行不行的,是沒(méi)用過(guò)好東西嗎。
但是每次執(zhí)行exec_command都會(huì)從家目錄開(kāi)始,無(wú)法切換目錄,十分不方便。一直沒(méi)有啥進(jìn)展,知道遇到了 invoke_shell ,一切看起來(lái)都有了些可能。
import time from threading import Thread import paramiko # 接收消息并打印的函數(shù) # 返回的消息會(huì)分成好幾段,如果只是發(fā)送命令后直接打印是打印不全的,這里直接循環(huán)檢測(cè)緩沖區(qū),有結(jié)果就打印。 def recv_and_print(channel): # 定義全局變量,recv_func_flag 此接收函數(shù)退出標(biāo)志,cmd 當(dāng)前執(zhí)行命令 global recv_func_flag, cmd while recv_func_flag: # 如果此次命令是exit并且退出完成,則設(shè)置退出標(biāo)志 if cmd == "exit" and channel.exit_status_ready(): # 打印退出狀態(tài),為int型數(shù)字 print(f"此次退出狀態(tài):{channel.recv_exit_status()}") # 退出標(biāo)志置為假 recv_func_flag = False # 吐過(guò)緩沖區(qū)有數(shù)據(jù) if channel.recv_ready(): # 接收數(shù)據(jù) response = channel.recv(1024).decode().strip() # 需要注意的是接收的數(shù)據(jù)會(huì)把傳入的命令也返回一遍,這里我們只保留自己打在屏幕上的,不要傳回的,所以傳回的數(shù)據(jù)如果和命令相同則不打印,略過(guò) if response != cmd: print(response, end="") print("接收函數(shù)退出......") # 定義全局變量 recv_func_flag = True cmd = "" # ssh登陸,老一套東西 hostname = 'localhost' port = 22 username = 'aaron' password = 'redhat010;' ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname, port, username, password) # 獲取invoke_shell invoke_shell = ssh.invoke_shell() # 接收函數(shù)使用另一個(gè)線程運(yùn)行,因?yàn)楹彤?dāng)前主線程一同退出,所以不需要join方法 t = Thread(target=recv_and_print, args=(invoke_shell,)) t.start() # 主線程退出標(biāo)志 flag = True while flag: # 輸入命令 cmd = input() # 輸入命令必須有回車才會(huì)執(zhí)行,這里我發(fā)送的是linux命令,\r之后能執(zhí)行命令,如果系統(tǒng)不同,需要測(cè)試\r\n等回車字符 invoke_shell.send(f"{cmd}\r") # 如果命令是exit則退出循環(huán) if cmd == "exit": flag = False # 檢測(cè)接收函數(shù)已經(jīng)退出,這里停止0.5s是因?yàn)橥顺雒畎l(fā)送給服務(wù)器,服務(wù)器會(huì)返回注銷的信息,之后檢測(cè)接收函數(shù)才會(huì)完全退出,認(rèn)為設(shè)置了一個(gè)等待時(shí)間,這個(gè)時(shí)間因?yàn)槭潜緳C(jī),設(shè)置的相對(duì)不長(zhǎng),如果是其他主機(jī),需要根據(jù)網(wǎng)絡(luò)以及超時(shí)情況進(jìn)行設(shè)置 while recv_func_flag: time.sleep(0.5) # 別忘了關(guān)閉ssh ssh.close()
這個(gè)demo直接運(yùn)行然后輸入命令即可,就像是使用terminal直接登陸一樣。
ll等定義的alias也是能使用的。
但是雙擊tab ctrl+c 等沒(méi)有實(shí)現(xiàn),留待諸君完善吧
這個(gè)demo目前還有一些問(wèn)題。時(shí)間原因也懶得解決了,以后用到的時(shí)候再深入探究吧。
換行總是有問(wèn)題,時(shí)好時(shí)壞,感覺(jué)每次發(fā)送數(shù)據(jù)有時(shí)命令、結(jié)果、信息提示符有時(shí)合并發(fā)送,有時(shí)分開(kāi)發(fā)送,沒(méi)有啥必然規(guī)律。也許和linux發(fā)行版有關(guān)?和tcp通信有關(guān)?目前原因不明(具體現(xiàn)象請(qǐng)自行測(cè)試)
顯示信息使用了 print(response, end="") 退出時(shí)也使用相同的顯示命令,到時(shí)系統(tǒng)注銷的顯示信息和函數(shù)的提示信息"接收函數(shù)退出......"拼接在一起了(對(duì)啊,提示信息之前我可以加個(gè)回車啊,哎呀,不再測(cè)試了,太累了)
su命令也可以正常執(zhí)行,輸入密碼啥的不影響,但是密碼會(huì)明文顯示。。。。。
接上條,su退出成問(wèn)題,su退出使用exit,整個(gè)函數(shù)就退出了。算了,不修復(fù)了/-_-\
上述就是小編為大家分享的如何在python中使用paramiko第三方庫(kù)了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。