[英]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
函数的回调自己遍历返回的文件。
看一下MLSD
或NLST
选项而不是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.