2010-04-09 36 views
7

Thao tác này sẽ không tải xuống nội dung của thư mục con; làm thế nào tôi có thể làm như vậy?Tải xuống cây thư mục với 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() 

Trả lời

6

đây là giải pháp thay thế. bạn có thể thử sử dụng gói ftputil. Sau đó, bạn có thể sử dụng số điện thoại đó để walk the remote directories và nhận các tệp của mình

+0

Là nó thực sự là phức tạp để điểm mà tôi nên gói xem xét? Tôi nghĩ rằng nó sẽ chỉ mất 10 dòng mã thực sự phức tạp. –

1

Ít nhất là không quan trọng. Trong trường hợp đơn giản nhất, bạn chỉ giả sử bạn có các tệp và thư mục. Điều này không phải luôn luôn như vậy, có các liên kết mềm và liên kết cứng và lối tắt kiểu Windows. Softlink và phím tắt thư mục đặc biệt có vấn đề vì chúng làm cho thư mục đệ quy có thể, điều này sẽ gây nhầm lẫn cho trình cài đặt ftp ngây thơ ngây thơ.

Bạn xử lý thư mục đệ quy như thế nào tùy thuộc vào nhu cầu của bạn; bạn có thể chỉ đơn giản là không theo softlinks hoặc bạn có thể thử phát hiện các liên kết đệ quy. Phát hiện liên kết đệ quy vốn đã phức tạp, bạn không thể làm điều đó một cách đáng tin cậy.

10

này nên làm các trick :)

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) 
+0

cũng có thể bạn không muốn thoát trong 'ftplib.error_perm' đầu tiên trừ trường hợp tài khoản người dùng của bạn có vấn đề về quyền. 'pass' có thể hoạt động. – jameh

6

Đây là một câu hỏi rất cũ, nhưng tôi đã có một nhu cầu tương tự mà tôi muốn để đáp ứng một cách rất chung chung. Tôi đã kết thúc bằng văn bản giải pháp của riêng tôi hoạt động rất tốt cho tôi. Tôi đã đặt nó trên Gist tại đây https://gist.github.com/Jwely/ad8eb800bacef9e34dd775f9b3aad987

và dán nó bên dưới trong trường hợp tôi đã từng sử dụng ngoại tuyến.

sử dụng Ví dụ:

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

Đoạn mã trên sẽ tìm kiếm một thư mục gọi là "remote_dir" trên các máy chủ ftp, và sau đó lặp lại trong các thư mục và toàn bộ nội dung của nó vào "local_dir". Nó gọi kịch bản dưới đây.

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) 
+0

Tuyệt vời. Làm việc như một say mê. Nên là một thư viện cho việc này! –

3

Sử dụng ftputil, một giải pháp nhanh chóng có thể là:

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)) 
Các vấn đề liên quan