• Python学习之paramiko模块的基础操作与排错


    关于

    python的ssh库操作需要引入一个远程控制的模块——paramiko,可用于对远程服务器进行命令或文件操作。

    应用

    登陆服务器,问题排查。可用于编写脚本,在服务器上做一些繁琐的重复操作。

    安装

    打开cmd,输入命令python -m pip install paramiko

    示例

    1.秘钥登陆

    配置免密登录,linux上信任了windows的公钥,然后脚本在windows上跑,使用windows的私钥就可以直接不要密码登录linux

    注意:提供秘钥的paramiko.RSAKey.from_private_key_file('文件'),这里面的"文件"是你本机上的秘钥,不是指你被控机上的公钥哦!

    import paramiko
    
    key = paramiko.RSAKey.from_private_key_file("C:\\Users\\liyansheng\\.ssh\\id_rsa")
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    print("connecting")
    ssh.connect(hostname="192.168.220.128", username="root", pkey=key)
    print("connected")
    commands = "uname -a"
    stdin, stdout, stderr = ssh.exec_command(commands)
    stdin.close()
    res, err = stdout.read(), stderr.read()
    result = res if res else err
    print(result)
    ssh.close()
    
    if __name__ == '__main__':
        print()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.单个命令执行

    1. 创建一个.py文件,引入 paramiko模块
    	import paramiko
    
    • 1
    1. 建立SSHClient对象
    	ssh = paramiko.SSHClient()
    
    • 1
    1. 设置可信任,将主机加到host_allow列表
    	ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    • 1
    1. 创建连接
        ssh.connect("150.158.16.123", 22, "wuyanping", "2022")
    
    • 1
    1. 创建命令,发送并获取响应结果
        stdin, stdout, stderr = ssh.exec_command("ls /home")
        print(stdout.read().decode("utf-8"))
    
    • 1
    • 2
    1. 关闭连接
        ssh.close()
    
    • 1

    3.执行多个命令

    # 执行多条命令,注意传入的参数有个list
    def execMultiCmd(host, user, psw, cmds: list, port=22) -> (str, str):
        with paramiko.SSHClient() as ssh_client:
            ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh_client.connect(hostname=host, port=port, username=user, password=psw)
            cmd = ";".join(cmds)
            _, stdout, stderr = ssh_client.exec_command(cmd, get_pty=True)
            result = stdout.read().decode('utf-8')
            err = stderr.read().decode('utf-8')
        return result, err
    
    
    if __name__ == '__main__':
        cmdList = ["cd /home", "ls"]
        print(execMultiCmd("192.168.220.128", "root", "root", cmdList))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.SFTPClient下载文件

    方法封装:

    def down_file(host, user, psw, local_file, remote_file, port=22):
        with paramiko.Transport((host, port)) as transport:
            # 连接服务
            transport.connect(username=user, password=psw)
            # 获取SFTP示例
            sftp = paramiko.SFTPClient.from_transport(transport)
            # 下载
            sftp.get(remote_file, local_file)
            transport.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    问题:(错误)

    if __name__ == '__main__':
        down_file(my_linux.host, my_linux.user, my_linux.psw, "D:\\ssh_download", "/home/test.txt")
    
    • 1
    • 2
    Traceback (most recent call last):
      File "D:\MyCode2\py-1\ssh\download.py", line 17, in <module>
        down_file("192.168.220.128", "root", "root", "D:\\ssh_download", "/home/test.txt")
      File "D:\MyCode2\py-1\ssh\download.py", line 11, in down_file
        sftp.get(remote_file, local_file)
      File "D:\MyCode2\py-1\venv\lib\site-packages\paramiko\sftp_client.py", line 810, in get
        with open(localpath, "wb") as fl:
    PermissionError: [Errno 13] Permission denied: 'D:\\ssh_download'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    正确使用

    要指定下载的文件名,不能只是一个目录

    if __name__ == '__main__':
        down_file(my_linux.host, my_linux.user, my_linux.psw, "D:\\ssh_download\\test.txt", "/home/test.txt")
    
    • 1
    • 2

    5.上传文件

    def upload_file(host, user, psw, local_file, remote_file, port=22):
        with paramiko.Transport((host, port)) as transport:
            # 连接服务
            transport.connect(username=user, password=psw)
            # 获取SFTP示例
            sftp = paramiko.SFTPClient.from_transport(transport)
            sftp.put(local_file, remote_file)
            transport.close()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试同下载,特别要注意路径问题。如

    if __name__ == '__main__':
        upload_file(my_linux.host, my_linux.user, my_linux.psw, "D:\\ssh_download\\test123.txt", "/home/test/test123.txt")
    
    • 1
    • 2

    6.ssh工具封装

    import os
    
    import paramiko
    
    
    class SSHTool():
        def __init__(self, ip, port, user, psw):
            """
            初始化
            :param ip:
            :param port:
            :param user:
            :param psw:
            """
            self.ip = ip
            self.port = port
            self.user = user
            self.psw = psw
    
        def connect_ssh(self):
            """
            创建连接
            :return:
            """
            try:
                self.ssh = paramiko.SSHClient()
                self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                self.ssh.connect(
                    hostname=self.ip,
                    port=self.port,
                    username=self.user,
                    password=self.psw
                )
            except Exception as e:
                print(e)
            return self.ssh
    
        def close_ssh(self):
            """
            关闭连接
            :return:
            """
            try:
                self.ssh.close()
            except Exception as e:
                print(e)
    
        def exec_shell(self, shell):
            ssh = self.connect_ssh()
            try:
                stdin, stdout, stderr = ssh.exec_command(shell)
                return stdin, stdout, stderr
            except Exception as e:
                print(e)
    
        def sftp_put_file(self, file, local_dir, remote_dir):
            try:
                t = paramiko.Transport((self.ip, self.port))
                t.connect(username=self.user, password=self.psw)
                sftp = paramiko.SFTPClient.from_transport(t)
                sftp.put(os.path.join(local_dir, file), remote_dir)
                t.close()
            except Exception:
                print("connect error!")
    
        def sftp_get_file(self, file, local_dir, remote_dir):
            try:
                t = paramiko.Transport((self.ip, self.port))
                t.connect(username=self.user, password=self.psw)
                sftp = paramiko.SFTPClient.from_transport(t)
                sftp.get(remote_dir, os.path.join(local_dir, file))
                t.close()
            except Exception:
                print("connect error!")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    补充

    • 获取当前文件路径:os.getcwd()

      import os
      
      if __name__ == '__main__':
          print(os.getcwd())  # D:\MyCode2\py-1\ssh
      
      • 1
      • 2
      • 3
      • 4
    • python函数返回多个参数

      def get_strs() -> (str, str):
          return "hello", "word"
      if __name__ == '__main__':
          # 返回值为元祖的形式
          print(get_strs())  # ('hello', 'word')
          # 获取元祖的个数
          print(len(get_strs()))  # 2
          # 通过下标获取元祖的某一个值
          print(get_strs().__getitem__(1))  # word
          # 通过元祖的某个元素定位对应的下标
          print(get_strs().index("hello"))  # 0
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • with … as …使用

      为了更好地避免此类问题,不同的编程语言都引入了不同的机制。在 Python 中,对应的解决方式是使用 with as 语句操作上下文管理器(context manager),它能够帮助我们自动分配并且释放资源。简单的理解,同时包含 enter() 和 exit() 方法的对象就是上下文管理器。

      格式:

      with 表达式 [as target]:
          代码块
      
      • 1
      • 2

    学习参考

  • 相关阅读:
    DataCastle X WAIC | 2022世界人工智能大会AI开发的数据基础分论坛即将举行!
    93.(后端)分类参数增加接口实现——flask框架使用蓝图与restful发送请求添加数据
    Docker+K3S搭建集群
    算法通关村-----透彻理解动态规划
    Shell编程条件语句(if、case)
    北斗引路,太阳为源,定位报警,保护渔业,安全护航!
    java基于SpringBoot+vue的餐厅点餐外卖系统 elementui 前后端分离
    《HelloGitHub》第 89 期
    Gradle中的buildScript代码块
    DLL和PLL
  • 原文地址:https://blog.csdn.net/weixin_44107140/article/details/126729548