使用ftplib下载目录树

这不会下载子目录的内容; 我该怎么办?

import ftplib import configparser import os directories = [] def add_directory(line): if line.startswith('d'): bits = line.split() dirname = bits[8] directories.append(dirname) def makeDir(archiveTo): for dir in directories: newDir = os.path.join(archiveTo, dir) if os.path.isdir(newDir) == True: print("Directory \"" + dir + "\" already exists!") else: os.mkdir(newDir) def getFiles(archiveTo, ftp): files = ftp.nlst() for filename in files: try: directories.index(filename) except: ftp.retrbinary('RETR %s' % filename, open(os.path.join(archiveTo, filename), 'wb').write) def runBackups(): #Load INI filename = 'connections.ini' config = configparser.SafeConfigParser() config.read(filename) connections = config.sections() i = 0 while i < len(connections): #Load Settings uri = config.get(connections[i], "uri") username = config.get(connections[i], "username") password = config.get(connections[i], "password") backupPath = config.get(connections[i], "backuppath") archiveTo = config.get(connections[i], "archiveto") #Start Back-ups ftp = ftplib.FTP(uri) ftp.login(username, password) ftp.cwd(backupPath) #Map Directory Tree ftp.retrlines('LIST', add_directory) #Make Directories Locally makeDir(archiveTo) #Gather Files getFiles(archiveTo, ftp) #End connection and increase counter. ftp.quit() i += 1 print() print("Back-ups complete.") print() 

这应该做的伎俩:)

 import sys import ftplib import os from ftplib import FTP ftp=FTP("ftp address") ftp.login("user","password") def downloadFiles(path,destination): #path & destination are str of the form "/dir/folder/something/" #path should be the abs path to the root FOLDER of the file tree to download try: ftp.cwd(path) #clone path to destination os.chdir(destination) os.mkdir(destination[0:len(destination)-1]+path) print destination[0:len(destination)-1]+path+" built" except OSError: #folder already exists at destination pass except ftplib.error_perm: #invalid entry (ensure input form: "/dir/folder/something/") print "error: could not change to "+path sys.exit("ending session") #list children: filelist=ftp.nlst() for file in filelist: try: #this will check if file is folder: ftp.cwd(path+file+"/") #if so, explore it: downloadFiles(path+file+"/",destination) except ftplib.error_perm: #not a folder with accessible content #download & return os.chdir(destination[0:len(destination)-1]+path) #possibly need a permission exception catch: ftp.retrbinary("RETR "+file, open(os.path.join(destination,file),"wb").write) print file + " downloaded" return source="/ftproot/folder_i_want/" dest="/systemroot/where_i_want_it/" downloadFiles(source,dest) 

这是一个替代scheme。 你可以尝试使用ftputil包。 然后,您可以使用它来遍历远程目录并获取您的文件

这是一个非常古老的问题,但我有一个类似的需要,我想以一个非常普遍的方式来满足。 我最终写了自己的解决scheme,对我来说效果很好。 我把它放在Gist这里https://gist.github.com/Jwely/ad8eb800bacef9e34dd775f9b3aad987

并粘贴在下面的情况下,我已经离线了。

用法示例:

 import ftplib ftp = ftplib.FTP(mysite, username, password) download_ftp_tree(ftp, remote_dir, local_dir) 

上面的代码将在ftp主机上查找一个名为“remote_dir”的目录,然后将该目录及其全部内容复制到“local_dir”中。 它调用下面的脚本。

 import ftplib import os def _is_ftp_dir(ftp_handle, name, guess_by_extension=True): """ simply determines if an item listed on the ftp server is a valid directory or not """ # if the name has a "." in the fourth to last position, its probably a file extension # this is MUCH faster than trying to set every file to a working directory, and will work 99% of time. if guess_by_extension is True: if name[-4] == '.': return False original_cwd = ftp_handle.pwd() # remember the current working directory try: ftp_handle.cwd(name) # try to set directory to new name ftp_handle.cwd(original_cwd) # set it back to what it was return True except: return False def _make_parent_dir(fpath): """ ensures the parent directory of a filepath exists """ dirname = os.path.dirname(fpath) while not os.path.exists(dirname): try: os.mkdir(dirname) print("created {0}".format(dirname)) except: _make_parent_dir(dirname) def _download_ftp_file(ftp_handle, name, dest, overwrite): """ downloads a single file from an ftp server """ _make_parent_dir(dest) if not os.path.exists(dest) or overwrite is True: with open(dest, 'wb') as f: ftp_handle.retrbinary("RETR {0}".format(name), f.write) print("downloaded: {0}".format(dest)) else: print("already exists: {0}".format(dest)) def _mirror_ftp_dir(ftp_handle, name, overwrite, guess_by_extension): """ replicates a directory on an ftp server recursively """ for item in ftp_handle.nlst(name): if _is_ftp_dir(ftp_handle, item): _mirror_ftp_dir(ftp_handle, item, overwrite, guess_by_extension) else: _download_ftp_file(ftp_handle, item, item, overwrite) def download_ftp_tree(ftp_handle, path, destination, overwrite=False, guess_by_extension=True): """ Downloads an entire directory tree from an ftp server to the local destination :param ftp_handle: an authenticated ftplib.FTP instance :param path: the folder on the ftp server to download :param destination: the local directory to store the copied folder :param overwrite: set to True to force re-download of all files, even if they appear to exist already :param guess_by_extension: It takes a while to explicitly check if every item is a directory or a file. if this flag is set to True, it will assume any file ending with a three character extension ".???" is a file and not a directory. Set to False if some folders may have a "." in their names -4th position. """ os.chdir(destination) _mirror_ftp_dir(ftp_handle, path, overwrite, guess_by_extension) 

使用ftputil,一个快速的解决scheme可能是:

 def download(folder): for item in ftp.walk(folder): print("Creating dir " + item[0]) os.mkdir(item[0]) for subdir in item[1]: print("Subdirs " + subdir) for file in item[2]: print(r"Copying File {0} \ {1}".format(item[0], file)) ftp.download(ftp.path.join(item[0],file), os.path.join(item[0],file)) 

至less是不平凡的。 在最简单的情况下,你只假定你有文件和目录。 这并不总是这样,有软链接和硬链接和Windows风格的捷径。 软链接和目录快捷方式是特别有问题的,因为他们使recursion目录成为可能,这将混淆天真的实施FTP抓取。

你将如何处理这样的recursion目录取决于你的需要; 你可能根本不遵循软链接,或者你可能会尝试检测recursion链接。 检测recursion链接本质上是棘手的,你不能可靠地做到这一点。