Crear funcionalidad SFTP en Python

Olorunfemi Akinlua 16 febrero 2024
  1. Use pysftp para crear la funcionalidad SFTP en Python
  2. Use paramiko para crear la funcionalidad SFTP en Python
Crear funcionalidad SFTP en Python

Secure Socket Shell (SSH) es un protocolo de red mejor y más seguro que nos permite acceder a otra computadora y utiliza una autenticación de contraseña y clave pública a través de SHA y encriptación.

El protocolo de transferencia de archivos SSH (SFTP) es un protocolo de transferencia de archivos que usa SSH y es mejor que el típico FTP que la gente usaba anteriormente.

Un protocolo de transferencia de archivos podría ser necesario para desarrollar nuestra aplicación en Python. Deberíamos usar el SFTP que nos brinda la capacidad predeterminada para superar ataques como la detección de contraseñas y el intermediario y mantener la integridad de nuestros datos.

Este artículo le muestra cómo usar SFTP dentro de su Python para mover sus datos y archivos.

Use pysftp para crear la funcionalidad SFTP en Python

Python viene con ftplib, una clase de cliente FTP con funciones auxiliares que brindan el servicio de protocolo FTP inseguro. Para que podamos usar SFTP, necesitamos instalar bibliotecas de terceros, y una de esas bibliotecas es la biblioteca pysftp.

Con pysftp, puede acceder a SFTP y trabajar con el protocolo seguro para satisfacer las necesidades de su aplicación. Para instalar pysftp, necesita usar pip.

pip install pysftp

Además, necesitamos un servidor SFTP. Para Windows, vamos a utilizar el software WinSCP, y para aprender a configurar un cliente de servidor SFTP en su PC con Windows, puede consultar esta guía de instalación. Sin embargo, si tiene un servidor SFTP, comencemos.

Antes de escribir algo de código, iniciaremos sesión en nuestro servidor SFTP utilizando nuestra clave privada y el nombre de usuario (akinl) y el nombre de host (localhost).

crear funcionalidad sftp en python - configuración avanzada del sitio

Ahora, hemos iniciado sesión en la carpeta raíz. Nuestro objetivo será enumerar los archivos y el directorio presentes en el directorio raíz y copiar los archivos en el servidor SFTP, especialmente en el directorio tienda.

crear funcionalidad sftp en python - servidor sftp registrado

Comencemos a codificar usando la plantilla de código predefinida especificada por la biblioteca pysftp. Dentro del código, hemos asignado nuestro nombre de host, puerto, nombre de usuario y ruta de clave privada.

Estos valores se informan a partir de los detalles de su servidor SFTP y la clave privada se copia en el directorio del archivo python.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("Connected to SFTP server!")

El código anterior se conecta al servidor SFTP utilizando un objeto de conexión SFTP (pysftp.Connection()) con los parámetros especificados. Dentro del bloque with, tenemos una conexión SFTP establecida dentro del objeto llamado sftp.

A continuación se muestra una salida del código:

C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py:61: UserWarning: Failed to load HostKeys from C:\\Users\\akinl\\.ssh\\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
  warnings.warn(wmsg, UserWarning)
Traceback (most recent call last):
  File "c:\\Users\\akinl\\Documents\\Python\\SFTP\\index.py", line 8, in <module>
    with pysftp.Connection(host=sftpHostName, port=sftpPort, username=userName, private_key=privateKeyPath) as sftp:
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 132, in __init__
    self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 71, in get_hostkey
    raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host localhost found.
Exception ignored in: <function Connection.__del__ at 0x000001F0E9656320>
Traceback (most recent call last):
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 1013, in __del__
    self.close()
  File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 784, in close
    if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'

No se encontró ninguna clave de host para el host %s es un error común cuando se trabaja con objetos de conexión SFTP con pysftp, que ocurre cuando el archivo de host no está presente.

Para manejar el problema, podemos crear opciones de conexión (pysftp.CnOpts()), especificar que las claves de host sean Ninguna e ignorar la verificación de hosts conocidos.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("SFTP server connection successful")

La salida del código es la siguiente:

C:\Python310\lib\site-packages\pysftp\__init__.py:61: UserWarning: Failed to load HostKeys from C:\Users\akinl\.ssh\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
  warnings.warn(wmsg, UserWarning)
SFTP server connection successful

El único error que tenemos es una advertencia de bajo nivel sobre la verificación de la clave de host deshabilitada. Primero, cambiemos el directorio de trabajo para mostrarle que estamos dentro del servidor SFTP.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print("SFTP server connection successful")
    print("The current working directory is ", sftp.pwd)
    sftp.cwd("./store")
    print("After the cwd operation, the current working directory is ", sftp.pwd)

La salida del código anterior se muestra a continuación:

SFTP server connection successful
The current working directory is /
After the cwd operation, the current working directory is /store.

