Python-FTP скачать все файлы в каталоге - PullRequest
26 голосов
/ 08 марта 2011

Я собираю скрипт для загрузки всех файлов из каталога через 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()

Бьюсь об закладВы можете сказать, что он мало что делает, когда я запускаю его, поэтому любые предложения по улучшению будут с благодарностью.

Ответы [ 6 ]

64 голосов
/ 15 марта 2011

Мне удалось взломать это, так что теперь выкладываю соответствующий бит кода для будущих посетителей:

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.

7 голосов
/ 08 марта 2011

Если это просто проблема, которую вы хотите решить, я могу предложить команду 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 был исходным каталогом remote в большинстве ваших программ, но функция os.walk() не может пройти каталог remote . Вам нужно перебирать возвращаемые файлы самостоятельно, используя обратный вызов, предоставленный функции retrlines.

Взгляните на опции MLSD или NLST вместо 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 члене объекта для получения подробной информации.

3 голосов
/ 24 января 2017

этот код немного излишним, я думаю.

(из примера с 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."

для загрузки всех файлов.

0 голосов
/ 12 марта 2019

Рекурсивное решение (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)
0 голосов
/ 20 марта 2016

Я новичок, поэтому я не сделал код эффективно, но я сделал его и протестировал, что он работает. Это то, что я сделал для загрузки файлов и папок с 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")
0 голосов
/ 27 сентября 2012

Вместо того, чтобы использовать Python lib для загрузки каталога по ftp, мы можем вызвать скрипт dos из программы python. В сценарии 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")
...