专栏名称: Python开发者
人生苦短,我用 Python。伯乐在线旗下账号「Python开发者」分享 Python 相关的技术文章、工具资源、精选课程、热点资讯等。
目录
相关文章推荐
Python中文社区  ·  量子计算芯片Willow问世:它会毁掉比特币吗? ·  3 天前  
Python中文社区  ·  用 Python 自动化生成股票投资分析报告 ·  4 天前  
Python爱好者社区  ·  曾硬刚小米,估值 60 亿美元的独角兽被宣布破产! ·  1 周前  
Python爱好者社区  ·  阿里也没啥余粮。。 ·  5 天前  
Python开发者  ·  再用 `print` 进行 ... ·  1 周前  
51好读  ›  专栏  ›  Python开发者

python 模块 paramiko 与 ssh

Python开发者  · 公众号  · Python  · 2016-12-23 21:57

正文

(点击上方公众号,可快速关注)


来源:361way 

链接:www.361way.com/python-paramiko-ssh/3984.html


paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。paramiko支持Linux, Solaris, BSD, MacOS X, Windows等平台通过SSH从一个平台连接到另外一个平台。利用该模块,可以方便的进行ssh连接和sftp协议进行sftp文件传输。


一、paramiko模块的安装


paramiko模块依赖PyCrypto模块,而PyCrypto需要GCC库编译,不过一般发行版的源里带有该模块。这里以centos6为例,直接借助以下命令可以直接完成安装:


# yum install gcc python-crypto python-paramiko python-devel  -y


windows版下可以安装windows版的GCC(MinGW),然后编辑安装pycrypto和paramiko ,下载安成后,直接运行python.exe setup.py build 和 python.exe setup.py install 就可以了。


二、paramiko的连接


使用paramiko模块有两种连接方式,一种是通过paramiko.SSHClient()函数,另外一种是通过paramiko.Transport()函数。


方法一:


import paramiko

ssh = paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect("某IP地址",22,"用户名", "口令")


上面的第二行代码的作用是允许连接不在know_hosts文件中的主机。


方法二


import paramiko

t = paramiko.Transport(("主机","端口"))

t.connect(username = "用户名", password = "口令")


如果连接远程主机需要提供密钥,上面第二行代码可改成:


t.connect(username = "用户名", password = "口令", hostkey="密钥")


三、paramiko ssh连接


以下是一个简单的通过paramiko模块定义的ssh连接并执行命令的函数,如下:


#!/usr/bin/python

#-*- coding: utf-8 -*-

import paramiko

#paramiko.util.log_to_file('/tmp/sshout')

def ssh2(ip,username,passwd,cmd):

    try:

        ssh = paramiko.SSHClient()

        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        ssh.connect(ip,22,username,passwd,timeout=5)

        stdin,stdout,stderr = ssh.exec_command(cmd)

#           stdin.write("Y")   #简单交互,输入 ‘Y’

        print stdout.read()

#        for x in  stdout.readlines():

#          print x.strip("n")

        print '%stOKn'%(ip)

        ssh.close()

    except :

        print '%stErrorn'%(ip)

ssh2("192.168.0.102","root","361way","hostname;ifconfig")

ssh2("192.168.0.107","root","123456","ifconfig")


其中第四行的日志部分,是记录ssh连接交互时的一些信息,可以看做是类似于debug的输出,一般情况下不需要开启。


stdin.write部分是用于交互情况下,通过该命令可以执行交互。注意这里可能会引起歧义,这里的交互并不是ssh连接过程中出现的让输入yes的交互,因为paramiko模块在连接过程中会自动处理好yes确认。这里的交互是指后面的cmd需要的执行的程序可能出现交互的情况下,可以通过该参数进行交互。


stdout标准输出,在输出内容比较少时,可以通过直接使用read读取出所有的输出;但在输出内容比较多时,建议通过按行读取进行处理。不过按行读取时,每行结尾会有换行符n,这样输出的结果很不美观。可以通过strip进行字符串的处理。


在函数调用过程中需要注意的是,IP、username、passwd都是属于字符串型的,所以需要加引号。后面执行的cmd,如果有多个命令需要操作时,需要通过分号进行分割。


四、paramiko sftp示例


单个文件小传下载的示例:


import paramiko

#建立一个加密的管道

scp=paramiko.Transport(('192.168.0.102',22))

#建立连接

scp.connect(username='root',password='361way')

#建立一个sftp客户端对象,通过ssh transport操作远程文件

sftp=paramiko.SFTPClient.from_transport(scp)

#Copy a remote file (remotepath) from the SFTP server to the local host

sftp.get('/root/testfile','/tmp/361way')

#Copy a local file (localpath) to the SFTP server as remotepath

sftp.put('/root/crash-6.1.6.tar.gz','/tmp/crash-6.1.6.tar.gz')

scp.close()


一个目录下多个文件上传下载的示例:


#!/usr/bin/env python

#-*- coding: utf-8 -*-

import paramiko,datetime,os

hostname='192.168.0.102'

