web-dev-qa-db-ja.com

Python-FTPはディレクトリ内のすべてのファイルをダウンロードします

FTP経由でディレクトリからすべてのファイルをダウンロードするスクリプトをまとめています。これまでのところ、1つのファイルを接続して取得することはできましたが、バッチで動作するようには思えません(ディレクトリからすべてのファイルを取得する)。

from ftplib import FTP
import os, sys, os.path

def handleDownload(block):
    file.write(block)
    print ".",

ddir='C:\\Data\\test\\'
os.chdir(ddir)
ftp = FTP('test1/server/')

print 'Logging in.'
ftp.login('user1\\anon', 'pswrd20')
directory = '\\data\\test\\'

print 'Changing to ' + directory
ftp.cwd(directory)
ftp.retrlines('LIST')

print 'Accessing files'

for subdir, dirs, files in os.walk(directory):
    for file in files: 
        full_fname = os.path.join(root, fname);  
        print 'Opening local file ' 
        ftp.retrbinary('RETR C:\\Data\\test\\' + fname,
                       handleDownload,
                       open(full_fname, 'wb'));
        print 'Closing file ' + filename
        file.close();
ftp.close()

実行してもあまり効果がないことがわかると思いますので、改善のための提案は大歓迎です。

26
Sosti

私はこれをクラックすることができたので、将来の訪問者のために関連するコードを投稿します:

filenames = ftp.nlst() # get filenames within the directory
print filenames

for filename in filenames:
    local_filename = os.path.join('C:\\test\\', filename)
    file = open(local_filename, 'wb')
    ftp.retrbinary('RETR '+ filename, file.write)

    file.close()

ftp.quit() # This is the “polite” way to close a connection

これはPython 2.5、Windows XPで機能しました。

64
Sosti

これが単にあなたが解決したい問題であるなら、私はwgetコマンドを提案するかもしれません:

_cd c:\destination
wget --mirror --continue --no-Host-directories --user=username --password=s3cr3t ftp://hostname/source/path/
_

_--continue_オプションは、サーバー上のファイルchangeの場合、非常に危険です。ファイルがaddedのみの場合、非常にフレンドリーです。

ただし、これが学習課題であり、プログラムを機能させたい場合は、次の行を確認することから始めてください。

_for subdir, dirs, files in os.walk(directory):
_

directoryはほとんどのプログラムでremoteソースディレクトリでしたが、os.walk()関数はをウォークできませんremoteディレクトリ。 retrlines 関数に提供されたコールバックを使用して、返されたファイルを自分で繰り返す必要があります。

MLSDの代わりにNLSTまたはLISTオプションを見てください。おそらく、それらは解析しやすいでしょう。 (FTPはリストの表示方法を実際に指定しないことに注意してください。コンソールで人間が操作するか、特定のファイル名を転送することを常に意図していました。 GUIは、奇妙なサーバーや不明瞭なサーバーのために、おそらく特別なケースコードの膨大な山を持たなければなりません。そして、それらはすべて、悪意のあるファイル名に直面したとき、おそらく愚かなことをします。

代わりに sftp を使用できますか? sftpdoesには、ファイル一覧の解析方法に関する仕様があり、ユーザー名/パスワードを平文で送信せず、巨人がいませんパッシブ接続とアクティブ接続の煩わしさ-単一の接続を使用するだけです。つまり、FTPよりも多くのファイアウォールで機能します。

Edit: 'callable'オブジェクトをretrlines関数に渡す必要があります。呼び出し可能オブジェクトは、___call___メソッドを定義したクラスのインスタンス、または関数のいずれかです。関数の記述は簡単かもしれませんが、クラスのインスタンスの方が便利な場合があります。 (インスタンスを使用してファイル名を収集できますが、関数はグローバル変数に書き込む必要があります。悪い。)

最も単純な呼び出し可能オブジェクトの1つを次に示します。

_>>> class c:
...  def __call__(self, *args):
...   print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')
_

これにより、インスタンスメソッド___call___を定義する新しいクラスcが作成されます。これは引数をかなり馬鹿げた方法で表示するだけですが、私たちが話している最小限度を示しています。 :)

