概要
Python×WinSCPスクリプトを利用することでリモート環境にあるファイルをローカル環境にダウンロードできます。paramikoという外部ライブラリを利用することでも実装できますが、今回は敢えてこの方法で紹介していきます。
実施環境
Windows11(Windows10でも可)
Python 3.12.4
WinSCP
実装方法
コードブロックを分けていますが、1本のファイルに記載して大丈夫です。
import os
import subprocess
def main():
host = "127.0.0.1"
user = "pecorimaru"
password = "Cnetuser"
remote_path = "/tmp/テスト.pdf"
local_path = "E:\\data\\Documents\\SE\\Git\\Python\\jidoca312\\data\\fl01\\jd01\\"
download_remote_file(host, user, password, remote_path, local_path)
return
上記コードが呼び出し元です。
リモートファイルをダウンロードする上で必要な情報は
- host : ホストIPアドレス
- user : ユーザー名
- password : パスワード
- remote_path : ダウンロード対象となるリモートファイルのパス
- local_path : ローカルPCにダウンロードするパス
となります。
Pythonで指定するパスは基本的に「/」でも「\\」でも良いのですが、今回のローカルパスにおいては「\\」の指定が必須です。
def download_remote_file(host, user, password, remote_path, local_path):
# ファイルダウンロード用のWinSCPスクリプトを作成(処理終了時に削除)
path = "tmpscript.txt"
with open(path, mode="w") as f:
f.write("open %2%:%3%@%1%\r\n")
f.write("get %4% %5%\r\n")
f.write("exit")
# ダウンロードに必要な情報を設定
winscpcom = "C:/Program Files (x86)/WinSCP/WinSCP.com"
# [コマンドイメージ]
# "C:/Program Files (x86)/WinSCP/WinSCP.com"
# /script=tmpscript.txt /parameter 127.0.0.1 pecorimaru Cnetuser
# /tmp/テスト.pdf E:\\data\\Documents\\SE\\Git\\Python\\jidoca312\\data\\fl01\\jd01\\
cmd_text = f"\"{winscpcom}\" /script={path} \
/parameter {host} {user} {password} {remote_path} {local_path}"
# コマンドを実行
result = subprocess.run(cmd_text, shell=True)
# リターンコードを取得
print(f"returncode:{result.returncode}")
# WinSCPスクリプトを削除
os.remove(path)
return
WinSCP.comのパスはコマンド内でダブルクォーテーション「"」で囲う必要があるため注意。上記は「"」を文字列として扱うように「\」でエスケープしています。
if __name__ == "__main__":
main()
実行
リモートパス
Pythonスクリプトを実行
PS E:\data\Documents\SE\Git\Python\jidoca312\src\fl01\jd01> python .\remotetest.py
サーバを探索中・・・
サーバに接続しています・・・
認証しています・・・
ユーザ名"pecorimaru" を使用中
入力済みパスワードで認証中
認証されました
セッションを開始しています・・・
セッションを開始しました
アクティブ セッション: [1] pecorimaru@127.0.0.1
テスト.pdf | 292 KB | 5657.9 KB/s | binary | 100%
returncode:0
スクリプトを実行すると上記のようなコンソール出力がされます。
リターンコード:0は成功なので、ローカルパスにファイルがダウンロードされました。
リターンコード:0 以外で返ってくる場合は失敗しているので、コードを作り込む際はエラーハンドリングしておくと良いでしょう。
応用パターン
ローカルパスをファイル名まで指定することも可能
上記で紹介したコードではローカルパスはフォルダ名までを指定しましたが、ファイル名まで記載することでダウンロードするファイル名を指定することも可能です。
ファイル名はアスタリスク(*)を用いたワイルドカードの指定が可能
フォルダ名は不可ですが、ファイル名であればワイルドカードを用いた指定ができるので、末尾にタイムスタンプが入ったログなどをまとめて取得する際などに便利に活用できます。試しに下記でメイン関数のリモートパスにアスタリスク(*)を指定してみます。
def main():
host = "127.0.0.1"
user = "pecorimaru"
password = "Cnetuser"
remote_path = "/tmp/テスト*.pdf"
local_path = "E:\\data\\Documents\\SE\\Git\\Python\\jidoca312\\data\\fl01\\jd01\\"
download_remote_file(host, user, password, remote_path, local_path)
return
リモートパス
Pythonスクリプトを実行
PS E:\data\Documents\SE\Git\Python\jidoca312\src\fl01\jd01> python .\remotetest.py
サーバを探索中・・・
サーバに接続しています・・・
認証しています・・・
ユーザ名"pecorimaru" を使用中
入力済みパスワードで認証中
認証されました
セッションを開始しています・・・
セッションを開始しました
アクティブ セッション: [1] pecorimaru@127.0.0.1
テスト_20240819.pdf | 292 KB | 5657.9 KB/s | binary | 100%
テスト.pdf | 292 KB | 7083.5 KB/s | binary | 100%
テスト_20240818.pdf | 292 KB | 2252.7 KB/s | binary | 100%
returncode:0
ワイルドカードを用いて複数件ダウンロードする場合にファイル名の指定はできません。成功はしますが、どれか1ファイルに全て上書きされます。
複数ファイルをダウンロードした後の処理
複数ファイルをダウンロードした場合、globライブラリをインポートしてパスリストを取得して後続処理すると良いでしょう。
import glob
def main():
host = "127.0.0.1"
user = "pecorimaru"
password = "Cnetuser"
remote_path = "/tmp/テスト*.pdf"
local_path = "E:\\data\\Documents\\SE\\Git\\Python\\jidoca312\\data\\fl01\\jd01\\"
download_remote_file(host, user, password, remote_path, local_path)
# ダウンロードファイルのパスリストを取得
path_list = glob.glob(local_path + "*")
for path in path_list:
print(path)
return
実行結果
PS E:\data\Documents\SE\Git\Python\jidoca312\src\fl01\jd01> python .\remotetest.py
サーバを探索中・・・
サーバに接続しています・・・
認証しています・・・
ユーザ名"pecorimaru" を使用中
入力済みパスワードで認証中
認証されました
セッションを開始しています・・・
セッションを開始しました
アクティブ セッション: [1] pecorimaru@127.0.0.1
テスト_20240819.pdf | 292 KB | 3336.7 KB/s | binary | 100%
テスト.pdf | 292 KB | 3541.8 KB/s | binary | 100%
テスト_20240818.pdf | 292 KB | 3187.8 KB/s | binary | 100%
returncode:0
E:\data\Documents\SE\Git\Python\jidoca312\data\fl01\jd01\テスト.pdf
E:\data\Documents\SE\Git\Python\jidoca312\data\fl01\jd01\テスト_20240818.pdf
E:\data\Documents\SE\Git\Python\jidoca312\data\fl01\jd01\テスト_20240819.pdf