Python ftplib.FTP.connect()徹底解説:基本から高度な使い方まで

2025-06-06

ftplib.FTP.connect() とは

ftplib.FTP.connect(host='', port=0, timeout=-999)

このメソッドは、指定されたホストとポート番号でFTPサーバーへの接続を試みます。

  • timeout (オプション): 接続試行のタイムアウト時間を秒単位で指定します。指定しない場合、システムのデフォルトのタイムアウトが使用されます。
  • port (オプション): 接続先のポート番号を整数で指定します。デフォルトはFTPの標準ポートである 21 です。
  • host (必須): 接続先のFTPサーバーのホスト名またはIPアドレスを文字列で指定します。例えば、'ftp.example.com''192.168.1.1' などです。

どのように機能するか

  1. TCP接続の確立: connect() メソッドは、まず指定されたホストとポートに対してTCP接続を確立しようとします。これは、FTP通信の基盤となるソケット接続です。
  2. 成功と失敗:
    • 接続に成功した場合、メソッドは何も返しません(None を返します)。
    • 接続に失敗した場合(例えば、ホストが見つからない、ポートが閉じている、ネットワークの問題など)、socket.error 例外が送出されます。
  3. 注意点: connect() メソッドは接続を確立するだけで、ユーザー認証(ログイン)は行いません。認証には、後述の login() メソッドを使用する必要があります。
from ftplib import FTP
import socket

ftp = FTP()  # FTPオブジェクトを作成

try:
    # FTPサーバーに接続を試みる
    # ここでは例として 'ftp.mozilla.org' を使用します。
    # 実際の環境に合わせて適切なホスト名に置き換えてください。
    ftp.connect('ftp.mozilla.org', 21)
    print("FTPサーバーに接続しました。")

    # 接続後、ログインなどの操作を行う
    # 例: 匿名ログイン
    ftp.login()
    print("匿名でログインしました。")

    # その他の操作... (例: ファイルリストの取得)
    print("ファイルリスト:")
    ftp.dir()

except socket.error as e:
    print(f"接続エラーが発生しました: {e}")
except Exception as e:
    print(f"その他のエラーが発生しました: {e}")
finally:
    # 接続が確立されていれば、必ずクローズする
    if ftp.sock: # ソケットが存在するかどうかを確認
        ftp.quit()
        print("FTP接続をクローズしました。")


socket.gaierror: [Errno 8] nodename nor servname provided, or not known (または getaddrinfo failed)

エラーの内容
指定されたホスト名(サーバー名)をIPアドレスに解決できない場合に発生します。これはDNSルックアップの失敗を示唆しています。

考えられる原因とトラブルシューティング

  • インターネット接続の問題
    • 基本的なインターネット接続があるか確認してください。ウェブブラウザで他のサイトにアクセスできるかなどを試します。
  • FTPサーバーが存在しない、または停止している
    • 指定したFTPサーバーが実際に稼働しているか、またはサービスが提供されているか確認してください。サーバー管理者やサービスプロバイダに問い合わせるのが最も確実です。
  • DNS解決の問題
    • あなたのコンピュータがそのホスト名を解決できるか確認してください。コマンドプロンプトやターミナルで ping ftp.example.comnslookup ftp.example.com を実行して、IPアドレスが返されるか確認します。
    • もし解決できない場合、DNSサーバーの設定に問題があるか、インターネット接続がない可能性があります。
  • ホスト名の入力ミス
    • FTPサーバーのホスト名(例: 'ftp.example.com')が正しく入力されているか確認してください。タイプミスがないかよく見直しましょう。

ConnectionRefusedError: [Errno 111] Connection refused (または [WinError 10061] Connection refused)

エラーの内容
指定されたホストとポートに接続しようとしたが、相手側(FTPサーバー)が接続を拒否したことを示します。

