2
3
paiza×Qiita記事投稿キャンペーン「プログラミング問題をやってみて書いたコードを投稿しよう!」

【Python】WinSCPスクリプトを利用してリモートPCのファイルをダウンロードする方法

Last updated at Posted at 2024-08-19

概要

Python×WinSCPスクリプトを利用することでリモート環境にあるファイルをローカル環境にダウンロードできます。paramikoという外部ライブラリを利用することでも実装できますが、今回は敢えてこの方法で紹介していきます。

実施環境

Windows11(Windows10でも可)
Python 3.12.4
WinSCP

実装方法

コードブロックを分けていますが、1本のファイルに記載して大丈夫です。

download_remote_file.py
import os
import subprocess
download_remote_file.py
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で指定するパスは基本的に「/」でも「\\」でも良いのですが、今回のローカルパスにおいては「\\」の指定が必須です。

download_remote_file.py
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のパスはコマンド内でダブルクォーテーション「"」で囲う必要があるため注意。上記は「"」を文字列として扱うように「\」でエスケープしています。

download_remote_file.py
if __name__ == "__main__":

    main()

実行

リモートパス

image.png

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は成功なので、ローカルパスにファイルがダウンロードされました。

image.png

リターンコード:0 以外で返ってくる場合は失敗しているので、コードを作り込む際はエラーハンドリングしておくと良いでしょう。

応用パターン

ローカルパスをファイル名まで指定することも可能

上記で紹介したコードではローカルパスはフォルダ名までを指定しましたが、ファイル名まで記載することでダウンロードするファイル名を指定することも可能です。

ファイル名はアスタリスク(*)を用いたワイルドカードの指定が可能

フォルダ名は不可ですが、ファイル名であればワイルドカードを用いた指定ができるので、末尾にタイムスタンプが入ったログなどをまとめて取得する際などに便利に活用できます。試しに下記でメイン関数のリモートパスにアスタリスク(*)を指定してみます。

download_remote_file.py
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

リモートパス

image.png

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ライブラリをインポートしてパスリストを取得して後続処理すると良いでしょう。

download_remote_file.py
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
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3