2011-03-08 57 views
23

Python newb在這裏,請耐心等待。我把一個腳本放在一起,通過FTP下載目錄中的所有文件。到目前爲止,我已經成功地連接並讀取一個文件,但我似乎無法使批量處理(獲得從目錄中的所有文件)這是我到目前爲止有:Python-FTP下載目錄中的所有文件

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

我敢打賭,你可以告訴它並沒有做太多,當我運行它,所以任何改進建議,將不勝感激

PS這不是功課:DD

謝謝!

回答

7

如果這正是你想解決一個問題,我可能會建議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函數的回調來遍歷返回的文件。

看看MLSDNLST選項而不是LIST,它們可能會更容易解析。 (請注意,FTP實際上並未指定列表應如何顯示;它始終打算由控制檯上的人員驅動,或者傳輸特定的文件名。因此,使用FTP列表進行聰明處理的程序,例如將它們呈現給用戶一個圖形用戶界面可能必須有大量的特殊情況代碼,用於奇怪或者不明顯的服務器,並且當面對惡意文件名時,他們可能都會做一些愚蠢的事情)。 sftp確實有一個關於如何解析文件列表的規範,不會在明文中傳輸用戶名/密碼,也沒有被動與主動連接的巨大煩惱 - 它只是使用單連接,這意味着它可以在比FTP更多的防火牆上工作。

編輯:您需要將「可調用」對象傳遞給retrlines函數。可調用對象是定義方法的類的實例或函數。雖然該函數可能更容易描述,但類的實例可能更有用。 (您可以使用實例來收集文件名,但函數必須寫入全局變量。)

這裏的最簡單的可調用對象之一:

>>> 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成員。

+0

@Sosti,'在我的文章中提到的'retrlines'函數是一個超鏈接到文檔:) – sarnold 2011-03-08 10:52:25

+0

非常感謝,他們都聽起來像可靠的建議!我忘了在Windows XP上使用Python 2.5提到im(如果這很有用)如果我使用MLSD選項'ftp.retrlines('MLSD')',代碼是否適用於迭代或需要修改更多? (確定它聽起來有點愚蠢,但在這裏新手,請記住?:DD) – Sosti 2011-03-08 11:00:21

+0

@Sosti,你仍然需要修改你的代碼:你不能使用'os.walk()'函數。我將稍微編輯我的答案,以展示如何爲'retrlines'創建回調對象。 – sarnold 2011-03-08 11:27:17

55

我已經成功地破解這個,所以現在發佈的代碼中的相關位爲未來的用戶:

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中。

+8

filenames = ftp.nlst() – nad2000 2011-10-13 09:57:41

+2

推薦的方法是使用:'ftp.quit()'而不是'ftp.close()'。 請參閱此鏈接(https://docs.python.org/2/library/ftplib.html#ftplib.FTP.quit) – Oran 2014-07-06 11:36:42

-1

而不是使用Python的lib來下載一個目錄,我們可以從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") 
+4

這是比解決方案更多的解決方法 – m1k3y3 2012-09-27 16:29:16

+1

它也特定於windows(dos) – Carl 2016-08-11 22:28:09

+0

有時候,它有幫助。 – JOHN 2018-01-09 06:11:44

0

我是一個初學者,所以我沒有有效地製作代碼,但我做了它,並測試它工作。這是我從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

你能解釋你的代碼是如何工作的?這將使OP和其他人能夠在其他地方瞭解和應用您的方法(如果適用)。僅有代碼的答案[不鼓勵](http://meta.stackexchange.com/q/148272/284827),並且可能被刪除。 - [審查期間](http:// stackoverflow。com/review/late-answers/11704863) – 2016-03-20 18:25:00

+0

你的意思是代碼? – PremVijay 2016-05-14 14:43:36

2

這個代碼是有點矯枉過正,我認爲。

(從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." 

下載的所有文件。