使用 Python 从包含给定字符串的 FTP 服务器下载文件
Download files from an FTP server containing given string using Python
我正在尝试从 FTP 服务器下载大量共享同一个字符串 (DEM
) 的文件。这些文件嵌套在多个目录中。例如,Adair/DEM*
和 Adams/DEM*
FTP 服务器位于此处:ftp://ftp.igsb.uiowa.edu/gis_library/counties/
,不需要用户名和密码。
所以,我想遍历每个县并下载包含字符串 DEM
.
的文件
我在这里阅读了很多关于 Stack Overflow 的问题和来自 Python 的文档,但无法弄清楚如何使用 ftplib.FTP()
在没有用户名和密码的情况下进入网站(这是不需要),我不知道如何在 ftplib 或 urllib 中使用 grep 或使用 glob.glob
。
在此先感谢您的帮助
好的,似乎有效。如果尝试下载目录或扫描文件,可能会出现问题。异常处理可能会很方便地捕获错误的文件类型并跳过。
glob.glob
无法工作,因为您在远程文件系统上,但您可以使用 fnmatch
来匹配名称
代码如下:它下载 TEMP 目录中所有匹配 *DEM*
的文件,按目录排序。
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)
with open(local_filename, 'wb') as fh:
fc.retrbinary('RETR '+ l + "/" + f, fh.write)
fc.close()
具有本地模式匹配的 是符合 FTP 标准的正确便携式解决方案。
尽管像 most FTP servers do support non-standard wildcard use with file listing commands 一样,您几乎总是可以使用更简单且更有效的解决方案,例如:
files = ftp.nlst("*DEM*")
for f in files:
with open(f, 'wb') as fh:
ftp.retrbinary('RETR ' + f, fh.write)
您可以使用 fsspec
s FTPFileSystem
在 FTP 服务器上方便地通配:
import fsspec.implementations.ftp
ftpfs = fsspec.implementations.ftp.FTPFileSystem("ftp.ncdc.noaa.gov")
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*")
,但它可能会很慢。
我正在尝试从 FTP 服务器下载大量共享同一个字符串 (DEM
) 的文件。这些文件嵌套在多个目录中。例如,Adair/DEM*
和 Adams/DEM*
FTP 服务器位于此处:ftp://ftp.igsb.uiowa.edu/gis_library/counties/
,不需要用户名和密码。
所以,我想遍历每个县并下载包含字符串 DEM
.
我在这里阅读了很多关于 Stack Overflow 的问题和来自 Python 的文档,但无法弄清楚如何使用 ftplib.FTP()
在没有用户名和密码的情况下进入网站(这是不需要),我不知道如何在 ftplib 或 urllib 中使用 grep 或使用 glob.glob
。
在此先感谢您的帮助
好的,似乎有效。如果尝试下载目录或扫描文件,可能会出现问题。异常处理可能会很方便地捕获错误的文件类型并跳过。
glob.glob
无法工作,因为您在远程文件系统上,但您可以使用 fnmatch
来匹配名称
代码如下:它下载 TEMP 目录中所有匹配 *DEM*
的文件,按目录排序。
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)
with open(local_filename, 'wb') as fh:
fc.retrbinary('RETR '+ l + "/" + f, fh.write)
fc.close()
具有本地模式匹配的
尽管像 most FTP servers do support non-standard wildcard use with file listing commands 一样,您几乎总是可以使用更简单且更有效的解决方案,例如:
files = ftp.nlst("*DEM*")
for f in files:
with open(f, 'wb') as fh:
ftp.retrbinary('RETR ' + f, fh.write)
您可以使用 fsspec
s FTPFileSystem
在 FTP 服务器上方便地通配:
import fsspec.implementations.ftp
ftpfs = fsspec.implementations.ftp.FTPFileSystem("ftp.ncdc.noaa.gov")
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*")
,但它可能会很慢。