El cwd cambia el directorio de trabajo actual a lo que se especifica como su argumento. Además, podemos listar los archivos dentro de los directorios root y store usando el método listdir() y los archivos dentro del

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    rootFiles = sftp.listdir()
    storeFiles = sftp.listdir("./store")
    print(rootFiles, storeFiles)

La salida del código es la siguiente:

['index.txt', 'main.py', 'store'] []

El método listdir() enumera todos los archivos y directorios dentro del directorio de trabajo actual si no se pasa ningún argumento, pero si le damos un argumento, busca archivos dentro del argumento que le pasamos. El resultado fueron dos archivos y un directorio para el directorio raíz y ninguno para el directorio almacén porque no existe ningún archivo.

Ahora, muevamos algunos archivos a nuestro servidor SFTP usando algunos métodos, put(), put_d() y put_r(). Usaremos el put() para mover solo archivos.

A continuación, cree un archivo de texto llamado test.txt dentro del mismo directorio que nuestro archivo python y copie el archivo en el servidor SFTP.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    sftp.put("test.txt", preserve_mtime=True)

La salida del código:

crear funcionalidad sftp en python - salida

El archivo test.txt ahora está en el directorio raíz del servidor SFTP. Ahora, muevamos el mismo test.txt al directorio store y enumeremos el contenido de su archivo antes y después de copiarlo.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print(sftp.listdir("./store"))
    sftp.put("test.txt", preserve_mtime=True, remotepath="./store/upload.txt")
    print(sftp.listdir("./store"))

El resultado del código anterior muestra que el archivo test.txt se cargó en el servidor como upload.txt y es visible dentro de la imagen.

[]
['upload.txt']

crear funcionalidad sftp en python - cargar salida

Podemos copiar el contenido de un directorio usando el método put_d(). Por ejemplo, creemos un directorio SeptData que contenga tres archivos de texto (uno.txt, dos.txt y tres.txt) y copiemos el contenido del directorio en la carpeta raíz.

Sin embargo, para que la ruta se copie, necesitaremos la ruta completa, no la ruta relativa que hemos usado anteriormente.

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    print(sftp.listdir("./"))
    sftp.put_d(
        r"C:\Users\akinl\Documents\Python\SFTP\SeptData", "./", preserve_mtime=True
    )
    print(sftp.listdir("./"))

La salida del código:

['index.txt', 'main.py', 'store', 'test.txt']
['index.txt', 'main.py', 'one.txt', 'store', 'test.txt', 'three.txt', 'two.txt']

Los tres archivos ahora están presentes dentro del directorio raíz, como se representa en la lista de archivos y directorios dentro del directorio. Por tanto, podemos descargar archivos del servidor SFTP utilizando el método get().

import pysftp

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None

with pysftp.Connection(
    host=sftpHostName,
    port=sftpPort,
    username=userName,
    private_key=privateKeyPath,
    cnopts=cnOptions,
) as sftp:
    sftp.get("./store/upload.txt", preserve_mtime=True)

Después de ejecutar con éxito el código, el archivo upload.txt estará presente dentro del directorio del archivo python. Puede obtener directorios remotos utilizando los métodos get_d() y get_r().

Use paramiko para crear la funcionalidad SFTP en Python

Paramiko es una gran biblioteca que proporciona una implementación sencilla de SSHv2 para Python a través de sus clases y métodos. Podemos usar algunos de estos métodos para iniciar conexiones a un servidor SFTP y trabajar con ese servidor mediante autenticación de clave pública.

Para instalar paramiko, puede usar el comando pip de la siguiente manera:

pip install paramiko

Usando los detalles de conexión de la última sección, podemos realizar las mismas operaciones, desde cambiar los directorios de trabajo hasta obtener archivos del servidor SFTP remoto.

El SSHClient() crea un nuevo SSH para que nos conectemos al servidor SFTP, y el set_missing_host_key_policy() nos permite establecer una política para conectarnos a servidores sin una clave de host conocida, y el método connect() crea la conexión real con el servidor SFTP.

Cambiemos el directorio al directorio store e imprimamos el directorio de trabajo actual y el contenido de dicho directorio con la ayuda de chdir, getcwd y listdir, respectivamente.

import paramiko

sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
    hostname=sftpHostName, port=sftpPort, username=userName, key_filename=privateKeyPath
)

sftp_client = ssh.open_sftp()
sftp_client.chdir("./store")
print(sftp_client.getcwd())
print(sftp_client.listdir())

sftp_client.close()
ssh.close()

La salida del código:

/store
['one.txt', 'three.txt', 'two.txt', 'upload.txt']

La primera línea contiene el directorio de trabajo actual, que fue establecido por el método chdir(), y la segunda línea contiene una lista de archivos y directorios dentro del directorio almacenar.

Olorunfemi Akinlua avatar Olorunfemi Akinlua avatar

Olorunfemi is a lover of technology and computers. In addition, I write technology and coding content for developers and hobbyists. When not working, I learn to design, among other things.

LinkedIn