python从ftp抓取最近三天数据

不啰嗦,直接上代码:

import ftplib
import os
import socket
import sys
import time

HOST = '**'  # ftp地址
USER = '**'  # 用户名
PASSWD = '**'  # 用户密码

LocalDir = r'**'  # 本地存贮路径
FTPDir = sys.argv[1]  # 需要下载的ftp目录路径
local_fname = 'checkfile.txt'  # 用本地存放已下载过的文件名

local_files = []  # 存放从checkfile.txt中读回的文件名
appendFiles = []  # 存放需要写进checkfile.txt的文件各


def FtpConnect(host, username, passwd):
    '''
    连接并登录ftp服务器

    host:ftp地址
    username:用户名
    passwd:用户密码
    '''
    try:
        ftp = ftplib.FTP(HOST)
        # ftp.encoding = 'utf-8' #解决中文乱码问题
        # ftp.set_debuglevel(0)  #不开启调试模式
    except (socket.error, socket.gaierror):
        print('Error, cannot reach ' + HOST)
        return None
    else:
        print('Connect To Host Success...')

    try:
        ftp.login(USER, PASSWD)
    except ftplib.error_perm:
        print('Username or Passwd Error')
        # ftp.quit()
        return None
    else:
        print(ftp.getwelcome())  # 显示登录ftp信息
        print('Login Success...')
        ftp.dir()  # 显示目录下所有目录信息
        print("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
    return ftp


def filelist(ftp):
    '''
    递归ftp当前目录下的所有文件及目录信息
    '''
    flist = []
    ftp.dir('.', flist.append)  # 将目录中的内容存进flist列表
    files = [f.split()[-1] for f in flist if f.startswith('-')]  # 读取flist列表中的信息,以-开头的是常规文件,将该信息以空字符分割成列表,取最后的元素即为文件名
    fids = [f.split(None, 4)[-1] for f in flist if f.startswith('-')]  # 读取flist列表中的信息,以-开头的是常规文件,将该信息以前4个空字符分割成列表,
    # 最后的元素包括了文件的大小,修改日期时间,可作为文件的标识
    dictf = dict(zip(files, fids))  # 将文件名与对应的标识合成字典
    dirs = [f.split()[-1] for f in flist if f.startswith('d')]  # 读取flist列表中的信息,以d开头的是目录,将该信息以空字符分割成列表,取最后的元素即为目录名
    # print(dirs)
    return (dictf, dirs)


def FtpDownloadDir(ftp, ftp_dir, local_dir):
    '''
    递归下载ftp指定目录下的所有文件及目录
    '''
    print('+++++++++++++++++++++++++++++++++++++++++++++++++++++')
    print(f'Walking to {ftp_dir}')
    print(f'Walking to {local_dir}')
    if ftp_dir == "/":
        dirname = "AllDir"  # 用于本地创建新目录,如果下载的是FTP根目录,则在目录名为AllDir
    else:
        dirname = os.path.basename(ftp_dir)  # 否则本地目录名与FTP目录名一样

    ftp.cwd(ftp_dir)  # 进入ftp对应目录
    os.chdir(local_dir)  # 进入本地下载目录

    if os.path.exists(dirname):  # 如果本地dirname目录已存在
        os.chdir(dirname)  # 则直接进入该目录
    else:
        try:
            os.mkdir(dirname)  # 否则在本地创建该目录
        except OSError:
            print('OSError!')
        else:
            os.chdir(dirname)  # 创建完后进入该目录

    ftp_curr_dir = ftp.pwd()  # 获取FTP当前目录路径
    print(ftp_curr_dir)
    local_curr_dir = os.getcwd()  # 获取本地当前目录路径
    # print(f'Changing to {ftp_curr_dir}')
    # print(f'Changing to {local_curr_dir}')

    dictf, dirs = filelist(ftp)  # 调用filelist函数,递归ftp当前目录下的所有文件及目录

    for f, k in dictf.items():  # 获取到的文件信息的键值对
        if ".tif" not in f or ".tif" not in k:
            continue
        else:
            if k not in local_files:  # 文件标识与本地存储的已下载过的文件标识做对比
                FtpDownloadFile(ftp, f, f)  # k不在local_files中说明该文件未下载过,则下载该文件
                appendFiles.append(k)  # 同时将该文件的标识存储到appenFiles列表中,用于下载完成后更新本地的checkfile.txt文件

    for d in dirs:  # 对子目录进行处理
        if isVaildDate(d):
            if compare_time(d) + 24*3600*3 >= 0:    #抓取最近三天的
                FtpDownloadDir(ftp, d, local_curr_dir)  # 调用自身,递归下载子目录中的文件
                ftp.cwd('..')
                os.chdir('..')  # 每次递归完成后,ftp及本地都返回上一层目录,继续其他子目录的处理
        else:
            FtpDownloadDir(ftp, d, local_curr_dir)  # 调用自身,递归下载子目录中的文件
            ftp.cwd('..')
            os.chdir('..')  # 每次递归完成后,ftp及本地都返回上一层目录,继续其他子目录的处理
    os.chdir(local_dir)

def isVaildDate(date):
    try:
        if len(date) == 4:
            time.strptime(date, "%Y")
            return True
        if len(date) == 6:
            time.strptime(date, "%Y%m")
            return True
        if len(date) == 8:
            time.strptime(date, "%Y%m%d")
            return True
        return False
    except:
        return False 

def compare_time(time1):
    fmt="%Y"
    if len(time1) == 6:
        fmt="%Y%m"
    if len(time1) == 8:
        fmt="%Y%m%d"
    time2=time.strftime(fmt,time.localtime(time.time()))
    s_time = time.mktime(time.strptime(time1,fmt))
    e_time = time.mktime(time.strptime(time2,fmt))
    return int(s_time) - int(e_time)

def FtpDownloadFile(ftp, remotefile, localfile):
    '''
    下载ftp当前目录的文件到本地的当前目录中
    '''
    buffer_size = 10240  # 默认是8192
    try:
        f = open(localfile, 'wb')
        ftp.retrbinary(f'RETR {remotefile}', f.write, buffer_size)
    except ftplib.error_perm:
        print(f'File:{f} Download Error')
        # os.unlink(localpath)
    else:
        print(f'File:{f} Download Success...')
    finally:
        f.close()


def operfile(fileTxt, op):
    '''
    操作下载目录中的文件人工
    op为'r'时读取该文件,如文件不存在则忽略
    op为'w'时追加写入文件
    '''
    fp = os.path.join(LocalDir, fileTxt)
    if op == 'r':
        print(f'从 {fp} 中读取本地文件列表')
        try:
            with open(fp, 'r')as ft:
                for line in ft:
                    line = line.strip()
                    local_files.append(line)
        except Exception as e:
            print(e)
    elif op == 'w':
        print(f'更新 {fileTxt} 中文件列表')
        try:
            with open(fp, 'a') as ft:
                ft.writelines([f'{x}\n' for x in appendFiles])
        except Exception as e:
            print(e)
    else:
        print("参数2请输入'r'或者'w'!")


if __name__ == '__main__':
    config = sys.argv[1]
    ftp = FtpConnect(HOST, USER, PASSWD)  # 连接并登录ftp服务器
    ftp.encoding = 'utf-8'
    if ftp:  # 如果登录成功
        operfile(local_fname, 'r')  # 从checkfile.txt中获取已下载过的文件
        FtpDownloadDir(ftp, FTPDir, LocalDir)  # 将ftp指定目录下的文件更新到本地目录中
        if appendFiles:  # 如果有新文件更新到本地
            operfile(local_fname, 'w')  # 则将其追加到checkfile.txt中
            appendFiles = []  # 清空列表
        else:
            print(f'无需更新{local_fname}')
        ftp.quit()
        print("FTP QUIT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")

 感谢支持技术分享,请扫码点赞支持:

技术合作交流qq:2401315930

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兴诚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值