【问题标题】:Download files from an FTP server containing given string using Python使用 Python 从包含给定字符串的 FTP 服务器下载文件
【发布时间】:2016-12-20 23:15:38
【问题描述】:

我正在尝试从 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。

提前感谢您的帮助

【问题讨论】:

    标签: python ftp ftplib


    【解决方案1】:

    您可以使用 fsspecs FTPFileSystem 在 FTP 服务器上方便地进行 globbing:

    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*"),但它可能会很慢。

    【讨论】:

      【解决方案2】:

      好的,看来可以了。如果尝试下载目录或扫描文件,可能会出现问题。异常处理可以方便地捕获错误的文件类型并跳过。

      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()
      

      【讨论】:

        【解决方案3】:

        具有本地模式匹配的answer by @Jean 是符合 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)
        

        【讨论】:

          猜你喜欢
          • 2021-02-21
          • 2015-06-30
          • 2012-07-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-21
          • 1970-01-01
          相关资源
          最近更新 更多