簡體   English   中英

Python-FTP下載目錄中的所有文件

[英]Python-FTP download all files in directory

我正在整理一個腳本,以通過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()

我敢打賭,您可以說運行時它並沒有太大作用,因此任何改進建議都將不勝感激。

我設法破解了這一點,所以現在為以后的訪問者發布一些相關的代碼:

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上有效。

如果這只是您要解決的問題,建議您使用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列表進行巧妙處理的程序例如將它們呈現給用戶。對於怪異或晦澀的服務器,GUI可能必須具有大量的特殊情況代碼。面對惡意文件名,它們可能都會做一些愚蠢的事情。)

可以改用sftp嗎? sftp 確實有一個關於應該如何解析文件列表的規范,沒有明文傳輸用戶名/密碼,也沒有被動和主動連接的煩惱-它僅使用單個連接,這意味着與FTP相比,它可以跨更多的防火牆工作。

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

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

>>> 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的對象調用iterlines ,然后在對象的lines成員中查找詳細信息。

我認為這段代碼有點過大。

(來自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."

下載所有文件。

我是一個初學者,所以我沒有高效地編寫代碼,但是我編寫並測試了它是否正常工作。 這是我從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")

遞歸解決方案(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)

可以使用Python程序調用dos腳本,而不是使用Python lib通過ftp下載目錄。 在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")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM