FTP Download nach Datum

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Hallo zusammen,

nach langer Zeit habe ich die Aufgabe bekommen mein FTP-Programm auf SFTP umzustellen.
Hierzu habe ich den Code mal teilweise angepasst:

Code: Alles auswählen

import pysftp
from operator import itemgetter
import os.path
import time
import urlparse

class TimeFTP(pysftp.Connection):

    def mdtm(self, filename):
        retcode, timestamp = self.sendcmd('MDTM ' + filename).split()
        return timestamp

    def last_modified(self, pattern):
        results = []
        for filename in self.nlst(pattern):
            timestamp = self.mdtm(filename)
            results.append((filename, timestamp))
        for filename, timestamp in sorted(results, key=itemgetter(1)):
            timestruct = time.strptime(timestamp, '%Y%m%d%H%M%S')
            yield filename, timestruct


def get_last_modified(ftp_addr, pattern='*', no=1, dest='.', user='', pw=''):
    parsed = urlparse.urlparse(ftp_addr)
    FTP = TimeFTP(parsed.netloc, user, pw)
    if parsed.path:
        ftp.cwd(parsed.path)
    for filename, timestruct in list(ftp.last_modified(pattern))[-no:]:
        with open(os.path.join(dest, filename), 'wb') as outfile:
            ftp.retrbinary('RETR ' + filename, outfile.write)
Das das so natürlich noch nicht funktioniert ist mir schon klar, da dass pysftp z.B. retrbinary nicht kennt.

Was mir jetzt nicht klar ist,was will mir die Fehlermeldung sagen:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:/Python_Test/Sourcecode/testmini", line 4, in <module>
    timeftpx.get_last_modified(ftp_addr, '*.dat', 2, 'C:\user', 'login','pass')
  File "C:\Python27\lib\timeftpx.py", line 25, in get_last_modified
    FTP = TimeFTP(parsed.netloc, user, pw)
  File "build\bdist.win32\egg\pysftp.py", line 74, in __init__
    xSx_key = paramiko.RSAKey.from_private_key_file(private_key_file,private_key_pass)
  File "build\bdist.win32\egg\paramiko\pkey.py", line 198, in from_private_key_file
    key = cls(filename=filename, password=password)
  File "build\bdist.win32\egg\paramiko\rsakey.py", line 51, in __init__
    self._from_private_key_file(filename, password)
  File "build\bdist.win32\egg\paramiko\rsakey.py", line 163, in _from_private_key_file
    data = self._read_private_key_file('RSA', filename, password)
  File "build\bdist.win32\egg\paramiko\pkey.py", line 279, in _read_private_key_file
    f = open(filename, 'r')
IOError: [Errno 2] No such file or directory: 'pass'
Für mich sieht das so aus, wie wenn er unter "def get_last_modified" andere Parameter erwarten würde,bzw. in anderer Reihenfolge.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Ein

Code: Alles auswählen

help(timeftpx.get_last_modified)
an der entsprechenden Stelle wird dir sicherlich die entsprechenden Parameter zeigen, die erwartet werden.
Zuletzt geändert von sparrow am Montag 4. Februar 2013, 13:11, insgesamt 1-mal geändert.
BlackJack

@Manne_Manta: Vielleicht ja nicht die `get_last_modified()`, wobei ich jetzt mal davon ausgehe, dass die a) von Dir ist und b) nicht verändert wurde. Aber was *hast* Du denn verändert und wo betrifft das die genannte Funktion. Das ist doch eigentlich ziemlich offensichtlich.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Die timeftp wurde von Snafu in einem der älteren Posts geschrieben.
Ich habe anstelle der ftplib die pysftp importiert.

@sparrow: Wenn ich

Code: Alles auswählen