考えられる原因とトラブルシューティング

  • SFTP/FTPSとの混同
    • ftplib は通常のFTPプロトコルを扱います。SFTP (SSH File Transfer Protocol) や FTPS (FTP over SSL/TLS) は異なるプロトコルであり、ftplib では直接扱えません。
      • SFTPの場合
        paramiko などのSSHライブラリを使用する必要があります。SFTPは通常ポート 22 を使用します。
      • FTPS (Implicit FTPS) の場合
        ポート 990 を使用し、接続自体がTLSで保護されます。ftplib.FTP_TLS クラスを使用する必要があります。
      • FTPS (Explicit FTPS) の場合
        通常ポート 21 を使用しますが、接続後に明示的にTLSセッションを開始する必要があります。これも ftplib.FTP_TLS を使用します。
  • FTPサーバーが最大接続数に達している
    • サーバーが同時に受け入れられる接続数の上限に達している場合、新しい接続が拒否されることがあります。
  • IPアドレスの制限
    • FTPサーバーが特定のIPアドレスからの接続のみを許可している場合があります。あなたのIPアドレスが許可リストに含まれているか確認してください。
  • ファイアウォールによるブロック
    • クライアント側(あなたのコンピュータ)のファイアウォールがFTP接続をブロックしている可能性があります。一時的にファイアウォールを無効にして試すか、FTPのポート(デフォルトは21)を許可するように設定します。
    • サーバー側のファイアウォールがあなたのIPアドレスからの接続を拒否している可能性もあります。サーバー管理者に確認が必要です。
  • 指定したポートが間違っている
    • FTPの標準ポートは 21 ですが、サーバーによっては異なるポートを使用している場合があります。正しいポート番号を指定しているか確認してください。
  • FTPサーバーが起動していない
    • FTPサーバーのプロセスが停止している可能性があります。サーバー管理者に確認してください。

TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

エラーの内容
接続を試みたが、指定されたタイムアウト時間内にサーバーからの応答がなかったことを示します。接続が確立できなかったか、非常に遅延している可能性があります。

考えられる原因とトラブルシューティング

  • 経路上の問題
    • クライアントとサーバー間のネットワーク経路に問題がある可能性があります。traceroute (Linux/macOS) や tracert (Windows) コマンドで経路を確認してみるのも有効です。
  • FTPサーバーが過負荷または応答不能
    • サーバーが一時的に応答できない状態にある可能性があります。しばらく待ってから再試行するか、サーバー管理者に連絡してください。
  • ファイアウォールによるブロック
    • ConnectionRefusedError と同様に、ファイアウォールが接続を途中で遮断している可能性があります。
  • ホスト名またはIPアドレスの入力ミス
    • 上記 socket.gaierror と同様に、ホスト名が間違っているが、DNS解決は成功し、間違ったIPアドレスに接続を試みてタイムアウトしている可能性があります。
  • ネットワークの遅延または不安定さ
    • インターネット接続が遅い、または不安定な場合、タイムアウトが発生することがあります。より安定したネットワーク環境で試すか、タイムアウト時間を長く設定してみてください。
      ftp = FTP()
      ftp.connect('ftp.example.com', 21, timeout=30) # 30秒に設定
      

エラーの内容
connect() メソッドに host 引数が指定されていない場合に発生します。

  • 引数の渡し忘れ
    • ftp.connect() を呼び出す際に、必ずホスト名を引数として渡してください。
      # 誤り
      # ftp.connect()
      
      # 正しい
      ftp.connect('ftp.example.com')
      
  • パッシブモード (Passive Mode) の確認
    ftplib はデフォルトでパッシブモードを使用します。多くのファイアウォール環境ではパッシブモードが推奨されますが、サーバーの設定によってはアクティブモードが必要な場合や、パッシブモードでのデータ接続に問題がある場合があります。 特にデータ転送(retrlines, storbinary など)でタイムアウトや接続エラーが発生する場合は、パッシブモードが原因である可能性があります。ftp.set_pasv(False) を呼び出してアクティブモードを試すこともできますが、通常はあまり推奨されません。

  • 別のFTPクライアントで確認
    FileZillaなどのGUIベースのFTPクライアントや、コマンドラインの ftp コマンドを使用して、同じFTPサーバーに接続できるか試してください。これにより、Pythonスクリプト側の問題なのか、ネットワークやサーバー側の問題なのかを切り分けることができます。

  • デバッグレベルの設定
    ftplib はデバッグ情報を出力する機能を持っています。これを活用すると、サーバーとの通信の詳細を見ることができます。

    import ftplib
    import sys
    
    ftp = ftplib.FTP()
    ftp.set_debuglevel(2) # デバッグレベルを2に設定 (詳細な通信ログが出力される)
    
    # 出力先を標準エラーにする場合は以下
    # ftp.set_debuglevel(1, sys.stderr)
    
    try:
        ftp.connect('ftp.example.com')
        # ...
    except Exception as e:
        print(f"エラー: {e}")
    finally:
        if ftp.sock:
            ftp.quit()
    

    デバッグレベルを高く設定すると、FTPコマンドとサーバー応答がコンソールに表示され、問題の切り分けに役立ちます。