username='root'

password='361way'

port=22

local_dir='/tmp/getfile'

remote_dir='/tmp/abc'

try:

    t=paramiko.Transport((hostname,port))

    t.connect(username=username,password=password)

    sftp=paramiko.SFTPClient.from_transport(t)

    #files=sftp.listdir(dir_path)

    files=sftp.listdir(remote_dir)

    for f in files:

        print ''

        print '#########################################'

        print 'Beginning to download file  from %s  %s ' % (hostname,datetime.datetime.now())

        print 'Downloading file:',os.path.join(remote_dir,f)

        sftp.get(os.path.join(remote_dir,f),os.path.join(local_dir,f))#下载

        #sftp.put(os.path.join(local_dir,f),os.path.join(remote_dir,f))#上传

        print 'Download file success %s ' % datetime.datetime.now()

        print ''

        print '##########################################'

    t.close()

except Exception:

       print "connect error!"


注:本处的目录下所有文件进行下载或上传的示例中,在遇到目录下还有嵌套的目录存在时,会将目录也当做文件进行处理,所以如果想要更加的完美的话,可以通过引入stat模块下的S_ISDIR方法进行处理


paramiko.transport对象也支持以socket的方式进行连接,如下示例:


import paramiko

transport = paramiko.Transport(('localhost',22))

transport.connect(username='root', password = 'password')

sftp = paramiko.SFTPClient.from_transport(transport)

sftp.get(remotefile,localfile)

#如果是上传则用:

#sftp.put(localfile, remotefile)

transport.close()

#用socket连接

tcpsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)

tcpsock.settimeout(5)

tcpsock.connect((ip,22),)

ssh = paramiko.Transport(tcpsock)

ssh.connect(username=user,password=password)

sftpConnect=paramiko.SFTPClient.from_transport(ssh)


五、利用paramiko实现ssh的交互式连接


以下是通过paramiko模块直接用ssh协议登陆到远程服务器的操作代码,这里先定义一个interactive模块,代码如下:


import socket

import sys

# windows does not have termios...

try:

    import termios

    import tty

    has_termios = True

except ImportError:

    has_termios = False

def interactive_shell(chan):

    if has_termios:

        posix_shell(chan)

    else:

        windows_shell(chan)

def posix_shell(chan):

    import select

    oldtty = termios.tcgetattr(sys.stdin)

    try:

        tty.setraw(sys.stdin.fileno())

        tty.setcbreak(sys.stdin.fileno())

        chan.settimeout(0.0)

        while True:

            r, w, e = select.select([chan, sys.stdin], [], [])

            if chan in r:

                try:

                    x = chan.recv(1024)

                    if len(x) == 0:

                        print 'rn*** EOFrn',

                        break

                    sys.stdout.write(x)

                    sys.stdout.flush()

                except socket.timeout:

                    pass

            if sys.stdin in r:

                x = sys.stdin.read(1)

                if len(x) == 0:

                    break

                chan.send(x)

    finally:

        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

# thanks to Mike Looijmans for this code

def windows_shell(chan):

    import threading

    sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.rnrn")

    def writeall(sock):

        while True:

            data = sock.recv(256)

            if not data:

                sys.stdout.write('rn*** EOF ***rnrn')

                sys.stdout.flush()

                break

            sys.stdout.write(data)

            sys.stdout.flush()

    writer = threading.Thread(target=writeall, args=(chan,))

    writer.start()

    try:

        while True:

            d = sys.stdin.read(1)

            if not d:

                break

            chan.send(d)

    except EOFError:

        # user hit ^Z or F6

        pass


代码内容可以从paramiko 在github项目上的demo里(https://raw.githubusercontent.com/paramiko/paramiko/master/demos/interactive.py)获取。再另外写一个ssh_inter.py的交互主程序,内容如下:


import paramiko

import interactive

#记录日志

paramiko.util.log_to_file('/tmp/test')

#建立ssh连接

ssh=paramiko.SSHClient()

ssh.load_system_host_keys()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect('192.168.0.102',port=22,username='root',password='xxxxxx',compress=True)

#建立交互式shell连接

channel=ssh.invoke_shell()

#建立交互式管道

interactive.interactive_shell(channel)

#关闭连接

channel.close()

ssh.close()


执行效果就像我们平时直接使用ssh登录一样。


六、总结


paramiko模块是一个比较强大的ssh连接模块,以上的示例只是列出了该模块的一些简单的使用方法,还可以使用threading模块加块程序并发的速度;也可以使用configparser模块处理配置文件,而我们将所有IP、用户信息操作都放入配置文件;使用setproctitle模块为执行的程序加一个容易区分的title等。


同样,虽然连fabric这样大名鼎鼎的软件使用的ssh都是用paramiko模块进行的封装,不过你依然可以选择不使用它,你也可以选择pexpect模块实现封装一个简易的ssh连接工具、或者使用同样比较火的salt-ssh模块。


觉得本文对你有帮助?请分享给更多人

关注「Python开发者」

看更多技术干货