34

我正在编写一个脚本来通过 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()

我敢打赌,当我运行它时,你可以看出它并没有多大作用,所以任何改进建议都将不胜感激。

4

6 回答 6

76

我已经设法破解了这个,所以现在为未来的访问者发布相关的代码:

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 上对我有用。

于 2011-03-15T15:28:27.767 回答
10

如果这只是您想解决的问题,我可能会建议以下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您需要使用提供给函数的回调自己迭代返回的文件。

看看MLSDorNLST选项而不是LIST,它们可能更容易解析。(请注意,FTP 实际上并没有指定列表的外观;它始终旨在由控制台上的人驱动,或传输特定的文件名。因此,对 FTP 列表进行巧妙操作的程序,例如将它们呈现给用户GUI 可能必须有大量特殊情况代码,用于奇怪或晦涩的服务器。当面对恶意文件名时,它们可能都会做一些愚蠢的事情。)

可以sftp改用吗?sftp 确实有关于如何解析文件列表的规范,不以明文形式传输用户名/密码,并且没有被动与主动连接的巨大烦恼——它只是使用单个连接,这意味着它与 FTP 相比,它可以跨越更多的防火墙。

编辑:您需要将“可调用”对象传递给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使用此类的对象调用,然后查看对象的lines成员以获取详细信息。

于 2011-03-08T10:27:59.380 回答
3

我认为这段代码有点矫枉过正。

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

下载所有文件。

于 2017-01-24T20:36:53.720 回答
1

递归解决方案(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)
于 2019-03-12T17:44:22.043 回答
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")
于 2016-03-20T18:04:08.543 回答
-4

我们可以从 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")
于 2012-09-27T13:11:24.640 回答