杰瑞科技汇

paramiko如何实现Python中的SCP文件传输?

Of course! Using paramiko for SCP (Secure Copy Protocol) in Python is a common task. While paramiko is primarily an SSHv2 protocol library, it includes a built-in SCP client implementation.

Here's a comprehensive guide covering everything from basic usage to more advanced scenarios and best practices.

What is Paramiko?

Paramiko is a pure Python (3.6+) implementation of the SSHv2 protocol. It provides a client for connecting to an SSH server and performing various operations, like executing commands, transferring files, and setting up tunnels. Its built-in SCP client is a convenient wrapper for secure file transfers.


Method 1: The Easy Way (Using Paramiko's Built-in SCP Client)

Paramiko has a high-level SCPClient class that makes file transfers very straightforward. This is the recommended approach for most use cases.

Step 1: Install Paramiko

If you don't have it installed, open your terminal or command prompt and run:

pip install paramiko

Step 2: Basic SCP Upload (Local to Remote)

This example shows how to copy a local file to a remote server.

import paramiko
import os
# --- Configuration ---
hostname = 'your.server.com'
port = 22
username = 'your_username'
password = 'your_password' # Or use key-based auth
local_path = '/path/to/your/local_file.txt'
remote_path = '/path/to/remote_file.txt' # Can be a filename or a full path
# --- Create SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # Note: This is insecure for production
try:
    # --- Connect to the Server ---
    ssh.connect(hostname, port=port, username=username, password=password)
    # --- Create SCP Client ---
    # The 'sftp' argument is recommended as it's more robust
    with paramiko.SCPClient(ssh.get_transport(), sanitize=lambda x: x) as scp:
        print(f"Uploading {local_path} to {remote_path}...")
        scp.put(local_path, remote_path)
        print("Upload complete!")
except paramiko.AuthenticationException:
    print("Authentication failed, please verify your credentials.")
except paramiko.SSHException as e:
    print(f"Unable to establish SSH connection: {e}")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    # --- Close the SSH Connection ---
    ssh.close()

Step 3: Basic SCP Download (Remote to Local)

To download a file from the server to your local machine, simply use the get() method.

import paramiko
# --- Configuration ---
hostname = 'your.server.com'
port = 22
username = 'your_username'
password = 'your_password'
remote_path = '/path/to/remote_file.txt'
local_path = '/path/to/your/local_download.txt' # The destination path
# --- Create SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    # --- Connect to the Server ---
    ssh.connect(hostname, port=port, username=username, password=password)
    # --- Create SCP Client ---
    with paramiko.SCPClient(ssh.get_transport(), sanitize=lambda x: x) as scp:
        print(f"Downloading {remote_path} to {local_path}...")
        scp.get(remote_path, local_path)
        print("Download complete!")
except paramiko.AuthenticationException:
    print("Authentication failed, please verify your credentials.")
except paramiko.SSHException as e:
    print(f"Unable to establish SSH connection: {e}")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    # --- Close the SSH Connection ---
    ssh.close()

Method 2: The More Robust Way (Using SFTP)

For more complex file operations (like listing directories, renaming files, or handling directories recursively), SFTP (SSH File Transfer Protocol) is a better choice. It's a more powerful and feature-rich protocol than SCP. Paramiko has a great SFTP client built-in.

The put() and get() methods of SFTP are very similar to SCP's.

import paramiko
import os
# --- Configuration ---
hostname = 'your.server.com'
port = 22
username = 'your_username'
password = 'your_password'
local_dir = '/path/to/local_dir'
remote_dir = '/path/to/remote_dir'
# --- Create SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    # --- Connect to the Server ---
    ssh.connect(hostname, port=port, username=username, password=password)
    # --- Create SFTP Client from the SSH transport ---
    sftp = ssh.open_sftp()
    # --- Example: Upload a directory recursively ---
    print(f"Uploading directory {local_dir} to {remote_dir}...")
    # To upload a directory, you need a helper function or loop
    # Here's a simple example for a single file
    sftp.put(os.path.join(local_dir, 'my_file.txt'), os.path.join(remote_dir, 'my_file.txt'))
    print("Directory upload complete (for the example file).")
    # --- Example: Download a file ---
    # sftp.get('/remote/path/to/file', '/local/path/to/file')
    # --- Close the SFTP session ---
    sftp.close()
except paramiko.AuthenticationException:
    print("Authentication failed, please verify your credentials.")
except paramiko.SSHException as e:
    print(f"Unable to establish SSH connection: {e}")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    # --- Close the SSH Connection ---
    ssh.close()

Advanced Topics & Best Practices

Key-Based Authentication (Recommended)

Using SSH keys is more secure than passwords. You'll need your private key file (e.g., id_rsa).

import paramiko
# --- Configuration ---
hostname = 'your.server.com'
port = 22
username = 'your_username'
private_key_path = '/home/user/.ssh/id_rsa' # Path to your private key
remote_path = '/path/to/remote_file.txt'
local_path = '/path/to/your/local_file.txt'
# --- Create SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    # --- Load the private key ---
    # You can use a password-protected key with passphrase=True
    private_key = paramiko.RSAKey.from_private_key_file(private_key_path)
    # --- Connect using the key ---
    ssh.connect(hostname, port=port, username=username, pkey=private_key)
    # --- Use SCP or SFTP ---
    with paramiko.SCPClient(ssh.get_transport()) as scp:
        scp.put(local_path, remote_path)
        print("File uploaded successfully using key authentication.")
except paramiko.AuthenticationException:
    print("Authentication failed. Check your key or username.")
except paramiko.SSHException as e:
    print(f"SSH connection error: {e}")
except FileNotFoundError:
    print(f"Private key file not found at {private_key_path}")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    ssh.close()

Handling Directories Recursively

Neither SCPClient.put() nor SFTPClient.put() can recursively upload a directory by default. You need to write a helper function.

import os
def upload_directory(local_dir, remote_dir, sftp):
    """
    Recursively uploads a directory to a remote path using SFTP.
    """
    # Create the remote directory if it doesn't exist
    try:
        sftp.stat(remote_dir)
    except IOError:
        sftp.mkdir(remote_dir)
    for item in os.listdir(local_dir):
        local_path = os.path.join(local_dir, item)
        remote_path = os.path.join(remote_dir, item)
        if os.path.isfile(local_path):
            print(f"Uploading file: {local_path} to {remote_path}")
            sftp.put(local_path, remote_path)
        elif os.path.isdir(local_path):
            print(f"Entering directory: {local_path}")
            upload_directory(local_path, remote_path, sftp)
# --- Usage within the SFTP try/except block ---
# sftp = ssh.open_sftp()
# upload_directory('/path/to/local_dir', '/path/to/remote_dir', sftp)
# sftp.close()

Security Warning: AutoAddPolicy

The line ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) is convenient for development but insecure for production. It automatically adds the host key of the server to your local known_hosts file, making you vulnerable to Man-in-the-Middle (MITM) attacks.