基本的な接続例

最もシンプルなftplib.FTP.connect() の使用例です。接続が成功した場合にメッセージを表示します。

from ftplib import FTP

# FTPオブジェクトを作成
ftp = FTP()

try:
    # FTPサーバーに接続
    # 接続先のホスト名とポート番号を指定します
    # ここでは例として 'ftp.mozilla.org' を使用しますが、
    # 実際には接続したいFTPサーバーの情報を指定してください。
    print("FTPサーバーへの接続を試みています...")
    ftp.connect('ftp.mozilla.org', 21)
    print("FTPサーバーに接続しました!")

    # 接続後、ログイン(匿名ログインの例)
    print("匿名でログインを試みています...")
    ftp.login()
    print("ログインに成功しました。")

    # ログイン後の操作(例: カレントディレクトリの表示)
    current_dir = ftp.pwd()
    print(f"現在のディレクトリ: {current_dir}")

except Exception as e:
    # 接続またはログイン中にエラーが発生した場合
    print(f"エラーが発生しました: {e}")

finally:
    # 接続が確立されていれば、必ずクローズする
    if ftp.sock: # ソケットが存在するかどうかを確認
        print("FTP接続をクローズしています...")
        ftp.quit()
        print("FTP接続をクローズしました。")

解説

  • try...except...finally ブロック:
    • try: 接続とログインのコードを囲み、エラーが発生する可能性のある処理を保護します。
    • except Exception as e: 何らかのエラーが発生した場合にそれを捕捉し、エラーメッセージを表示します。socket.errorftplib.all_errors などのより具体的な例外を捕捉することも可能ですが、ここでは汎用的に Exception を使用しています。
    • finally: try ブロックの成功/失敗にかかわらず、必ず実行されるコードです。ここでは、確立されたFTP接続を ftp.quit() で安全にクローズしています。ftp.sock でソケットが確立されているか確認することで、未接続の状態で quit() を呼び出すことを防いでいます。
  • ftp.pwd(): ログイン後に現在の作業ディレクトリを取得する例です。
  • ftp.login(): 接続が確立された後、FTPサーバーにログインします。引数を指定しない場合、匿名ログイン (username='anonymous', password='') が試みられます。
  • ftp.connect('ftp.mozilla.org', 21): 指定されたホスト ('ftp.mozilla.org') のポート 21 (FTPの標準ポート) に接続を試みます。成功すると、ソケット接続が確立されます。
  • ftp = FTP(): FTP クラスのインスタンスを作成します。この時点ではまだ何も接続されていません。

タイムアウト設定とエラーハンドリングの例

接続時のタイムアウトを設定し、より具体的なエラーハンドリングを行う例です。ネットワークの問題などで接続が遅延する場合に役立ちます。

from ftplib import FTP, all_errors
import socket

# FTPオブジェクトを作成
ftp = FTP()

# 接続先の情報
HOST = 'ftp.example.com'  # 実際には有効なホスト名に置き換えてください
PORT = 21
TIMEOUT = 10  # タイムアウトを10秒に設定

print(f"FTPサーバー ({HOST}:{PORT}) への接続を試みています (タイムアウト: {TIMEOUT}秒)...")

try:
    # タイムアウトを指定して接続
    ftp.connect(HOST, PORT, TIMEOUT)
    print("FTPサーバーに接続しました!")

    # ログイン
    ftp.login('your_username', 'your_password') # 実際のユーザー名とパスワードに置き換えてください
    print("ログインに成功しました。")

    # ファイルリストの取得など、FTP操作
    print("\nファイルリスト:")
    files = []
    ftp.dir(files.append) # ディレクトリの内容をリストに取得
    for f in files:
        print(f)

except socket.timeout:
    print(f"エラー: 接続がタイムアウトしました。{TIMEOUT}秒以内にサーバーからの応答がありませんでした。")
    print("ネットワークが遅いか、サーバーが応答していません。")
except socket.gaierror:
    print(f"エラー: ホスト名 '{HOST}' を解決できませんでした。入力ミスがないか確認してください。")
except socket.error as e:
    print(f"エラー: ネットワークまたは接続の問題が発生しました: {e}")
