杰瑞科技汇

python paramiko 上传

核心概念

paramiko 是一个纯 Python 实现的 SSHv2 协议库,它为你提供了类似 OpenSSH 客户端的功能,让你可以在 Python 脚本中安全地连接到远程服务器,并执行命令、传输文件等。

python paramiko 上传-图1
(图片来源网络,侵删)

文件传输主要通过 SFTP (SSH File Transfer Protocol) 实现,paramiko 通过 SFTPClient 类来封装 SFTP 的所有操作。


安装 Paramiko

如果你的环境中还没有安装 paramiko,可以使用 pip 进行安装:

pip install paramiko

编写上传代码

我们将创建一个 Python 脚本,该脚本会将本地的一个文件上传到远程服务器的指定目录。

完整代码示例

这是一个功能完整、带有错误处理的示例。

python paramiko 上传-图2
(图片来源网络,侵删)
import paramiko
import os
def upload_file_via_sftp(
    hostname: str,
    port: int,
    username: str,
    password: str,
    local_path: str,
    remote_path: str
):
    """
    使用 Paramiko 通过 SFTP 上传文件到远程服务器。
    :param hostname: 远程服务器地址 (IP 或域名)
    :param port: SSH 端口号,通常是 22
    :param username: SSH 用户名
    :param password: SSH 密码
    :param local_path: 本地文件的完整路径
    :param remote_path: 远程服务器上目标文件的完整路径
    """
    # 1. 创建 SSH 客户端对象
    ssh = paramiko.SSHClient()
    # 2. 自动添加服务器的 host key (不安全,仅用于测试环境)
    # 在生产环境中,应该使用 ssh.load_host_keys() 或设置 known_hosts 文件
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        # 3. 连接远程服务器
        print(f"正在连接到 {hostname}...")
        ssh.connect(hostname=hostname, port=port, username=username, password=password)
        print("连接成功!")
        # 4. 创建 SFTP 客户端
        sftp = ssh.open_sftp()
        print("SFTP 会话已开启。")
        # 5. 上传文件
        # sftp.put(local_file, remote_file)
        print(f"开始上传: {local_path} -> {remote_path}")
        sftp.put(local_path, remote_path)
        print("文件上传成功!")
    except paramiko.AuthenticationException:
        print("认证失败,请检查用户名和密码。")
    except paramiko.SSHException as e:
        print(f"SSH 连接或操作出错: {e}")
    except FileNotFoundError:
        print(f"本地文件未找到: {local_path}")
    except Exception as e:
        print(f"发生未知错误: {e}")
    finally:
        # 6. 关闭 SFTP 和 SSH 连接
        if 'sftp' in locals() and sftp:
            sftp.close()
            print("SFTP 连接已关闭。")
        if ssh:
            ssh.close()
            print("SSH 连接已关闭。")
# --- 使用示例 ---
if __name__ == "__main__":
    # --- 请替换为你的服务器信息 ---
    HOSTNAME = "your_server_ip_or_domain.com"
    PORT = 22
    USERNAME = "your_ssh_username"
    PASSWORD = "your_ssh_password"
    # --- 请替换为你的文件路径 ---
    # 本地文件路径
    LOCAL_FILE_PATH = "/path/to/your/local_file.txt"
    # 远程文件路径 (建议使用绝对路径)
    # 如果远程目录不存在,put() 操作会失败
    REMOTE_FILE_PATH = "/home/your_username/remote_file.txt"
    # 调用函数执行上传
    upload_file_via_sftp(
        hostname=HOSTNAME,
        port=PORT,
        username=USERNAME,
        password=PASSWORD,
        local_path=LOCAL_FILE_PATH,
        remote_path=REMOTE_FILE_PATH
    )

