Advertisement
shinemic

SFTP 批量下载远程文件

Nov 8th, 2020
1,089
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.78 KB | None | 0 0
  1. from functools import partial
  2. import paramiko
  3. import stat
  4. import os
  5. import os.path as op
  6.  
  7.  
  8. def eprint(verbose=True, *args, **kwargs):
  9.     if verbose:
  10.         print(*args, **kwargs)
  11.  
  12.  
  13. def unix_path_join(parent, child):
  14.     """兼容 *nix/dos 系统版本的 os.path.join"""
  15.  
  16.     return op.join(parent, child).replace(os.sep, '/')
  17.  
  18.  
  19. class SFTPDownloader:
  20.     def __init__(self, host, username, pkeyfile=None, password=None, port=22, verbose=False):
  21.         self._eprint = partial(eprint, verbose, flush=True)
  22.  
  23.         self.host = host
  24.         self.username = username
  25.         self.password = password
  26.         self.pkeyfile = pkeyfile
  27.         self.port = port
  28.  
  29.         self.connect_sftp_server()
  30.  
  31.     def connect_sftp_server(self):
  32.         """连接 SFTP 服务器"""
  33.  
  34.         ssh = paramiko.SSHClient()
  35.         ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  36.  
  37.         if self.pkeyfile is not None:
  38.             try:
  39.                 pkey = paramiko.RSAKey.from_private_key_file(
  40.                     filename=self.pkeyfile)
  41.                 ssh.connect(hostname=self.host,
  42.                             username=self.username, pkey=pkey)
  43.             except Exception as e:
  44.                 self._eprint('[ERR] failed to connect {} '
  45.                              'using rsa key <{}> | <{}>'
  46.                              .format(self.host, self.pkeyfile, e))
  47.             else:
  48.                 self._eprint('[INFO] connect to {}@{} '
  49.                              'successfully (using rsa key)'
  50.                              .format(self.username, self.host))
  51.                 self.sftp = paramiko.SSHClient.open_sftp(ssh)
  52.  
  53.         if self.password is not None:
  54.             try:
  55.                 ts = paramiko.Transport((self.host, self.port))
  56.                 ts.connect(username=self.username, password=self.password)
  57.             except Exception as e:
  58.                 self._eprint('[ERR] failed to connect {} '
  59.                              'using username/password | <{}>'
  60.                              .format(self.host, e))
  61.             else:
  62.                 self._eprint('[INFO] connect to {}@{} successfully'
  63.                              '(using username/password)'
  64.                              .format(self.username, self.host))
  65.                 self.sftp = paramiko.SFTPClient.from_transport(ts)
  66.  
  67.     def download(self, remotefile, localdir='.'):
  68.         """下载单个文件至指定本地目录"""
  69.  
  70.         if not op.exists(localdir):
  71.             os.makedirs(localdir)
  72.  
  73.         try:
  74.             self.sftp.get(remotefile, unix_path_join(
  75.                 localdir, op.basename(remotefile)))
  76.         except Exception:
  77.             return False
  78.         else:
  79.             return True
  80.  
  81.     def download_dir(self, rootdir, localdir='.', include=True):
  82.         """
  83.        递归下载远程目录
  84.  
  85.        @param rootdir  远程根目录
  86.        @param localdir 本地根目录
  87.        @param include  是否包括远程目录根目录本身
  88.        """
  89.  
  90.         rootdir = rootdir.rstrip('/\\')
  91.         localdir = localdir.rstrip('/\\')
  92.  
  93.         if include:
  94.             prefix = len(op.dirname(rootdir)) + 1
  95.         else:
  96.             prefix = len(rootdir) + 1
  97.  
  98.         def iterdirs(remotedir):
  99.             for child in self.sftp.listdir_attr(remotedir):
  100.                 if stat.S_ISDIR(child.st_mode):
  101.                     local_dir = unix_path_join(unix_path_join(
  102.                         localdir, remotedir[prefix:]), child.filename)
  103.                     try:
  104.                         os.makedirs(local_dir)
  105.                     except Exception:
  106.                         pass
  107.                     iterdirs(unix_path_join(remotedir, child.filename))
  108.                 else:
  109.                     remote_file = unix_path_join(remotedir, child.filename)
  110.                     local_dir = unix_path_join(localdir, remotedir[prefix:])
  111.                     self._eprint('[INFO] downloading <{}> ... '
  112.                                  .format(remote_file.replace(op.sep, '/')), end='')
  113.                     if self.download(remote_file, local_dir):
  114.                         self._eprint('success!')
  115.                     else:
  116.                         self._eprint('fail!')
  117.  
  118.         iterdirs(rootdir)
  119.  
  120.  
  121. def test():
  122.  
  123.     # 用户名-密钥文件
  124.     # host = 'localhost'
  125.     # username = 'username'
  126.     # pkeyfile = '/home/xx/.ssh/id_rsa'
  127.     # sftp = SFTPDownloader(host, username, pkeyfile, verbose=True)
  128.     # sftp.download_dir('remote/dir', 'local/dest', False)
  129.  
  130.     # 用户名-密码
  131.     # host = 'localhost'
  132.     # port = 10086
  133.     # username = 'username'
  134.     # password = 'password'
  135.     # sftp = SFTPDownloader(host, username, password=password, port=port, verbose=True)
  136.     # sftp.download_dir('remote/dir/', 'local/dest', True)
  137.  
  138.     pass
  139.  
  140.  
  141. if __name__ == "__main__":
  142.     test()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement