Python-FTP下载目录中的所有文件

Python-FTP download all files in directory

Python新手来了,所以请你忍受我。我正在编写一个脚本,通过ftp从一个目录下载所有文件。到目前为止,我已经成功地连接并获取了一个文件,但我似乎无法成批工作(从目录中获取所有文件),以下是我迄今为止所拥有的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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()

我敢打赌,你可以告诉我,当我运行它的时候,它没有什么作用,所以任何改进的建议都会非常感谢

PS这不是家庭作业:DD

谢谢!!


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

1
2
3
4
5
6
7
8
9
10
11
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

这在Python2.5、WindowsXP上对我很有用。


如果这只是你想解决的问题,我建议使用wget命令:

1
2
cd c:\destination
wget --mirror --continue --no-host-directories --user=username --password=s3cr3t ftp://hostname/source/path/

如果服务器上的文件发生更改,--continue选项可能非常危险。如果只添加文件,那么它是非常友好的。

然而,如果这是一个学习练习,你想让你的计划工作,我认为你应该从这一行开始:

1
for subdir, dirs, files in os.walk(directory):

在大多数程序中,directory是远程源目录,但os.walk()功能不能遍历远程目录。您需要自己迭代返回的文件,使用提供给retrlines函数的回调。

看看MLSDNLST选项,而不是LIST,它们可能更容易解析。(请注意,ftp实际上并没有指定列表的外观;它总是由控制台上的人员驱动,或者由传输的特定文件名驱动。因此,对ftp列表进行巧妙处理的程序(如在GUI中向用户展示它们)可能需要大量的特殊情况代码,用于奇怪或不明确的服务器。当面对恶意文件名时,他们可能都会做些愚蠢的事情。)

你能用sftp代替吗?sftp确实有一个关于文件列表应该如何解析的规范,没有清晰地传输用户名/密码,也没有被动连接和主动连接的巨大麻烦——它只使用单一连接,这意味着它跨防火墙的工作比ftp多。

编辑:您需要将"可调用"对象传递给retrlines函数。可调用对象可以是定义__call__方法的类的实例,也可以是函数。虽然函数可能更容易描述,但类的实例可能更有用。(您可以使用实例收集文件名,但函数必须写入全局变量。糟透了。

下面是一个最简单的可调用对象:

1
2
3
4
5
6
7
8
9
>>> class c:
...  def __call__(self, *args):
...   print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')

这创建了一个新的类,c,它定义了一个实例方法__call__。这只是以一种相当愚蠢的方式打印它的论点,但它显示了我们谈论的内容是多么少。:)

如果你想要更聪明的东西,它可以这样做:

1
2
3
4
5
class handle_lines:
  def __init__(self):
    self.lines = []
  def __call__(self, *args):
    self.lines << args[0]

用这个类的对象调用iterlines,然后在对象的lines成员中查找详细信息。


我觉得这个代码有点过分了。

(从python示例https://docs.python.org/2/library/ftplib.html)在ftp.login()和设置ftp.cwd()之后,您只需使用:

1
2
3
4
5
6
7
8
9
10
11
12
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."

下载所有文件。


递归解决方案(PY 2.7):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)

我是一个初学者,所以我没有有效地编写代码,但是我编写了代码并测试了它的工作状态。这是我从ftp站点下载文件和文件夹所做的,但文件结构的深度有限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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")


我们可以从python程序调用dos脚本,而不是使用python lib来ftp下载目录。在DOS脚本中,我们将使用本地FTP协议,该协议可以使用mget *.*从文件夹中下载所有文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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")