よりスマートなものが必要な場合は、次のようなことができます。

_class handle_lines:
  def __init__(self):
    self.lines = []
  def __call__(self, *args):
    self.lines << args[0]
_

このクラスのオブジェクトでiterlinesを呼び出してから、オブジェクトのlinesメンバーで詳細を確認します。

7
sarnold

このコードはちょっとやり過ぎだと思います。

(python例 https://docs.python.org/2/library/ftplib.html から)ftp.login()およびftp.cwdの設定後()ただ使用できます:

os.chdir(ddir)
ls = ftp.nlst()
count = len(ls)
curr = 0
print "found {} files".format(count)
for fn in ls:
    curr += 1
    print 'Processing file {} ... {} of {} ...'.format(fn, curr, count)
    ftp.retrbinary('RETR ' + fn, open(fn, 'wb').write)

ftp.quit()
print "download complete."

すべてのファイルをダウンロードします。

3
kztd

再帰的ソリューション(py 2.7):

import os, ftplib, shutil, operator

def cloneFTP((addr, user, passw), remote, local):
    try:
        ftp = ftplib.FTP(addr)
        ftp.login(user, passw)
        ftp.cwd(remote)
    except: 
        try: ftp.quit()
        except: pass
        print 'Invalid input ftp data!'
        return False
    try: shutil.rmtree(local)
    except: pass
    try: os.makedirs(local)
    except: pass
    dirs = []
    for filename in ftp.nlst():
        try:
            ftp.size(filename)
            ftp.retrbinary('RETR '+ filename, open(os.path.join(local, filename), 'wb').write)
        except:
            dirs.append(filename)
    ftp.quit()
    res = map(lambda d: cloneFTP((addr, user, passw), os.path.join(remote, d), os.path.join(local, d)), dirs)
    return reduce(operator.iand, res, True)
0
Iulian Bute

私は初心者なので、コードを効率的に作成していませんが、作成し、動作することをテストしました。これは、ftpサイトからファイルやフォルダーをダウンロードするためにやったことですが、ファイル構造の深さは限られています。

try:
   a = input("Enter hostname : ")
   b = input("Enter username : ")
   c = input("Enter password : ")
   from ftplib import FTP
   import os
   os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
   os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
   ftp = FTP(Host = a, user= b, passwd = c)
   D = ftp.nlst()
   for d in D:
      l = len(d)
      char = False
      for i in range(0,l):
          char = char or d[i]=="."
      if not char:
         ftp.cwd("..")
         ftp.cwd("..")
         E = ftp.nlst("%s"%(d))
         ftp.cwd("%s"%(d))
         try:
             os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
         except:
             print("you can debug if you try some more")
         finally:
             os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
             for e in E:
                l1 = len(e)
                char1 = False
                for i in range(0,l1):
                   char1 = char1 or e[i]=="."
                if not char1:
                   ftp.cwd("..")
                   ftp.cwd("..")
                   F = ftp.nlst("%s/%s"%(d,e))
                   ftp.cwd("%s/%s"%(d,e))
                   try:
                       os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s"%(d,e))
                   except:
                       print("you can debug if you try some more")
                   finally:
                       os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s"%(d,e))
                       for f in F:
                           if "." in f[2:]:
                               with open(f,'wb') as filef:
                                   ftp.retrbinary('RETR %s' %(f), filef.write)
                           Elif not "." in f:
                               try:
                                  os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s\\%s"%(d,e,f))
                               except:
                                  print("you can debug if you try some more")
                Elif "." in e[2:]:
                   os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
                   ftp.cwd("..")
                   ftp.cwd("..")
                   ftp.cwd("..")
                   ftp.cwd("%s"%(d))
                   with open(e,'wb') as filee:
                      ftp.retrbinary('RETR %s' %(e), filee.write)
      Elif "." in d[2:]:
          ftp.cwd("..")
          ftp.cwd("..")
          os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
          with open(d,'wb') as filed:
             ftp.retrbinary('RETR %s'%(d), filed.write)
   ftp.close()
   print("Your files has been successfully downloaded and saved. Bye")
except:
    print("try again you can do it")
finally:
    print("code ran")
0
PremVijay