在使用 Python 写一些脚本的时候,在某些情况下,我们需要频繁登陆远程服务去执行一次命令,并返回一些结果。

在 shell 环境中,我们是这样子做的。

$ sshpass -p ${passwd} ssh -p ${port} -l ${user} -o StrictHostKeyChecking=no xx.xx.xx.xx "ls -l"

然后你会发现,你的输出有很多你并不需要,但是又不去不掉的一些信息(也许有方法,请留言交流),类似这样

host: xx.xx.xx.xx, port: xx
Warning: Permanently added '[xx.xx.xx.xx]:xx' (RSA) to the list of known hosts.
Login failure: [Errno 1] This server is not registered to rmp platform, please confirm whether cdn server.
total 4
-rw-r--r-- 1 root root 239 Mar 30  2018 admin-openrc

对于直接使用 shell 命令,来执行命令的,可以直接使用管道,或者将标准输出重定向到文件的方法取得执行命令返回的结果

1. 使用 subprocess

若是使用 Python 来做这件事,通常我们会第一时间,想到使用 os.popen,os.system,commands,subprocess 等一些命令执行库来间接获取 。

但是据我所知,这些库获取的 output 不仅只有标准输出,还包含标准错误(也就是上面那些多余的信息)

所以每次都要对 output 进行的数据清洗,然后整理格式化,才能得到我们想要的数据。

用 subprocess 举个例子,就像这样子

import subprocess
ssh_cmd = "sshpass -p ${passwd} ssh -p 22 -l root -o StrictHostKeyChecking=no xx.xx.xx.xx  'ls -l'"
status, output = subprocess.getstatusoutput(ssh_cmd)# 数据清理,格式化的就不展示了
<code...>

通过以上的文字 + 代码的展示 ,可以感觉到 ssh 登陆的几大痛点

  • 痛点一:需要额外安装 sshpass(如果不免密的话)
  • 痛点二:干扰信息太多,数据清理、格式化相当麻烦
  • 痛点三:代码实现不够优雅(有点土),可读性太差
  • 痛点四:ssh 连接不能复用,一次连接仅能执行一次
  • 痛点五:代码无法全平台,仅能在 Linux 和 OSX 上使用

为了解决这几个问题,我搜索了全网关于 Python SSH 的文章, 还真的被我找到了两个库

  • sh.ssh
  • Paramiko

2. 使用 sh.ssh

首先来介绍第一个, sh.ssh

sh 是一个可以让你通过函数的调用来完成 Linxu/OSX 系统命令的一个库,非常好用,关于它有机会也写篇介绍。

$ python3 -m pip install sh

今天只介绍它其中的一个函数: ssh

通常两台机器互访,为了方便,可设置免密登陆,这样就不需要输入密码。

这段代码可以实现免密登陆,并执行我们的命令 ls -l

from sh import ssh
output=ssh("root@xx.xx.xx.xx", "-p 22", "ls -l")
print(output)

但有可能 ,我们并不想设置互信免密,为了使这段代码更通用,我假定我们没有设置免密,只能使用密码进行登陆。

问题就来了,要输入密码,必须得使用交互式的方法来输入呀,在 Python 中要如何实现呢?

原来 ssh 方法接收一个 _out 参数,这个参数可以为一个字符串,表示文件路径,也可以是一个文件对象(或者类文件对象),还可以是一个回调函数,意思是当有标准输出时,就会调用将输出内容传给这个函数。

这就好办了呀。

我只要识别到有 password: 字样,就往标准输入写入我的密码就好了呀。

完整代码如下:

import sys
from sh import sshaggregated = ""
def ssh_interact(char, stdin):global aggregatedsys.stdout.write(char.encode())sys.stdout.flush()aggregated += charif aggregated.endswith("password: "):stdin.put("you_password\n")output=ssh("root@xx.xx.xx.xx", "-p 22", "ls -l",_tty_in=True, _out_bufsize=0, _out=ssh_interact)
print(output)