except all_errors as e:
    # ftplib固有のエラー (例: ログイン失敗など)
    print(f"FTP操作中にエラーが発生しました: {e}")
except Exception as e:
    # その他の予期せぬエラー
    print(f"予期せぬエラーが発生しました: {e}")

finally:
    if ftp.sock:
        print("FTP接続をクローズしています...")
        ftp.quit()
        print("FTP接続をクローズしました。")

解説

  • ftp.dir(files.append): ディレクトリの内容をリストに格納する例です。dir() メソッドにコールバック関数を渡すと、各行がその関数に渡されます。
  • ftp.connect(HOST, PORT, TIMEOUT): タイムアウト値を引数として渡すことで、指定された時間内に接続が確立されなかった場合に socket.timeout 例外が送出されます。
  • TIMEOUT = 10: connect() メソッドに渡すタイムアウト値を定義しています。

通常のFTPはデータを暗号化しませんが、ftplib.FTP_TLS を使用することでFTPS (FTP over SSL/TLS) によるセキュアな接続が可能です。

from ftplib import FTP_TLS, all_errors
import socket
import ssl # SSL/TLS関連のエラーハンドリングのためにインポート

# FTPSオブジェクトを作成
ftp_tls = None # finallyブロックで参照できるように初期化

# 接続先の情報 (FTPSサーバーに置き換えてください)
# Implicit FTPSの場合ポート990、Explicit FTPSの場合ポート21を使用することが多いです。
# ここではExplicit FTPSの例としてポート21を使用し、後でTLSを開始します。
HOST = 'ftp.example.com'  # 実際にはFTPS対応のホスト名に置き換えてください
PORT = 21 # または 990 (Implicit FTPSの場合)
TIMEOUT = 15

print(f"FTPSサーバー ({HOST}:{PORT}) へのセキュアな接続を試みています...")

try:
    ftp_tls = FTP_TLS()
    ftp_tls.set_debuglevel(1) # デバッグレベルを設定すると通信内容が見やすくなります

    # 接続 (FTPと同じ)
    ftp_tls.connect(HOST, PORT, TIMEOUT)
    print("サーバーに接続しました。")

    # TLSハンドシェイクを開始し、セキュアな制御チャネルを確立
    # Explicit FTPSの場合、このコマンドを実行します
    ftp_tls.auth() # または ftp_tls.auth('TLS') / ftp_tls.auth('SSL')
    ftp_tls.prot_p() # データチャネルも保護 (PORT/PASVコマンド後に有効)

    print("TLSハンドシェイクに成功し、セキュアなチャネルを確立しました。")

    # ログイン
    ftp_tls.login('your_username', 'your_password') # 実際のユーザー名とパスワードに置き換えてください
    print("ログインに成功しました。")

    # セキュアなデータ転送(例: ファイルリストの取得)
    print("\nセキュアなファイルリスト:")
    ftp_tls.dir()

except socket.timeout:
    print(f"エラー: 接続がタイムアウトしました。{TIMEOUT}秒以内にサーバーからの応答がありませんでした。")
except socket.gaierror:
    print(f"エラー: ホスト名 '{HOST}' を解決できませんでした。入力ミスがないか確認してください。")
except (socket.error, ssl.SSLError) as e: # socket.error と SSL関連のエラーを捕捉
    print(f"エラー: ネットワークまたはSSL/TLS接続の問題が発生しました: {e}")
    print("ポート番号が正しいか、サーバーがFTPSに対応しているか確認してください。")
except all_errors as e:
    print(f"FTPS操作中にエラーが発生しました: {e}")
except Exception as e:
    print(f"予期せぬエラーが発生しました: {e}")

finally:
    if ftp_tls and ftp_tls.sock:
        print("FTPS接続をクローズしています...")
        ftp_tls.quit()
        print("FTPS接続をクローズしました。")
  • ssl.SSLError: TLSハンドシェイク中に発生する可能性のあるエラーを捕捉するために、ssl モジュールからこの例外をインポートし、socket.error と共に捕捉しています。
  • ftp_tls.prot_p(): データチャネル(ファイル転送用)も暗号化することをサーバーに伝えます。これを実行しないと、制御チャネルは暗号化されても、データチャネルは暗号化されない場合があります。
  • ftp_tls.auth(): これがFTPSの重要なステップです。制御チャネルでTLSハンドシェイクを開始し、暗号化された通信を確立します。サーバーが対応している認証メカニズム(AUTH TLS/SSL)によって、auth('TLS')auth('SSL') が必要になる場合もありますが、auth() のみで自動的に適切な方法が選択されることが多いです。
  • ftp_tls.connect(HOST, PORT, TIMEOUT): 通常のFTPと同様に接続します。
  • ftp_tls = FTP_TLS(): FTP_TLS のインスタンスを作成します。
  • from ftplib import FTP_TLS: FTP_TLS クラスをインポートします。