help(timeftpx.get_last_modified
vor

Code: Alles auswählen

def get_last_modified
einfüge bringt er mir

Code: Alles auswählen

    import timeftpx
  File "C:\Python27\lib\timeftpx.py", line 24
    def get_last_modified(ftp_addr, pattern='*', no=1, dest='.', user='', pw=''):
      ^
SyntaxError: invalid syntax
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Schließen die Klammer du musst!
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Natürlich die Klammer.

Aber das kann ich wohl so nur nur im Hauptprogramm einfügen und dabei kommt nichts vernünftiges raus.

Code: Alles auswählen

Help on function get_last_modified in module timeftpx:

get_last_modified(ftp_addr, pattern='*', no=1, dest='.', user='', pw='')
BlackJack

@Manne_Manta: Das war ja schon vorher klar. Du hast den Quelltext von dieser Funktion ja gezeigt.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Achso, das ist die Funktion von oben? Dann hat mich der TraceBack verwirrt, weil da die Datei in einem lib-Verzeichnis von Python liegt.

In dem Fall solltest du prüfen, was denn pysftp.Connection für Parameter bei der Initialisierung erwartet.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Dann kommt dass hier:

Code: Alles auswählen

Help on class Connection in module pysftp:

class Connection(__builtin__.object)
 |  Connects and logs into the specified hostname. 
 |  Arguments that are not given are guessed from the environment.
 |      host             - The Hostname of the remote machine.
 |      username         - Your username at the remote machine.(None)
 |      private_key      - Your private key file.(None)
 |      password         - Your password at the remote machine.(None)
 |      port             - The SSH port of the remote machine.(22)
 |      private_key_pass - password to use if your private_key is encrypted(None)
 |      log              - log connection/handshake details (False)
 |  returns a connection to the requested machine
 |  
 |  srv = pysftp.Connection('example.com')
 |  
 |  Methods defined here:
 |  
 |  __del__(self)
 |      Attempt to clean up if not explicitly closed.
 |  
 |  __init__(self, host, username=None, private_key=None, password=None, port=22, private_key_pass=None, log=False)
 |  
 |  chdir(self, path)
 |      change the current working directory on the remote
 |  
 |  close(self)
 |      Closes the connection and cleans up.
 |  
 |  execute(self, command)
 |      Execute the given commands on a remote machine.
 |  
 |  get(self, remotepath, localpath=None)
 |      Copies a file between the remote host and the local host.
 |  
 |  getcwd(self)
 |      return the current working directory on the remote
 |  
 |  listdir(self, path='.')
 |      return a list of files for the given path
 |  
 |  put(self, localpath, remotepath=None)
 |      Copies a file between the local host and the remote host.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Genau, da stehen die Argumente die erwartet werden.
Wenn du das jetzt mit dem vergleichst, was du übergibst, siehst du ja schon den Fehler.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Die Argumente habe ich mal angepasst.
Nur ist mir die folgende Fehlermeldung wieder etwas suspekt.
Hat da das parsen in

Code: Alles auswählen

FTP = TimeFTP(parsed.netloc, username, password)
den fehler verursacht oder liegt es daran, dass Paramiko mit den Argumenten nicht klar kommt.

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\PASU_FTP_Export\Sourcecode\testmini", line 7, in <module>
    timeftpx.get_last_modified('host', '*.dat', 2, 'C:\user', 'username','password')
  File "C:\Python27\lib\timeftpx.py", line 29, in get_last_modified
    FTP = TimeFTP(parsed.netloc, username, password)
  File "build\bdist.win32\egg\pysftp.py", line 55, in __init__
    self._transport = paramiko.Transport((host, port))
  File "build\bdist.win32\egg\paramiko\transport.py", line 298, in __init__
    'Unable to connect to %s: %s' % (hostname, reason))
SSHException: Unable to connect to : [Errno 10049] Die angeforderte Adresse ist in diesem Kontext ungültig
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Hast du jetzt nur die Namen der Variablen angepasst, die übergeben werden?
Das kann man aus dem Schnipsel leider nicht erkennen.
BlackJack

@Manne_Manta: Die Fehlermeldung lässt vermuten, dass Paramiko mit einer leeren Zeichenkette als `host` aufgerufen wird. Was ja auch stimmt wenn die Daten im Stapelabzug (Traceback) stimmen:

Code: Alles auswählen

In [2]: urlparse.urlparse('host').netloc
Out[2]: ''
Das nächste Problem wird deutlich wenn Du noch einmal vergleichst mit welchen Argumenten Du `TimeFTP` aufrufst und was `pyftp.Connection` eigentlich erwartet. Das Passwort ist dort *nicht* an *der* Stelle in den Argumenten.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Aber so funktioniert es doch auch:

Code: Alles auswählen

import pysftp

srv = pysftp.Connection(host='testserver',username='usr', password='test')
srv.execute('ls -al')
srv.chdir('/dat3')
srv.get('hb.txt')