这是官方文档(http://amoffat.github.io/sh/tutorials/interacting_with_processes.html?highlight=ssh)给的一些信息,写的一个demo。

尝试运行后,发现程序会一直在运行中,永远不会返回,不会退出,回调函数也永远不会进入。

通过调试查看源代码,仍然查不到问题所在,于是去 Github 上搜了下,原来在 2017 年就已经存在这个问题了,到现在 2020 年了还没有修复,看来使用 sh.ssh 的人并不多,于是我又“追问”了下,期望能得到回复。

以上这个问题,只有在需要输入密码才会出现,如果设置了机器互信是没有问题的。

为了感受 sh.ssh 的使用效果,我设置了机器互信免密,然后使用如下这段代码。

from sh import sshmy_server=ssh.bake("root@xx.xx.xx.xx", "-p 22")# 相当于执行登陆一次执行一次命令,执行完就退出登陆
print(my_server.ls())# 可在 sleep 期间,手动登陆服务器,使用 top ,查看当前有多少终端在连接
time.sleep(5)# 再次执行这条命令时,登陆终端数将 +1,执行完后,又将 -1
print(my_server.ifconfig())

惊奇地发现使用 bake 这种方式, my_server.ls() 和 my_server.ifconfig() 这种看似是通过同一个ssh连接,执行两次命令,可实际上,你可以在远程机器上,执行 top 命令看到已连接的终端的变化,会先 +1 再 -1 ,说明两次命令的执行是通过两次连接实现的。

如此看来,使用 sh.ssh 可以解决痛点一(如果上述问题能得到解决)、痛点二、痛点三。

但是它仍然无法复用 ssh 连接,还是不太方便,不是我理想中的最佳方案。

最重要的一点是, sh 这个模块,仅支持 Linxu/OSX ,在 Windows 你得使用它的兄弟库 - pbs ,然后我又去 pypi 看了一眼 pbs,已经 “年久失修”,没人维护了。

至此,我离 “卒”,就差最后一根稻草了。

3. 使用 paramiko

带着最后一丝希望,我尝试使用了 paramiko 这个库,终于在 paramiko 这里,找回了本应属于 Python 的那种优雅。

你可以通过如下命令去安装它

$ python3 -m pip install paramiko

然后接下来,就介绍几种常用的 ssh 登陆的方法

方法1:基于用户名和密码的 sshclient 方式登录

然后你可以参考如下这段代码,在 Linux/OSX 系统下进行远程连接

import paramikossh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# 建立连接
ssh.connect("xx.xx.xx.xx", username="root", port=22, password="you_password")# 使用这个连接执行命令
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")# 获取输出
print(ssh_stdout.read())# 关闭连接
ssh.close()

方法2:基于用户名和密码的 transport 方式登录

方法1 是传统的连接服务器、执行命令、关闭的一个操作,多个操作需要连接多次,无法复用连接[ 痛点四 ]。

有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,方法1 则无法实现,那就可以使用 transport 的方法。

import paramiko# 建立连接
trans = paramiko.Transport(("xx.xx.xx.xx", 22))
trans.connect(username="root", password="you_passwd")# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans# 剩下的就和上面一样了
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
print(ssh_stdout.read())# 关闭连接
trans.close()

方法3:基于公钥密钥的 SSHClient 方式登录

import paramiko# 指定本地的RSA私钥文件
# 如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')# 建立连接
ssh = paramiko.SSHClient()
ssh.connect(hostname='xx.xx.xx.xx',port=22,username='you_username',pkey=pkey)# 执行命令
stdin, stdout, stderr = ssh.exec_command('ls -l')# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read())# 关闭连接
ssh.close()

方法4:基于密钥的 Transport 方式登录

import paramiko# 指定本地的RSA私钥文件
# 如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')# 建立连接
trans = paramiko.Transport(('xx.xx.xx.xx', 22))
trans.connect(username='you_username', pkey=pkey)# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())# 关闭连接
trans.close()

以上四种方法,可以帮助你实现远程登陆服务器执行命令,如果需要复用连接:一次连接执行多次命令,可以使用 方法二 和 方法四

用完后,记得关闭连接。

实现 sftp 文件传输

同时,paramiko 做为 ssh 的完美解决方案,它非常专业,利用它还可以实现 sftp 文件传输。

import paramiko# 实例化一个trans对象# 实例化一个transport对象
trans = paramiko.Transport(('xx.xx.xx.xx', 22))# 建立连接
trans.connect(username='you_username', password='you_passwd')# 实例化一个 sftp对象,指定连接的通道
sftp = paramiko.SFTPClient.from_transport(trans)# 发送文件
sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')# 下载文件
sftp.get(remotepath='/tmp/22.txt', localpath='/tmp/33.txt')
trans.close()

到这里,Paramiko 已经完胜了,但是仍然有一个痛点我们没有提及,就是多平台,说的就是 Windows,这里就有一件好事,一件坏事了,。

好事就是:paramiko 支持 windows

坏事就是:你需要做很多复杂的准备,你可 google 解决,但是我建议你直接放弃,坑太深了。

注意事项
使用 paramiko 的时候,有一点需要注意一下,这个也是我自己 “踩坑” 后才发现的,其实我觉得这个设计挺好的,如果你不需要等待它返回数据,可以直接实现异步效果,只不过对于不知道这个设计的人,确实是个容易掉坑的点

就是在执行 ssh.exec_command(cmd) 时,这个命令并不是同步阻塞的。

比如下面这段代码,执行时,你会发现 脚本立马就结束退出了,并不会等待 5 s 后,再 执行 ssh.close()

import paramikotrans = paramiko.Transport(("172.20.42.1", 57891))
trans.connect(username="root", password="youpassword")
ssh = paramiko.SSHClient()
ssh._transport = trans
stdin, stdout, stderr = ssh.exec_command("sleep 5;echo ok")
ssh.close()

但是如果改成这样,加上一行 stdout.read(), paramiko 就知道,你需要这个执行的结果,就会在 read() 进行阻塞。

import paramikotrans = paramiko.Transport(("172.20.42.1", 57891))
trans.connect(username="root", password="youpassword")
ssh = paramiko.SSHClient()
ssh._transport = trans
stdin, stdout, stderr = ssh.exec_command("sleep 5;echo ok")# 加上一行 read()
print(stdout.read())
ssh.close()

4. 写在最后

经过了一番对比,和一些实例的展示,可以看出 Paramiko 是一个专业、让人省心的 ssh 利器,个人认为 Paramiko 模块是运维人员必学模块之一,如果你恰好需要在 Python 代码中实现 ssh 到远程服务器去获取一些信息,那么我把 Paramiko 推荐给你。

最后,希望这篇文章,能给你带来帮助。

关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

点此免费领取:CSDN大礼包:《python学习路线&全套学习资料》免费分享

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、Python必备开发工具

三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

五、Python练习题

检查学习结果。

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。


这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

Python 远程连接服务器,用它就够了相关推荐

  1. Python 远程连接服务器用它就够了

    作者 | 费弗里 来源 | Python大数据分析 ❝ 本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNote ...

  2. 【Python】Python 远程连接服务器,用它就够了

    在使用 Python 写一些脚本的时候,在某些情况下,我们需要频繁登陆远程服务去执行一次命令,并返回一些结果. 在 shell 环境中,我们是这样子做的. $ sshpass -p ${passwd} ...

  3. Python远程连接服务器

    在使用 Python 写一些脚本的时候,在某些情况下,我们需要频繁登陆远程服务去执行一次命令,并返回一些结果. 对于直接使用 shell 命令,来执行命令的,可以直接使用管道,或者将标准输出重定向到文 ...

  4. python 远程桌面 命令行_Pycharm 远程连接服务器、远程访问python环境和打开远程命令行...

    Pycharm远程访问服务器教程 一.pycharm远程连接服务器操作流程 0.注意事项 本配置是基于pycharm 2020专业版进行的,其它版本也相差不大.社区版本无此功能. 1.首先进入远程连接 ...

  5. Pycharm远程连接服务器,操作代码

    1. Pycharm连接远程服务器 1.1 进入配置页面 Pycharm菜单栏,如下图所示,依次点击 Tools -> Deployment -> Configration- 1.2 配置 ...

  6. 金蝶虚拟化客户端连不上服务器,金蝶kis客户端远程连接服务器

    金蝶kis客户端远程连接服务器 内容精选 换一换 ELB的常见异常返回码有400.403.502.504等.若遇到这些返回码建议您先直接访问后端云服务器,查看是否是后端云服务器的异常.若后端云服务器响 ...

  7. Xshell远程连接服务器上的jupyter notebook

    用Xshell远程连接服务器上的jupyter notebook 今天浅写一下在Xshell远程连接服务器上已有的jupyter notebook,以后更新一下如何在服务器上部署jupyter not ...

  8. pycharm远程连接服务器中的docker容器的配置

    pycharm远程连接服务器中的docker容器 第一步:服务器中安装docker以及docker容器的运行 1.1docker的安装 docker的安装可以参照阿里云的教程, 阿里云安装教程,包含d ...

  9. Pycharm远程连接服务器(实践笔记)

    Pycharm远程连接服务器(实践笔记) 1. 远程连接服务器 2.配置服务器上的环境 记录一下过程,防止自己隔一段时间又忘了- &只有pycharm专业版才能远程连接 搞错了步骤1和2的顺序 ...

最新文章

  1. 荔枝FM 字体文件 IconFontTextView
  2. quartz可以指定方法名吗_大理石可以自己抛光吗?大理石自己抛光方法解答
  3. python 驱动级鼠标_罗技各系鼠标测评(2020年12月更新)
  4. linux中sed或awk,Linux中sed和awk命令比较实例
  5. numpy产生一个大于0的随机数_Numpy中常用随机函数的总结
  6. python下载教程-如何下载python包
  7. Spring整合log4j日志组件(转)
  8. 招聘笔试行测题之图形推理题解题思路汇总
  9. android手机 滚动截屏,安卓手机如何滚动截屏?看完图解一秒学会!
  10. LeoCAD:用于创建虚拟乐高模型的开源CAD程序
  11. LinkedList真的比ArrayList增删快吗?为什么?
  12. java 连接不上数据库
  13. 基础编程入门题目-Fortran
  14. android imageview.setVisibility(View.VISIBLE)设置无效,代码已执行但是图片不显示
  15. 电脑 ktv服务器系统,ktv服务器主机系统
  16. 实用selenium+python实现web自动化测试第八节
  17. Linux命令查看硬盘通电时间(smartmontools)
  18. graphpadY轴设置刻度不均匀_flotherm学习心得(参数设置)
  19. 在Anaconda3(D盘)中安装PyInstaller第三方库并导入pycharm,在PyCharm中和使用PyInstaller对py程序进行打包的方法
  20. fpga挂一片ddr2_FPGA的外部存储器接口DDR2(7)_CYCLONE IV与DDR2相关的引脚

热门文章

  1. numpy文件存取-npz,npy
  2. 摩尔斯电码转换python编码_python-摩尔斯电码查询器
  3. 怎么将翼型导入catia_CATIA翼型数据导入与曲面生成CATIA翼型数据导入与曲面生成.doc...
  4. math@python双阶乘@累乘的多种实现方式
  5. 《有限与无限的游戏》第三章 我是自己的天才:经典摘抄(2)
  6. 《计算广告》_刘鹏_[一]在线广告市场与背景_(2)计算广告基础
  7. 【网络通信】select、poll、epoll
  8. 机械硬盘smartID05 警告怎么办?
  9. libcurl异步请求+http长连接池
  10. AD-Altium Designer 16 安装附带链接