The secure way is to manually add the host key or use WarningPolicy:

# --- Better, but still not perfect for production ---
ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
# This will warn you if the host key changes, but will still allow the connection.
# --- The most secure way (Recommended for Production) ---
# 1. Get the host key from your server first (e.g., using `ssh-keyscan your.server.com`)
# 2. Add it to your ~/.ssh/known_hosts file manually.
# 3. Paramiko will then trust it automatically.
# If you can't do that, you can load it from a file:
# host_key = paramiko.RSAKey(filename='/path/to/known_hosts')
# ssh.get_host_keys().add(hostname, 'ssh-rsa', host_key)

Summary: SCP vs. SFTP with Paramiko

Feature paramiko.SCPClient paramiko.SFTPClient
Purpose Simple, fast file copying. General-purpose file management.
Operations put(), get() put(), get(), listdir(), remove(), rename(), mkdir(), etc.
Directory Handling No built-in recursive support. No built-in recursive support, but easier to implement with loops.
Performance Generally faster for simple transfers. Slightly more overhead, but very efficient.
Use Case Quick, simple scripts where you just need to copy a file or two. Complex scripts requiring file manipulation, directory traversal, or status checks.

Final Recommendation:

  • For a quick and simple file transfer, use paramiko.SCPClient. It's clean and easy.
  • For any complex operation (directories, multiple files, checking if a file exists), use paramiko.SFTPClient. It's more powerful and flexible.
分享:
扫描分享到社交APP
上一篇
下一篇