代码详解

  1. paramiko.SSHClient()

    这是创建 SSH 客户端连接的入口对象。

  2. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    • 安全警告: 这行代码会自动接受并保存服务器的 SSH 密钥(Host Key),这在测试或个人开发环境中很方便,但在生产环境中是危险的,因为它可能让你遭受“中间人攻击”(Man-in-the-Middle Attack)。
    • 生产环境建议:
      • 方法一: 在你的本地机器上,确保你已经通过 ssh-keyscan 或手动连接过服务器,服务器的密钥已经保存在 ~/.ssh/known_hosts 文件中。paramiko 默认会检查这个文件。
      • 方法二: 在代码中显式加载密钥文件。
        # 加载 known_hosts 文件
        ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
        # 如果服务器密钥不在文件中,连接会失败
  3. ssh.connect(...)

    python paramiko 上传-图3
    (图片来源网络,侵删)
    • 这是建立到服务器的实际连接。
    • hostname: 服务器地址。
    • port: SSH 端口,默认是 22。
    • username: 你的登录用户名。
    • password: 你的登录密码。
  4. ssh.open_sftp()

    • 在已建立的 SSH 连接上,开启一个 SFTP 会话,并返回一个 SFTPClient 对象,我们用它来处理所有文件传输相关操作。
  5. sftp.put(local_path, remote_path)

    • 这是上传文件的核心方法。
    • local_path: 你想上传的本地文件的绝对路径相对于当前工作目录的路径
    • remote_path: 文件在远程服务器上保存的绝对路径
    • 注意: remote_path 中指定的目录不存在sftp.put() 操作会失败并抛出 IOError,你需要确保目标目录已经存在,或者先创建它。
  6. sftp.close()ssh.close()

    • 非常重要: 在 finally 块中关闭连接,确保无论操作成功还是失败,网络资源都能被正确释放,先关闭 SFTP,再关闭 SSH。

进阶用法与最佳实践

使用 SSH 密钥认证(更安全)

在生产环境中,强烈推荐使用 SSH 密钥对进行认证,而不是密码。

# ... 在 ssh.connect() 之前 ...
# 加载私钥文件
private_key_path = '/path/to/your/private_key'
private_key = paramiko.RSAKey.from_private_key_file(private_key_path)
try:
    # 在 connect 方法中传入密钥
    ssh.connect(hostname=hostname, port=port, username=username, pkey=private_key)
    # ... 后续代码相同 ...

创建远程目录

如果目标目录不存在,可以先创建它。SFTPClient 提供了 mkdir 方法。

# 在 sftp.put() 之前,确保目录存在
remote_dir = os.path.dirname(remote_path)
try:
    sftp.stat(remote_dir) # 检查目录是否存在
except IOError:
    print(f"远程目录 {remote_dir} 不存在,正在创建...")
    sftp.mkdir(remote_dir) # 创建目录

显示上传进度

sftp.put() 本身不直接提供回调函数来显示进度,但我们可以通过一个技巧来实现:在循环中分块传输文件,并计算已传输的字节数。

def sftp_upload_with_progress(sftp, local_path, remote_path, chunk_size=8192):
    file_size = os.path.getsize(local_path)
    uploaded = 0
    with open(local_path, 'rb') as f:
        with sftp.file(remote_path, 'wb') as remote_file:
            while True:
                chunk = f.read(chunk_size)
                if not chunk:
                    break
                remote_file.write(chunk)
                uploaded += len(chunk)
                progress = (uploaded / file_size) * 100
                print(f"\r上传进度: {progress:.2f}%", end='', flush=True)
    print("\n上传完成!")
# 在你的主函数中替换 sftp.put()
# sftp_upload_with_progress(sftp, local_path, remote_path)

处理文件名中的空格和特殊字符

paramiko 的路径处理通常比较健壮,但为了确保万无一失,最好将路径作为字符串处理,并确保它们是绝对路径,避免在路径中包含可能被 shell 误解的字符。


常见问题排查

  • AuthenticationException: 认证失败,检查用户名、密码或密钥是否正确。
  • SSHException: 连接被拒绝或服务器配置问题,检查服务器是否运行 SSH 服务,防火墙是否开放了指定端口。
  • FileNotFoundError: 本地文件路径错误。
  • IOError: [Errno 2] No such file or directory: 远程目录不存在,确保在上传前创建好远程目录。
  • Permission denied (publickey,password).: 服务器拒绝了你的认证方式,如果你使用的是密码,请确认用户密码正确且有权限写入目标目录,如果你使用的是密钥,请确认密钥已正确添加到服务器的 ~/.ssh/authorized_keys 文件中,并且文件权限正确(authorized_keys 文件权限为 600,.ssh 目录权限为 700)。
分享:
扫描分享到社交APP
上一篇
下一篇