PythonでFTPによるファイルダウンロードを行う方法
PythonでFTPによるファイルダウンロードを行う方法をご紹介します。
目次
条件
- Python 3.7.0
サンプルソース
以下がFTP接続して指定ファイルをダウンロードするサンプルです。
import ftplib from logging import getLogger, StreamHandler, Formatter, DEBUG ## ログ出力設定 logger = getLogger("FTP Test") logger.setLevel(DEBUG) stream_handler = StreamHandler() stream_handler.setLevel(DEBUG) formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) ## FTP情報 HOST = 'XXX.com' PORT = 21 USER = 'userName' PASSWORD = 'password' DIRECTORY = 'test' ## 取得するファイル名の生成 FILE_NAME = 'test.csv' ## FTP接続、csvファイル取得 logger.debug('== Start FTP ==') with ftplib.FTP() as ftp: try: ftp.connect(HOST, PORT) # ホスト、ポートを指定して接続 ftp.login(USER, PASSWORD) # ユーザID、パスワードを指定してログイン ftp.cwd(DIRECTORY) # 指定のディレクトリに移動 with open(FILE_NAME, 'wb') as f: ftp.retrbinary('RETR ' + FILE_NAME, f.write) # 対象ファイルをバイナリ転送モードで取得 except ftplib.all_errors as e: logger.error('FTP error = %s' % e) else: logger.debug('FTP success.') logger.debug('== End FTP ==')
処理の流れ
- 処理の流れは以下の通りです。
- 対象ホストに接続
- 対象ホストにログイン
- 指定のディレクトリに移動
- 対象ファイルをダウンロード
解説
- ftplibを用いてFTP接続を行っています。
- withと共に使用することで、明示的にquit()を記述しなくてもftp接続を閉じることが出来ます。
- ftp.connectでは、「接続先ホスト」と「ポート」を指定して接続を行っています。
- ftp.loginでは、「ユーザID」と「パスワード」を指定してログインを行っています。
- ftp.retrbinaryでは、対象ファイルをバイナリ転送モードでダウンロードしています。
(バイナリ転送モードは、画像などのバイナリファイル取得や、テキストファイルの改行コード変換を行わずに取得したい場合に使用します。) - except ftplib.all_errors as e:では、FTP接続で発生する全ての例外を捕獲できます。
詳細エラーは以下のような種類があります。ftplib.
error_reply:サーバから想定外の応答があったときに送出される例外。
ftplib.
error_temp:一時的エラーを表すエラーコード(400–499の範囲の応答コード)を受け取った時に発生する例外。
ftplib.
error_perm:永久エラーを表すエラーコード(500–599の範囲の応答コード)を受け取った時に発生する例外。
ftplib.
error_proto:File Transfer Protocol の応答仕様に適合しない、すなわち1–5の数字で始まらない応答コードをサーバから受け取った時に発生する例外。
サーバー側の設定がおかしい場合の回避策
FTP接続を行うサーバー側の設定がおかしくて、「FTP接続は出来るけれどもデータが取得できない」という状況に出くわす場合があります。
詳細は以下の記事をご参照ください。
回避策ソース
以下のような記述を追記します。
from ftplib import FTP ## ネットワーク設定問題の回避策 _old_makepasv = FTP.makepasv def _new_makepasv(self): HOST, PORT = _old_makepasv(self) HOST = self.sock.getpeername()[0] return HOST, PORT FTP.makepasv = _new_makepasv
回避策を含めた全体ソース
全体のソースは以下のようになります。
from ftplib import FTP import ftplib from logging import getLogger, StreamHandler, Formatter, DEBUG ## ログ出力設定 logger = getLogger("FTP Test") logger.setLevel(DEBUG) stream_handler = StreamHandler() stream_handler.setLevel(DEBUG) formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) ## FTP情報 HOST = 'XXX.com' PORT = 21 USER = 'userName' PASSWORD = 'password' DIRECTORY = 'test' ## 取得するファイル名の生成 FILE_NAME = 'test.csv' ## ネットワーク設定問題の回避策 _old_makepasv = FTP.makepasv def _new_makepasv(self): HOST, PORT = _old_makepasv(self) HOST = self.sock.getpeername()[0] return HOST, PORT FTP.makepasv = _new_makepasv ## FTP接続、csvファイル取得 logger.debug('== Start FTP ==') with FTP() as ftp: try: ftp.connect(HOST, PORT) # ホスト、ポートを指定して接続 ftp.login(USER, PASSWORD) # ユーザID、パスワードを指定してログイン ftp.cwd(DIRECTORY) # 指定のディレクトリに移動 with open(FILE_NAME, 'wb') as f: ftp.retrbinary('RETR ' + FILE_NAME, f.write) # 対象ファイルをバイナリ転送モードで取得 except ftplib.all_errors as e: logger.error('FTP error = %s' % e) else: logger.debug('FTP success.') logger.debug('== End FTP ==')
参考
Python:ftplib
— FTPプロトコルクライアント
https://docs.python.jp/3/library/ftplib.html