Как удалить файлы с помощью скрипта Python с FTP-сервера, возраст которых превышает 7 дней?

Я хотел бы написать сценарий Python, который позволяет мне удалять файлы с FTP-сервера по достижении ими определенного возраста. Я подготовил сценарий ниже, но он выдает сообщение об ошибке: WindowsError: [Error 3] The system cannot find the path specified: '/test123/*.*'

У кого-нибудь есть идеи, как решить эту проблему? Заранее спасибо!

import os, time
from ftplib import FTP

ftp = FTP('127.0.0.1')
print "Automated FTP Maintainance"
print 'Logging in.'
ftp.login('admin', 'admin')

# This is the directory that we want to go to
path = 'test123'
print 'Changing to:' + path
ftp.cwd(path)
files = ftp.retrlines('LIST')
print 'List of Files:' + files 
#--everything works fine until here!...

#--The Logic which shall delete the files after the are 7 days old--
now = time.time()
for f in os.listdir(path):
  if os.stat(f).st_mtime < now - 7 * 86400:
    if os.path.isfile(f):
        os.remove(os.path.join(path, f))
except:
    exit ("Cannot delete files")

print 'Closing FTP connection'
ftp.close()

person Tom    schedule 19.05.2010    source источник
comment
что такое os.directory? Ваш код не имеет смысла. Почему вы пытаетесь удалить файлы из своей локальной системы?   -  person SilentGhost    schedule 19.05.2010
comment
Я думаю, что оболочка / bash была бы лучшей альтернативой python   -  person dassouki    schedule 19.05.2010
comment
да, но он должен работать в Windows. поэтому shell / bash в этом случае не подходит.   -  person Tom    schedule 20.05.2010


Ответы (5)


В ПОРЯДКЕ. Предполагая, что ваш FTP-сервер поддерживает команду MLSD, создайте модуль со следующим кодом (это код из сценария, который я использую для синхронизации удаленного FTP-сайта с локальным каталогом):

код модуля

# for python ≥ 2.6
import sys, os, time, ftplib
import collections
FTPDir= collections.namedtuple("FTPDir", "name size mtime tree")
FTPFile= collections.namedtuple("FTPFile", "name size mtime")

class FTPDirectory(object):
    def __init__(self, path='.'):
        self.dirs= []
        self.files= []
        self.path= path

    def getdata(self, ftpobj):
        ftpobj.retrlines('MLSD', self.addline)

    def addline(self, line):
        data, _, name= line.partition('; ')
        fields= data.split(';')
        for field in fields:
            field_name, _, field_value= field.partition('=')
            if field_name == 'type':
                target= self.dirs if field_value == 'dir' else self.files
            elif field_name in ('sizd', 'size'):
                size= int(field_value)
            elif field_name == 'modify':
                mtime= time.mktime(time.strptime(field_value, "%Y%m%d%H%M%S"))
        if target is self.files:
            target.append(FTPFile(name, size, mtime))
        else:
            target.append(FTPDir(name, size, mtime, self.__class__(os.path.join(self.path, name))))

    def walk(self):
        for ftpfile in self.files:
            yield self.path, ftpfile
        for ftpdir in self.dirs:
            for path, ftpfile in ftpdir.tree.walk():
                yield path, ftpfile

class FTPTree(FTPDirectory):
    def getdata(self, ftpobj):
        super(FTPTree, self).getdata(ftpobj)
        for dirname in self.dirs:
            ftpobj.cwd(dirname.name)
            dirname.tree.getdata(ftpobj)
            ftpobj.cwd('..')

дело с одним каталогом

Если вы хотите работать с файлами каталога, вы можете:

import ftplib, time

quite_old= time.time() - 7*86400 # seven days

site= ftplib.FTP(hostname, username, password)
site.cwd(the_directory_to_work_on) # if it's '.', you can skip this line
folder= FTPDirectory()
folder.getdata(site) # get the filenames
for path, ftpfile in folder.walk():
    if ftpfile.mtime < quite_old:
        site.delete(ftpfile.name)

