Python で SFTP 機能を作成する

Olorunfemi Akinlua 2024年2月16日
  1. pysftp を使用して Python で SFTP 機能を作成する
  2. paramiko を使用して Python で SFTP 機能を作成する
Python で SFTP 機能を作成する

Secure Socket Shell (SSH) は、別のコンピューターにアクセスできるようにする安全で優れたネットワーク プロトコルであり、SHA と暗号化によるパスワードと公開キー認証を使用します。

SSH ファイル転送プロトコル (SFTP) は、SSH を使用するファイル転送プロトコルであり、以前に使用されていた一般的な FTP よりも優れています。

Python でアプリケーションを開発するには、ファイル転送プロトコルが必要になる場合があります。 パスワード スニッフィングや中間者攻撃などの攻撃を克服し、データの整合性を維持するデフォルトの機能を提供する SFTP を使用する必要があります。

この記事では、Python 内で SFTP を使用してデータとファイルを移動する方法について説明します。

pysftp を使用して Python で SFTP 機能を作成する

Python には、セキュアでない FTP プロトコル サービスを提供するヘルパー関数を備えた FTP クライアント クラスである ftplib が付属しています。 SFTP を使用するには、サードパーティのライブラリをインストールする必要があります。そのようなライブラリの 1つが pysftp ライブラリです。

pysftp を使用すると、SFTP にアクセスし、安全なプロトコルを使用してアプリケーションのニーズを満たすことができます。 pysftp をインストールするには、pip を使用する必要があります。

pip install pysftp

また、SFTP サーバーも必要です。 Windows の場合、WinSCP ソフトウェアを使用します。ただし、SFTP サーバーがある場合は、始めましょう。

コードを書く前に、private keyusername (akinl) およびホスト名 (localhost) を使用して SFTP サーバーにログインします。

python で sftp 機能を作成する - 高度なサイト設定

これで、root フォルダーにログインしました。 私たちの目標は、root ディレクトリ内に存在するファイルとディレクトリを一覧表示し、ファイルを SFTP サーバー、特に store ディレクトリにコピーすることです。

python で sftp 機能を作成 - sftp サーバーにログイン

pysftp ライブラリで指定された定義済みのコード テンプレートを使用してコーディングを開始しましょう。 コード内で、hostnameportusername、および private key path を割り当てました。

これらの値は SFTP サーバーの詳細から通知され、秘密鍵 は 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!")

上記のコードは、指定されたパラメーターで SFTP 接続オブジェクト (pysftp.Connection()) を使用して SFTP サーバーに接続します。 with ブロック内では、sftp という名前のオブジェクト内で確立された SFTP 接続があります。

以下は、コードの出力です。

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'

ホスト %s のホストキーが見つかりませんは、ホスト ファイルが存在しない場合に発生する、pysftpで SFTP 接続オブジェクトを操作する際の一般的なエラーです。

この問題を処理するには、接続オプション (pysftp.CnOpts()) を作成し、ホスト キーが None であることを指定して、既知のホスト チェックを無視します。

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")

コードの出力は次のとおりです。

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

唯一のエラーは、無効化されたホスト キー チェックに関する低レベルの警告です。 まず、作業ディレクトリを変更して、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)

上記のコードの出力を以下に示します。

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

cwd は、現在の作業ディレクトリをその引数として指定されたものに変更します。 また、listdir() メソッドを使用して root および store ディレクトリ内のファイルを一覧表示することもできます。

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)

コードの出力は次のとおりです。

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

listdir() メソッドは、引数が渡されない場合、現在の作業ディレクトリ内のすべてのファイルとディレクトリを一覧表示しますが、引数を指定すると、渡した引数内のファイルをチェックします。 その結果、ファイルが存在しないため、root ディレクトリには 2つのファイルと 1つのディレクトリがあり、store ディレクトリには何もありませんでした。

それでは、put()put_d()、および put_r() メソッドを使用して、いくつかのファイルを SFTP サーバーに移動してみましょう。 put() を使用して、ファイルのみを移動します。

次に、python ファイルと同じディレクトリ内に test.txt という名前のテキスト ファイルを作成し、そのファイルを 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)

コードの出力:

python で sftp 機能を作成 - 出力

test.txt ファイルは現在、SFTP サーバーのルート ディレクトリにあります。 次に、同じ test.txtstore ディレクトリに移動し、コピー前とコピー後のファイルの内容を一覧表示します。

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"))

上記のコードの出力は、test.txt ファイルが upload.txt としてサーバーにアップロードされ、画像内に表示されていることを示しています。

[]
['upload.txt']

python で sftp 機能を作成 - 出力をアップロード

put_d() メソッドを使用して、ディレクトリの内容をコピーできます。 たとえば、3つのテキスト ファイル (one.txttwo.txt、および three.txt) を含む SeptData ディレクトリを作成し、ディレクトリの内容を root フォルダーにコピーしてみましょう。

ただし、コピー元のパスには、以前に使用した相対パスではなく、完全パスが必要です。

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("./"))

コードの出力:

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

3つのファイルは、ディレクトリ内のファイルとディレクトリのリストで表されるように、root ディレクトリ内に存在します。 したがって、get() メソッドを使用して 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.get("./store/upload.txt", preserve_mtime=True)

コードが正常に実行されると、upload.txt ファイルが python ファイルのディレクトリ内に存在します。 get_d() および get_r() メソッドを使用して、リモート ディレクトリを取得できます。

paramiko を使用して Python で SFTP 機能を作成する

Paramiko は、クラスとメソッドを介して Python 用の SSHv2 を簡単に実装できる優れたライブラリです。 これらの方法のいくつかを使用して、SFTP サーバーへの接続を開始し、公開鍵認証を介してそのサーバーと連携できます。

paramiko をインストールするには、次のように pip コマンドを使用できます。

pip install paramiko

前のセクションの接続の詳細を使用して、作業ディレクトリの変更からリモート SFTP サーバーからのファイルの取得まで、同じ操作を実行できます。

SSHClient() は、SFTP サーバーに接続するための新しい SSH を作成し、set_missing_host_key_policy() は、既知のホスト キーなしでサーバーに接続するためのポリシーを設定できるようにし、connect() メソッドを使用します。 SFTP サーバーへの実際の接続を作成します。

ディレクトリを store ディレクトリに変更し、現在の作業ディレクトリとそのディレクトリの内容を、それぞれ chdirgetcwd、および listdir を使用して出力します。

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()

コードの出力:

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

最初の行には、chdir() メソッドによって設定された現在の作業ディレクトリが含まれており、2 行目には、store ディレクトリ内のファイルとディレクトリのリストが含まれています。

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