#srv.put('hb.txt')
srv.close()
Was ist an der Anordnung der Argumente da anderst?
BlackJack

@Manne_Manta: Hier gibt es im Grunde gar keine Ordnung auf den Argumenten weil die ja *namentlich* und per Position bestimmt werden. Wenn Du die Namen *nicht* angibst, sondern nur die Werte, dann überlege doch mal wie Python die zuordnet.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Wenn ich Dich richtig verstehe müsste der Code so aussehen:

Code: Alles auswählen

FTP = TimeFTP(parsed.netloc,username, '',password,'','','')
Er bringt damit aber folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\PASU_FTP_Export\Sourcecode\testmini", line 8, in <module>
    timeftpx.get_last_modified('host', '*.dat', 2, 'C:\user', 'pasu','tvpu')
  File "C:\Python27\lib\timeftpx.py", line 29, in get_last_modified
    FTP = TimeFTP(parsed.netloc,username, '',password,'','','')
  File "build\bdist.win32\egg\pysftp.py", line 55, in __init__
    self._transport = paramiko.Transport((host, port))
  File "build\bdist.win32\egg\paramiko\transport.py", line 291, in __init__
    sock.connect((hostname, port))
  File "C:\Python27\lib\socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
TypeError: an integer is required
Wo wird jetzt eine Zahl benötigt?
BlackJack

@Manne_Manta: Du solltest vielleicht mal aufhören zu raten und anfangen Dich mit der Materie auseinander zu setzen. Wenn man sich den Stapelabzug anschaut läuft es darauf hinaus das ein `socket.socket`-Objekt mit dem Hostnamen und der Portnummer erzeugt werden soll. Informiere Dich was Sockets sind und welches dieser beiden Argumente eine Zahl sein muss. Und dann schau Dir Deinen Aufruf an, und Du wirst feststellen wo Du statt einer Zahl etwas anderes übergibst.

Und nein, so meinte ich das mit dem Aufruf nicht. Du sollst nicht einfach irgendwas übergeben, und auch nicht alles mit Werten belegen, sondern nur gezielt die Argumente, wo Du nicht den Default-Wert haben möchtest. Dazu könntest Du Dir in der Python-Dokumentation erarbeiten wie das mit Argumenten, Default-Argumenten, und Funktionsaufrufen in Python funktioniert.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Wenn ich richtig recherchiert habe ist es wie folgt:

Die Parameter bei denen ich den Default Wert benutzen möchte übergebe ich nicht.
Python benötigt die Parameter, wenn Sie nicht benannt sind nach der im Aufruf stehenden Reihenfolge, wenn die
Parameter benannt sind wird der Namen des Parameters benutzt.

Das heißt für mich. Wenn ich im Funktionsaufruf die Parameter

Code: Alles auswählen

timeftpx.get_last_modified(host, '*.dat', 2, 'C:\user', username,password)
an

Code: Alles auswählen

def get_last_modified(host="", pattern='*', no=1, dest='.', username='', password='')

übergebe müsste das eigentlich passen.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Nein, weil da ja gar nicht der Fehler aufgetreten ist, sondern bei der Instanzierung der Klasse TimeFTP, die von pysftp.Connection erbt und daher bestimmte Argumente beim Initialisieren erwartet, die du aber nicht oder falsch angibst.
Welche Argumente, in welcher Reihenfolge das sind (und wie sie heißen, und was der Default-Wert ist) hast du hier im Thread schon gepostet. Der Post beginnt mit "Dann kommt das hier", und das was da kommt, dass solltest du auch wirklich lesen.
Manne_Manta
User
Beiträge: 39
Registriert: Dienstag 5. Mai 2009, 11:26

Ich blicks nicht.
Das Initialisieren der Argumente geschieht doch in:

Code: Alles auswählen

def get_last_modified(host,username,password,private_key='', port='', private_key_pass='', log=''):
Nur wie bekomm ich die Default Argumente aus pysftp dort rein. So wie ichs gemacht habe funktionierts auf jeden Fall nicht. wenn ich

Code: Alles auswählen

print port
eingebe dann kommt da nichts.
Wie komme ich denn nun an die Default Werte?
Wenn ich z.B. http://effbot.org/zone/default-values.htm das hier lese, finde ich nichts was ich auf mein Problem anwenden kann, da die Default Werte ja von pysftp kommen.
Antworten