Следующие два сценария призваны удовлетворить эту потребность. Первый из них, downloadflat.py, автоматически загружает (то есть копирует) по FTP все файлы из каталога удаленного сайта в каталог на локальном компьютере. В настоящее время я храню основные копии файлов моего сайта на своем ПК, но в действительности использую этот сценарий двумя способами:
• Чтобы загрузить мой веб-сайт на клиентский компьютер, где я хочу заняться редактированием, я загружаю содержимое веб-каталога своей учетной записи на сервере моего интернет-провайдера.
• Чтобы сделать зеркальную копию моего сайта на другом сервере, я периодически выполняю этот сценарий на целевом компьютере, если он поддерживает Telnet или безопасную оболочку SSH — в противном случае я просто загружаю файлы веб-сервера на один компьютер и выгружаю их оттуда на требуемый сервер.
Вообще говоря, этот сценарий (представленный в примере 13.10) загрузит полный каталог файлов на любой компьютер с Python и сокетами с любого компьютера, на котором работает сервер FTP.
Пример 13.10. PP4E\Internet\Ftp\Mirror\downloadflat.py
#!/bin/env python """
############################################################################ использует протокол FTP для копирования (загрузки) всех файлов из единственного каталога на удаленном сайте в каталог на локальном компьютере; запускайте этот сценарий периодически для создания зеркала плоского каталога FTP-сайта, находящегося на сервере вашего провайдера; для анонимного доступа установите переменную remoteuser в значение ‘anonymous‘; чтобы пропускать ошибки загрузки файлов, можно было бы использовать инструкцию try, но в случае таких ошибок FTP-соединение скорее всего все равно будет закрыто автоматически; можно было бы перед передачей каждого нового файла переустанавливать соединение, создавая новый экземпляр класса FTP: сейчас устанавливается всего одно соединение; в случае неудачи попробуйте записать в переменную nonpassive значение True, чтобы использовать активный режим FTP, или отключите брандмауэр; кроме того, работоспособность этого сценария зависит от настроек сервера FTP и возможных ограничений на загрузку.
############################################################################
import os, sys, ftplib
from getpass import getpass
from mimetypes import guess_type
nonpassive = False # в 2.1+ по умолчанию пассивный режим FTP
remotesite = ‘home.rmi.net’ # загрузить с этого сайта
remotedir = ‘.’ # и из этого каталога (например, public_html)
remoteuser = ‘lutz’
remotepass = getpass(‘Password for %s on %s: ‘ % (remoteuser, remotesite)) localdir = (len(sys.argv) > 1 and sys.argv[1]) or ‘.’
cleanall = input(‘Clean local directory first? ‘)[:1] in [‘y’, ‘Y’]
print(‘connecting…’)
connection = ftplib.FTP(remotesite) # соединиться с FTP—сайтом
connection.login(remoteuser, remotepass) # зарегистрироваться
# с именем/паролем
connection.cwd(remotedir) # перейти в копируемый каталог
if nonpassive: # принудительный переход
# в активный режим FTP
connection.set_pasv(False) # большинство серверов работают
# в пассивном режиме
if cleanall: # сначала удалить все локальные
for localname in os.listdir(localdir): # файлы, чтобы избавиться от
try: # устаревших копий os.listdir
print(‘deleting local’, localname) # пропускает . и ..
os.remove(os.path.join(localdir, localname))
except:
print(‘cannot delete local’, localname)
count = 0 # загрузить все файлы из удаленного каталога
remotefiles = connection.nlst() # nlst() возвращает список файлов
# dir() возвращает полный список
for remotename in remotefiles:
if remotename in (‘.’, ‘..’): continue # некоторые серверы
# включают . и ..
mimetype, encoding = guess_type(remotename) # например,
# (‘text/plain’,’gzip’) mimetype = mimetype or ‘?/?’ # допускается (None, None)
maintype = mimetype.split(‘/’)[0] # .jpg (‘image/jpeg’, None’)
localpath = os.path.join(localdir, remotename) print(‘downloading’, remotename, ‘to’, localpath, end=’ ‘) print(‘as’, maintype, encoding or »)
if maintype == ‘text’ and encoding == None:
# использовать текстовый файл и режим передачи ascii
# использовать кодировку, совместимую с ftplib
localfile = open(localpath, ‘w’, encoding=connection.encoding) callback = lambda line: localfile.write(line + ‘\n’) connection.retrlines(‘RETR ‘ + remotename, callback)
else:
# использовать двоичный файл и двоичный режим предачи localfile = open(localpath, ‘wb‘)
connection.retrbinary(‘RETR ‘ + remotename, localfile.write)
localfile.close() count += 1
connection.quit()
print(‘Done:’, count, ‘files downloaded.’)
В этом примере не так много нового для обсуждения в сравнении с примерами использования протокола FTP, которые мы видели выше. Здесь мы открываем соединение с удаленным сервером FTP, регистрируемся с необходимыми именем пользователя и паролем (в этом сценарии не используется анонимный доступ к FTP) и переходим в требуемый удаленный каталог. Новыми здесь, однако, являются циклы обхода всех файлов в локальном и удаленном каталогах, загрузка в текстовом режиме и удаление файлов:
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011