34

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()

私が実行したときはあまり効果がないことがわかると思いますので、改善のための提案をいただければ幸いです。

4

6 に答える 6

76

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

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 でうまくいきました。

于 2011-03-15T15:28:27.767 に答える
10

これが解決したい問題である場合は、次のwgetコマンドをお勧めします。

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

サーバー上でファイルが変更された場合、この--continueオプションは非常に危険です。ファイルが追加されるだけの場合は、非常に使いやすいです。

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

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

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

MLSDの代わりにまたはNLSTオプションを参照してくださいLIST。おそらく解析が容易になります。(FTP はリストがどのように表示されるかを実際に指定していないことに注意してください。これは常にコンソールで人間が操作すること、または特定のファイル名が転送されることを意図していました。 GUI は、奇妙なサーバーやあいまいなサーバーのために、特殊なケースのコードを大量に用意する必要があります.そして、悪意のあるファイル名に直面すると、それらはおそらく愚かなことをします.)

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

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

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

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

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

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

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

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

于 2011-03-08T10:27:59.380 に答える
-4

Python lib を使用してディレクトリを ftp ダウンロードする代わりに、python プログラムから dos スクリプトを呼び出すことができます。dos スクリプトでは、 を使用してフォルダからすべてのファイルをダウンロードできるネイティブ ftp プロトコルを使用しますmget *.*

fetch.bat
ftp -s:fetch.txt

fetch.txt
open <ipaddress>
<userid>
<password>
bin (set the mnode to binary)
cd </desired directory>
mget *.*
bye

fetch.py
import os
os.system("fetch.bat")
于 2012-09-27T13:11:24.640 に答える