繁体   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