2011-03-08 46 views
23

Python newb aquí así que por favor tengan paciencia conmigo. Estoy armando un script para descargar todos los archivos de un directorio a través de FTP. Hasta ahora he logrado conectar a buscar un archivo, pero me parece que no puede hacer para trabajar en lotes (obtener todos los archivos del directorio) Esto es lo que tengo hasta ahora:Python-FTP descarga todos los archivos en el directorio

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() 

apuesto a que puede diga que no hace mucho cuando corro, así que cualquier sugerencia de mejora sería muy apreciada

PS Esto no es tarea: DD

Gracias !!

Respuesta

7

Si esto es sólo un problema desea resolver, podría sugerir el comando wget:

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

La opción --continue podría ser muy peligroso si los archivos cambio en el servidor. Si los archivos solo son añadidos, entonces es muy amigable.

Sin embargo, si se trata de un ejercicio de aprendizaje para usted y que le gustaría hacer su programa de trabajo, creo que usted debe comenzar por mirar esta línea:

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

directory ha sido el directorio de origen remoto en la mayoría de su programa, pero la función os.walk() no puede recorrer un directorio remoto . Necesita iterar sobre los archivos devueltos usted mismo, utilizando una devolución de llamada suministrada a la función retrlines.

Eche un vistazo a las opciones MLSD o NLST en lugar de LIST, probablemente sean más fáciles de analizar. (Tenga en cuenta que FTP no especifica cómo deberían verse las listas, siempre fue pensado para ser manejado por un humano en una consola, o un nombre de archivo específico transferido. Por lo tanto, los programas que hacen cosas inteligentes con listas de FTP se los presentan al usuario en una GUI probablemente tenga que tener enormes montones de códigos de casos especiales para servidores raros u oscuros. Y probablemente todos hagan algo estúpido cuando se enfrenten con nombres de archivos maliciosos.)

¿Se puede usar sftp? sftptiene tiene una especificación de cómo se supone que se deben analizar los listados de archivos, no transmite el nombre de usuario/contraseña a la vista y no tiene la gran molestia de las conexiones pasivas vs activas; simplemente usa la conexión única, lo que significa que funciona en más firewalls que FTP.

Editar: Debe pasar un objeto 'invocable' a la función retrlines. Un objeto invocable es una instancia de una clase que definió un método __call__ o una función. Si bien la función puede ser más fácil de describir, una instancia de una clase puede ser más útil. (Podría usar la instancia para recopilar los nombres de los archivos, pero la función tendría que escribir en una variable global.)

Aquí es uno de los objetos más simple exigible:

>>> class c: 
... def __call__(self, *args): 
... print(args) 
... 
>>> f = c() 
>>> f('hello') 
('hello',) 
>>> f('hello', 'world') 
('hello', 'world') 

Esto crea una nueva clase, c, que define un método de instancia __call__. Esto solo imprime sus argumentos de una manera bastante estúpida, pero muestra cuán mínimo estamos hablando. :)

Si quería algo más inteligente, podría hacer algo como esto:

class handle_lines: 
    def __init__(self): 
    self.lines = [] 
    def __call__(self, *args): 
    self.lines << args[0] 

llamada iterlines con un objeto de esta clase, a continuación, busque en lines miembro del objeto para obtener más información.

+0

@Sosti, la mención de la función 'retrlines' en mi publicación es un hipervínculo a la documentación :) – sarnold

+0

Muchas gracias por eso, ¡todos suenan como sugerencias sólidas! Olvidé mencionar que estoy usando Python 2.5 en Windows XP (si es que eso es útil) Si uso la opción MLSD, 'ftp.retrlines (' MLSD ')', ¿funcionaría el código para la iteración o tendré que modificarlo? ¿Más? (seguro que suena un poco tonto pero nuevo aquí, ¿recuerdas?: DD) – Sosti

+0

@Sosti, aún necesitarías modificar tu código: no puedes usar la función 'os.walk()'. Editaré mi respuesta en un momento para mostrar cómo hacer un objeto de devolución de llamada para 'retrlines'. – sarnold

55

he logrado descifrar esto, por lo que ahora publicar el bit correspondiente del código para futuros visitantes:

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 

Esto funcionó para mí en Python 2.5, Windows XP.

+8

filenames = ftp.nlst() – nad2000

+2

La forma recomendada es usar: 'ftp.quit()' en lugar de 'ftp.close()'. Por favor [consulte este enlace] (https://docs.python.org/2/library/ftplib.html#ftplib.FTP.quit) – Oran

-1

En lugar de usar Python lib para ftp descargar un directorio, podemos llamar a dos secuencias de comando desde el programa python. En el script dos utilizamos el protocolo nativo ftp que puede descargar todo el archivo de la carpeta usando 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") 
+4

esto es más solución que la solución – m1k3y3

+1

también es específico de Windows (dos) – Carl

+0

A veces, ayuda. – JOHN

0

Soy un principiante, así que no he hecho el código de manera eficiente, pero lo hice y probé que está funcionando. Esto es lo que hice para descargar archivos y carpetas del sitio ftp, pero solo una profundidad limitada en la estructura del archivo.

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

¿Podría explicar cómo y por qué funciona su código? Eso permitirá que OP y otros entiendan y apliquen sus métodos (donde corresponda) en cualquier otro lugar. Las respuestas de solo código son [desaconsejadas] (http://meta.stackexchange.com/q/148272/284827) y pueden ser eliminadas. - [Durante la revisión] (http: // stackoverflow.com/review/late-answers/11704863) –

+0

¿Se refiere a los comentarios en el código? – PremVijay

2

este código es un poco exagerado, creo.

(a partir del ejemplo de pitón https://docs.python.org/2/library/ftplib.html) Después ftp.login() y el establecimiento de ftp.cwd() sólo se puede utilizar:

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." 

para descargar todos los archivos.

Cuestiones relacionadas