ftplib.FTP_TLS を使用したFTPS接続 (Implicit/Explicit FTPS)

これは ftplib モジュール内での「代替」というよりは、「よりセキュアなバージョン」です。FTP自体は平文でデータをやり取りするため、セキュリティ上の懸念があります。FTPS (FTP Secure) はSSL/TLSを利用して通信を暗号化します。

特徴

  • Explicit FTPS (FTPES): 通常ポート21を使用し、接続後に明示的に AUTH TLS コマンドを発行してTLSハンドシェイクを開始します。これがより一般的です。
  • Implicit FTPS: 通常ポート990を使用し、接続開始時からTLSハンドシェイクが行われます。
  • SSL/TLS暗号化: 制御チャネルとデータチャネルの両方を暗号化できます。
  • ftplib モジュールの一部: 別途インストールは不要です。

ftplib.FTP.connect() との違い
connect() の呼び出し方は同じですが、接続後に auth()prot_p() などのメソッドを呼び出してTLSセッションを確立する必要があります。

コード例(Explicit FTPS)

from ftplib import FTP_TLS
import socket
import ssl

HOST = 'your_ftps_server.com' # FTPSサーバーのホスト名
PORT = 21 # Explicit FTPSのデフォルトポート
USERNAME = 'your_username'
PASSWORD = 'your_password'

ftp = None
try:
    ftp = FTP_TLS()
    ftp.set_debuglevel(1) # デバッグ出力を有効にすると詳細が見えます

    print(f"FTPSサーバー {HOST}:{PORT} に接続を試みています...")
    ftp.connect(HOST, PORT)
    print("サーバーに接続しました。TLSハンドシェイクを開始します...")

    # Explicit FTPS: AUTH TLS コマンドでTLSハンドシェイクを開始
    ftp.auth() # サーバーがAUTH TLSに対応していればこれでOK
    # ftp.auth('TLS') # 明示的に指定する場合
    # ftp.auth('SSL') # 古いサーバーの場合

    # データチャネルも保護する (必須ではないが推奨)
    ftp.prot_p()
    print("TLSハンドシェイクとデータ保護設定が完了しました。")

    print("ログインを試みています...")
    ftp.login(USERNAME, PASSWORD)
    print("ログインに成功しました。")

    print("\nファイルリスト:")
    ftp.dir()

except (socket.gaierror, socket.timeout, socket.error, ssl.SSLError) as e:
    print(f"FTPS接続エラー: {e}")
except Exception as e:
    print(f"その他のエラー: {e}")
finally:
    if ftp and ftp.sock:
        print("FTPS接続をクローズしています...")
        ftp.quit()
        print("FTPS接続をクローズしました。")

paramiko ライブラリを使用したSFTP接続 (SSH経由のファイル転送)

これはFTPとは全く異なるプロトコルですが、ファイル転送の目的でFTPの代替として頻繁に使用されます。SFTP (SSH File Transfer Protocol) はSSHプロトコル上で動作し、常に暗号化されています。

特徴

  • 機能豊富: SSH接続、コマンド実行、ポートフォワーディングなど、FTPにはない機能も提供します。
  • インストールが必要: pip install paramiko
  • 常にセキュア: デフォルトで暗号化されています。
  • SSHベース: SSH認証(パスワード、SSHキー)を使用します。

ftplib.FTP.connect() との違い
paramikoftplib とは全く異なるAPIを持っています。SSHクライアントを確立し、そのクライアントからSFTPクライアントを取得して操作します。

コード例(SFTP)

import paramiko

HOSTNAME = 'your_sftp_server.com' # SFTPサーバーのホスト名
PORT = 22 # SFTPのデフォルトポート (SSHと同じ)
USERNAME = 'your_sftp_username'
PASSWORD = 'your_sftp_password'
# またはプライベートキーを使用する場合
# PRIVATE_KEY_PATH = '/path/to/your/private_key'

