杰瑞科技汇

Python实现SCP传输,用Paramiko怎么写?

Of course! Using Python for SCP (Secure Copy Protocol) is a common task, especially for automating file transfers between servers. The most popular and robust library for this is Paramiko.

Here's a comprehensive guide covering everything from the basics to best practices and advanced use cases.


The Core Concept: SFTP vs. SCP

Before diving into the code, it's crucial to understand the difference:

  • SCP (Secure Copy Protocol): Designed for simple, fast file transfers. It's a protocol built on top of SSH. It's great for quickly copying a single file or a directory from one machine to another. It's generally faster for this specific task.
  • SFTP (SSH File Transfer Protocol): A more feature-rich protocol that works like a remote file system. You can list directories, create files, rename them, delete them, etc. It's more versatile but can be slightly slower for simple copies.

Paramiko provides an SCP client implementation built on its SSH client. This is the easiest and most common way to perform SCP transfers in Python.


Prerequisites

First, you need to install the paramiko library.

pip install paramiko

The Basic SCP Upload (File to Server)

This is the most common use case: uploading a local file to a remote server.

import paramiko
import os
# --- Configuration ---
HOSTNAME = 'your_server_ip'
USERNAME = 'your_username'
PASSWORD = 'your_password' # Or use SSH keys (recommended)
LOCAL_FILE_PATH = '/path/to/your/local_file.txt'
REMOTE_PATH = '/path/to/remote/directory/' # Note the trailing slash
# --- Create the SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # Be careful with this in production!
try:
    # --- Connect to the server ---
    print(f"Connecting to {HOSTNAME}...")
    ssh.connect(hostname=HOSTNAME, username=USERNAME, password=PASSWORD)
    # --- SCPClient for the transfer ---
    # The 'sftp' argument tells Paramiko to use the underlying SFTP channel for the transfer
    with ssh.open_sftp() as sftp:
        print(f"Uploading {LOCAL_FILE_PATH} to {REMOTE_PATH}")
        # The put() method handles the SCP protocol
        sftp.put(LOCAL_FILE_PATH, os.path.join(REMOTE_PATH, os.path.basename(LOCAL_FILE_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 connection ---
    ssh.close()
    print("Connection closed.")

Key Points:

  • ssh.open_sftp(): This creates an SFTP client object. Paramiko cleverly uses this to perform the SCP transfer.
  • sftp.put(local_path, remote_path): The core method for uploading. It handles the file copying.
  • os.path.basename(): A good practice to get just the filename from the local path and append it to the remote directory.
  • Security Warning: ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) automatically adds the server's host key to your known_hosts file. This is convenient but vulnerable to Man-in-the-Middle (MitM) attacks. In a production environment, you should manually verify and add the host key first.

The Basic SCP Download (File from Server)

Downloading a file from a remote server is just as easy, using the get() method.

import paramiko
import os
# --- Configuration ---
HOSTNAME = 'your_server_ip'
USERNAME = 'your_username'
PASSWORD = 'your_password' # Or use SSH keys
REMOTE_FILE_PATH = '/path/to/remote_file.txt'
LOCAL_DIR = '/path/to/local/directory/'
# --- Create the SSH Client ---
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    # --- Connect to the server ---
    print(f"Connecting to {HOSTNAME}...")
    ssh.connect(hostname=HOSTNAME, username=USERNAME, password=PASSWORD)
    # --- SCPClient for the transfer ---
    with ssh.open_sftp() as sftp:
        # Ensure local directory exists
        os.makedirs(LOCAL_DIR, exist_ok=True)
        local_file_path = os.path.join(LOCAL_DIR, os.path.basename(REMOTE_FILE_PATH))
        print(f"Downloading {REMOTE_FILE_PATH} to {local_file_path}")
        sftp.get(REMOTE_FILE_PATH, local_file_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:
    ssh.close()
    print("Connection closed.")

Best Practice: Using SSH Keys Instead of Passwords

Hardcoding passwords in your scripts is a security risk. Using SSH keys is the standard, more secure method.

How to Set Up SSH Keys (if you haven't already):

  1. On your local machine, generate a key pair (if you don't have one):

    ssh-keygen -t rsa -b 4096

    (Just press Enter to accept the defaults, and optionally set a passphrase).

  2. Copy your public key to the remote server:

    ssh-copy-id your_username@your_server_ip

    You'll be prompted for your password one last time. After this, you can log in without a password.

Updated Python Code for Key-Based Authentication:

import paramiko
import os
# --- Configuration ---
HOSTNAME = 'your_server_ip'
USERNAME = 'your_username'
PRIVATE_KEY_PATH = '/home/your_user/.ssh/id_rsa' # Path to your private key
LOCAL_FILE_PATH = '/path/to/your/local_file.txt'
REMOTE_PATH = '/path/to/remote/directory/'
# --- Create the SSH Client ---
ssh = paramiko.SSHClient()
# For production, load known hosts instead of AutoAddPolicy
# ssh.load_system_host_keys() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
try:
    # --- Connect using the private key ---
    print(f"Connecting to {HOSTNAME} with key...")
    # Use the key_filename parameter
    ssh.connect(hostname=HOSTNAME, username=USERNAME, key_filename=PRIVATE_KEY_PATH)
    with ssh.open_sftp() as sftp:
        print(f"Uploading {LOCAL_FILE_PATH}...")
        sftp.put(LOCAL_FILE_PATH, os.path.join(REMOTE_PATH, os.path.basename(LOCAL_FILE_PATH)))
    print("Upload complete!")
except paramiko.AuthenticationException:
    print("Authentication failed. Is the key correctly set up on the server?")
except paramiko.SSHException as e:
    print(f"Unable to establish SSH connection: {e}")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    ssh.close()
    print("Connection closed.")

Advanced: Copying an Entire Directory

The sftp.put() and sftp.get() methods work on files, not directories directly. To copy a directory, you need to implement a recursive function.

Here's a robust example for uploading a directory:

import paramiko
import os
def upload_directory(local_dir, remote_dir, sftp):
    """Recursively uploads a directory to a remote path."""
    print(f"Syncing {local_dir} to {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).replace('\\', '/') # Use forward slashes for remote path
        if os.path.isfile(local_path):
            print(f"  -> Uploading file: {item}")
            sftp.put(local_path, remote_path)
        elif os.path.isdir(local_path):
            print(f"  -> Creating directory: {item}")
            try:
                sftp.mkdir(remote_path)
            except IOError: # Directory might already exist
                pass
            upload_directory(local_path, remote_path, sftp) # Recursive call
# --- Configuration ---
HOSTNAME = 'your_server_ip'
USERNAME = 'your_username'
PRIVATE_KEY_PATH = '/home/your_user/.ssh/id_rsa'
LOCAL_DIR = '/path/to/local/directory/'
REMOTE_DIR = '/path/to/remote/directory/'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
    ssh.connect(hostname=HOSTNAME, username=USERNAME, key_filename=PRIVATE_KEY_PATH)
    with ssh.open_sftp() as sftp:
        # Ensure the base remote directory exists
        try:
            sftp.stat(REMOTE_DIR)
        except IOError: # Directory does not exist
            print(f"Creating remote base directory: {REMOTE_DIR}")
            sftp.mkdir(REMOTE_DIR)
        upload_directory(LOCAL_DIR, REMOTE_DIR, sftp)
    print("Directory upload complete!")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    ssh.close()
    print("Connection closed.")

Summary of Paramiko SCP Methods

Method Description Use Case
sftp.put(local_path, remote_path) Uploads a file from your local machine to the remote server. Copying a single file to the server.
sftp.get(remote_path, local_path) Downloads a file from the remote server to your local machine. Copying a single file from the server.
sftp.mkdir(path) Creates a new directory on the remote server. Preparing a location for uploads or part of a recursive copy.
sftp.stat(path) Gets information about a remote file or directory. Checking if a remote path exists before creating it.
sftp.listdir(path) Lists the contents of a remote directory. Useful for more complex directory operations.
分享:
扫描分享到社交APP
上一篇
下一篇