Python SFTP上传本地目录到远程服务器

最近有个需求,需要将本地目录上传到远程服务器,保持目录层级关系不变。

马上想到用过的Paramiko模块,但发现Paramiko只支持文件上传,而不支持目录上传。

Paramiko是一个用Python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。

Paramiko支持Linux、Solaris、BSD、MacOS X、Windows等平台通过SSH从一个平台连接到另外一个平台。利用该模块,可以方便的进行ssh连接和sftp协议进行sftp文件传输。

一番尝试实现后,在此记录下,代码如下:

# coding=utf-8

import os
import sys
import logging
import paramiko

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

REMOTE_HOST = "remote_host"
REMOTE_USERNAME = "remote_username"
REMOTE_PASSWORD = "remote_password"
LOCAL_FOLDER = "local_folder_path"
REMOTE_FOLDER = "remote_folder_path"


def sftp_upload_whole_folder(client, local_folder, remote_folder):
    sftp = client.open_sftp()
    root_path = None
    for path, dirs, files in os.walk(local_folder):
        root_path = path if root_path is None else root_path
        remote_path = path.replace(root_path, remote_folder)
        for d in dirs:
            try:
                sftp.listdir(os.path.join(remote_path, d))
            except IOError:
                sftp.mkdir(os.path.join(remote_path, d))
        for f in files:
            sftp.put(os.path.join(path, f), os.path.join(remote_path, f))
    sftp.close()


client = paramiko.SSHClient()
client.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname=REMOTE_HOST, username=REMOTE_USERNAME, password=REMOTE_PASSWORD)
client.exec_command("mkdir -p {}".format(REMOTE_FOLDER))
sftp_upload_whole_folder(client, LOCAL_FOLDER, REMOTE_FOLDER)
client.close()

Note:

  1. REMOTE_HOST如果设置为localhost,需要将本机公钥写入authorized_keys

    $ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

    否则会出现paramiko.ssh_exception.BadAuthenticationType: ('Bad authentication type', ['publickey']) (allowed_types=['publickey'])错误,可通过$ ssh -v host查找具体原因。

  2. LOCAL_FOLDERREMOTE_FOLDER路径结尾不需要斜杠/