transport = None
sftp = None
try:
    # SSHトランスポート層を確立
    transport = paramiko.Transport((HOSTNAME, PORT))
    print(f"SFTPサーバー {HOSTNAME}:{PORT} に接続を試みています...")

    # 認証
    # パスワード認証
    transport.connect(username=USERNAME, password=PASSWORD)
    # キー認証 (例)
    # private_key = paramiko.RSAKey.from_private_key_file(PRIVATE_KEY_PATH)
    # transport.connect(username=USERNAME, pkey=private_key)

    print("SSH接続を確立しました。SFTPクライアントを作成します...")
    sftp = paramiko.SFTPClient.from_transport(transport)
    print("SFTPクライアントを作成しました。")

    # SFTP操作
    print("\nファイルリスト:")
    for entry in sftp.listdir():
        print(entry)

    # 例: ファイルのアップロード
    # sftp.put('local_file.txt', 'remote_file.txt')
    # 例: ファイルのダウンロード
    # sftp.get('remote_file.txt', 'local_download.txt')

except paramiko.AuthenticationException:
    print("SFTP認証エラー: ユーザー名またはパスワードが間違っています。")
except paramiko.SSHException as e:
    print(f"SFTP接続エラー (SSH): {e}")
except Exception as e:
    print(f"その他のSFTPエラー: {e}")
finally:
    if sftp:
        print("SFTPセッションをクローズしています...")
        sftp.close()
    if transport:
        print("SSHトランスポートをクローズしています...")
        transport.close()
    print("SFTP接続をクローズしました。")

requests-ftp または同様のHTTPベースのファイル転送

これは直接的なFTPの代替というよりは、FTPサーバーがHTTP/HTTPS経由でのアクセスも許可している場合や、RESTful APIを提供している場合に有効なアプローチです。Pythonの有名なHTTPライブラリ requests を利用して、FTP URLを処理できるようにする requests-ftp のような拡張機能もあります。

特徴

  • 制限: すべてのFTPサーバーがHTTPアクセスを許可しているわけではありません。また、FTPの特定コマンド(例: SITE コマンド)には対応していません。
  • インストールが必要: pip install requests-ftp
  • 使い慣れたAPI: requests ライブラリのシンプルなAPIを利用できます。
  • HTTP/HTTPSプロトコル: FTPプロトコルを直接使用しません。

ftplib.FTP.connect() との違い
FTPサーバーに接続する代わりに、URLを指定してリソースを取得・送信します。

import requests
from requests_ftp import FtpAdapter

# FTPサーバーのURL
FTP_URL = 'ftp://your_ftp_username:your_ftp_password@your_ftp_server.com/path/to/directory/'

session = requests.Session()
session.mount('ftp://', FtpAdapter())

try:
    print(f"FTP URL {FTP_URL} からファイルリストを取得しようとしています...")
    response = session.get(FTP_URL)

    if response.status_code == 200:
        print("ファイルリストを正常に取得しました:")
        # FTPサーバーからのレスポンスは通常、LF区切りのテキスト
        print(response.text)
    else:
        print(f"エラー: HTTPステータスコード {response.status_code}")
        print(f"応答: {response.text}")

    # 例: ファイルのダウンロード (対応していれば)
    # response_file = session.get('ftp://your_ftp_username:your_ftp_password@your_ftp_server.com/path/to/file.txt')
    # if response_file.status_code == 200:
    #     with open('downloaded_file.txt', 'wb') as f:
    #         f.write(response_file.content)
    #     print("ファイルをダウンロードしました。")

except requests.exceptions.RequestException as e:
    print(f"requests-ftp エラー: {e}")
except Exception as e:
    print(f"その他のエラー: {e}")

finally:
    session.close() # セッションをクローズ
  • 既存のHTTPインフラを流用したい場合や、簡単な読み取りアクセスのみの場合

    • サーバーがHTTP/HTTPS経由でのアクセスを許可していれば、requests-ftp のような方法も検討できますが、これはFTPのフル機能が必要な場合には不向きです。
  • SSH接続が必要な場合

    • FTPサーバーではなく、SSHサーバー経由でファイル転送を行う場合は、迷わず paramiko を選択してください。
  • セキュアなFTPが必要な場合

    • FTPサーバーがFTPSに対応しているなら、ftplib.FTP_TLS を使うのが最も直接的です。
    • サーバーがSFTPに対応しているなら、paramiko を使うのが強く推奨されます。SFTPはFTPよりも現代的で安全なファイル転送プロトコルです。