Это должно делать то, что вы хотите.

каталог и его потомки

Теперь, если это должно работать рекурсивно, вам нужно будет внести следующие два изменения в код для «одного каталога»:

folder= FTPTree()

и

site.delete(os.path.join(path, ftpfile.name))

Возможное предостережение

На серверах, с которыми я работал, не было проблем с относительными путями в командах STOR и DELE, поэтому site.delete с относительным путем тоже работали. Если вашему FTP-серверу требуются имена файлов без указания пути, вы должны сначала .cwd перейти к предоставленному path, .delete обычному ftpfile.name, а затем .cwd обратно в базовую папку.

person tzot    schedule 24.06.2010
comment
Привет, ΩΤΖΙΟΥ, спасибо за идею, мне она очень нравится. Я попробовал это, и мне пришлось немного изменить код, но я получаю сообщение об ошибке: site = ftplib.FTP ('127.0.0.1, admin, admin') File C: \ Python26 \ lib \ ftplib.py, строка 116, в файле init self.connect (host) C: \ Python26 \ lib \ ftplib.py, строка 131, в connect self.sock = socket.create_connection ((self.host, self. порт), self.timeout) для res в getaddrinfo (хост, порт, 0, SOCK_STREAM): socket.gaierror: [Errno 11001] getaddrinfo не удалось - person Tom; 04.08.2010
comment
импортировать ОС, время, FTP_AUTO из ftplib import FTP own_old = time.time () - 7 * 86400 # семь дней # C: \ Temp \ ftp \ test123 site = ftplib.FTP ('127.0.0.1, admin, admin') site .cwd (test123) # если это '.', вы можете пропустить эту строку folder = FTPDirectory () print folder folder.getdata (site) # получить имена файлов для пути, ftpfile в папке .walk (): if ftpfile.mtime ‹ довольно_old: site.delete (ftpfile.name) - person Tom; 04.08.2010
comment
@Tom: '127.0.0.1, admin, admin' не является допустимым именем хоста; вот в чем ошибка. Вы, вероятно, имели в виду '127.0.0.1', 'admin', 'admin' в своем коде. - person tzot; 04.08.2010
comment
Спасибо, сейчас связь работает. Но система заявила, что: Файл G: / MY_TCS / !! PROJECTS / Q3 / FTP_auto_del / python / ftp_del.py, строка 6, в папке ‹module› = FTPDirectory () NameError: имя 'FTPDirectory' не определено - person Tom; 04.08.2010
comment
@Tom: как вы назвали мой модуль? Вы импортировали его в начале ftp_del.py? Если вы сохранили мой код как, скажем, ftptool.py, то в начале ftp_del.py вы должны import ftptool, а затем иметь классы с префиксом имени модуля, например folder = ftptool.FTPDirectory(). ISTM, вам нужно сначала прочитать учебник Python; это похоже на то, что вам не хватает базовых знаний о Python. - person tzot; 04.08.2010
comment
Привет, ΩΤΖΙΟΥ, в этом случае я назвал ваш модуль FTP_dir. Я импортирую это, как вы упомянули. Теперь вроде работает! Старые файлы удалены с моего тестового FTP-сервера, сейчас попробую в производственной среде. Большое спасибо за вашу помощь и помощь! Он отвечает в консоли с объектом ‹FTP_dir.FTPDirectory по адресу 0x00B6E590› Все выглядят ХОРОШО! - person Tom; 05.08.2010
comment
Он работал в тестовой среде FileZilla Server на базе Windows, но в продуктивной среде я получаю сообщение об ошибке: ftplib.error_perm: 500 Не могу понять «MLSD». Будет ли обходной путь для этой проблемы? Может ли провайдер просто включить команды MLSD? - person Tom; 05.08.2010
comment
Это потрясающий код! Некоторые вещи: @Tom MLSD был официально реализован в 2007 году, поэтому вам может потребоваться обновить свой FTP-сервер. Причина, по которой это было сделано, заключалась в том, что каждый FTP-сервер использовал другой формат со списком LIST. ПРИМЕЧАНИЕ. В строке надстройки функции вы должны преобразовать field_name в нижний регистр. Есть серверы, такие как ServU, которые возвращают имена полей в верхнем регистре. field_name = field_name.lower () - person SilentSteel; 16.07.2013
comment
Мне пришлось перевести field_name в нижний регистр, поскольку FTP-сервер возвращал Type, Modify и т. Д., И это проверяет type, modify и т. Д. - person David; 08.12.2016

