Скачать файлы с 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)

Ты можешь использовать fsspecs 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*"), но это может быть довольно медленно.

Другие вопросы по тегам