Скачать файлы с FTP-сервера, содержащие заданную строку, используя python
Я пытаюсь загрузить большое количество файлов с общей строкой ('DEM') с FTP-сервера. Эти файлы вложены в несколько каталогов. Например, "Adair>DEM*" и "Adams>DEM*"
Сервер FTP находится здесь: ftp://ftp.igsb.uiowa.edu/gis_library/counties/ и не требует имени пользователя и пароля. Итак, я хотел бы пройтись по каждому округу и скачать файлы, содержащие строку "DEM"
Я прочитал здесь много вопросов о стеке и документации от python, но не могу понять, как использовать ftplib.FTP() для входа на сайт без имени пользователя и пароля (что не обязательно), и я не могу понять Узнайте, как использовать greb.glob внутри ftplib или urllib.
Заранее спасибо за помощь
3 ответа
Ок, похоже на работу. Могут возникнуть проблемы при попытке загрузить каталог или отсканировать файл. Обработка исключений может оказаться полезной для отлова неправильных типов файлов и пропуска.
glob.glob
не может работать, так как вы находитесь на удаленной файловой системе, но вы можете использовать fnmatch
соответствовать именам
Вот код: он загружает все файлы, соответствующие *DEM*
в каталоге TEMP, сортировка по каталогу.
import ftplib,sys,fnmatch,os
output_root = os.getenv("TEMP")
fc = ftplib.FTP("ftp.igsb.uiowa.edu")
fc.login()
fc.cwd("/gis_library/counties")
root_dirs = fc.nlst()
for l in root_dirs:
sys.stderr.write(l + " ...\n")
#print(fc.size(l))
dir_files = fc.nlst(l)
local_dir = os.path.join(output_root,l)
if not os.path.exists(local_dir):
os.mkdir(local_dir)
for f in dir_files:
if fnmatch.fnmatch(f,"*DEM*"): # cannot use glob.glob
sys.stderr.write("downloading "+l+"/"+f+" ...\n")
local_filename = os.path.join(local_dir,f)
fh = open(local_filename, 'wb')
fc.retrbinary('RETR '+ l + "/" + f, fh.write)
fc.close()
Ответ на @Jean с местным сопоставлением с образцом является правильным портативным решением придерживаясь стандартами FTP.
Хотя большинство FTP-серверов поддерживают нестандартное использование подстановочных знаков с командами вывода списка файлов, вы почти всегда можете использовать более простое и в основном более эффективное решение, например:
files = ftp.nlst("*DEM*")
for f in files:
with open(f, 'wb') as fh:
ftp.retrbinary('RETR ' + f, fh.write)
Ты можешь использовать fsspec
s FTPFileSystem
:
import fsspec.implementations.ftp
ftpfs = fsspec.implementations.ftp.FTPFileSystem("ftp.ncdc.noaa.gov")
ftpfs.glob("/pub/data/swdi/stormevents/csvfiles/*1985*")
files = ftpfs.glob("/pub/data/swdi/stormevents/csvfiles/*1985*")
print(files)
contents = ftpfs.cat(files[0])
print(contents[:100])
Результат:
['/pub/data/swdi/stormevents/csvfiles/StormEvents_details-ftp_v1.0_d1985_c20160223.csv.gz', '/pub/data/swdi/stormevents/csvfiles/StormEvents_fatalities-ftp_v1.0_d1985_c20160223.csv.gz', '/pub/data/swdi/stormevents/csvfiles/StormEvents_locations-ftp_v1.0_d1985_c20160223.csv.gz']
b'\x1f\x8b\x08\x08\xcb\xd8\xccV\x00\x03StormEvents_details-ftp_v1.0_d1985_c20160223.csv\x00\xd4\xfd[\x93\x1c;r\xe7\x8b\xbe\x9fOA\xe3\xd39f\xb1h\x81[\\\xf8\x16U\x95\xac\xca\xc5\xacL*3\x8b\xd5\xd4\x8bL\xd2\xb4\x9d'
Также работает вложенный поиск, например,
nested_files = ftpfs.glob("/pub/data/swdi/stormevents/**1985*")
, но это может быть довольно медленно.