Мне пришлось это сделать, и это заняло некоторое время, я подумал, что смогу сэкономить здесь время. Мы используем python с установленным модулем ftputil:

#! /usr/bin/python
import time
import ftputil
host = ftputil.FTPHost('ftphost.com', 'username', 'password')
mypath = 'ftp_dir'
now = time.time()
host.chdir(mypath)
names = host.listdir(host.curdir)
for name in names:
    if host.path.getmtime(name) < (now - (7 * 86400)):
      if host.path.isfile(name):
         host.remove(name)


print 'Closing FTP connection'
host.close()
person user2070320    schedule 15.07.2013

Хорошо, но вместо того, чтобы анализировать опубликованный вами код, вот пример, который может направить вас на верный путь.

from ftplib import FTP
import re

pattern = r'.* ([A-Z|a-z].. .. .....) (.*)'

def callback(line):
    found = re.match(pattern, line)
    if (found is not None):
        print found.groups()

ftp = FTP('myserver.wherever.com')
ftp.login('elvis','presley')
ftp.cwd('testing123')
ftp.retrlines('LIST',callback)

ftp.close()
del ftp

Запустите его, и вы получите что-то вроде этого, что должно стать началом того, чего вы пытаетесь достичь. Чтобы завершить его, вам нужно преобразовать первый результат в дату и время, сравнить его с «сейчас» и использовать ftp.delete (), чтобы избавиться от удаленного файла, если он слишком старый.

>>> 
('May 16 13:47', 'Thumbs.db')
('Feb 16 17:47', 'docs')
('Feb 23  2007', 'marvin')
('May 08  2009', 'notes')
('Aug 04  2009', 'other')
('Feb 11 18:24', 'ppp.xml')
('Jan 20  2010', 'reports')
('Oct 10  2005', 'transition')
>>> 
person eemz    schedule 19.05.2010
comment
Однако обратите внимание, что разные ftp-серверы по-разному форматируют вывод команды LIST, поэтому вам, возможно, придется изменить регулярное выражение, чтобы оно соответствовало тому, которое вы используете. - person eemz; 19.05.2010
comment
Привет, спасибо за ответ, я постараюсь соответствующим образом изменить свой код. - person Tom; 20.05.2010
comment
Мне нравится решение, очень простое, но не полное, у нас есть дела с датами и т. Д. - person Sérgio; 27.01.2014

Что ж, похоже, что ошибка, которую вы видите, связана с тем, что вы пытаетесь удалить каталог test123 со своего локального компьютера, а не с FTP-сайта. В документах FTP есть метод, называемый delete, и вот что вы хотите использовать для удаления файла. Что касается тестирования, существует ли что-то 7 дней назад или нет, вам, возможно, действительно придется временно вытащить эти файлы с FTP, а затем проверить время изменения перед использованием FTP.delete.

person Ben Hayden    schedule 19.05.2010
comment
Нет, он должен перейти в каталог test123, а затем удалить из него все файлы старше 7 дней. Устройство указывает, что не может найти каталог. - person Tom; 20.05.2010

На какой ОС вы работаете? Путь к файлу /test123/*.* в стиле Unix, но в сообщении указано WindowsError. Вы берете результат выполнения команды ftp LIST в стиле Unix и пытаетесь дословно использовать его в сценарии Windows?

person eemz    schedule 19.05.2010
comment
Hi работает на Windows 2003 Server, и в настоящее время он подключается к испытательному FTP-серверу, который работает на Windows XP. - person Tom; 20.05.2010