py实现ftp
https://www.cnblogs.com/wangziyi0513/p/11077323.html
参考原始代码:
修改了一下:
许多网友问中文路径乱码怎么办,我觉得应该讲中文路径转码后再发送。
ftpath = '/home/omcr/文档/{}'.format(y).encode('utf-8').decode('latin-1')
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/4/12 22:00 # @Author : zengsk in HoHai # edited by wh ''' FTP批量下载数据 ''' import os import sys from ftplib import FTP import datetime class FtpDownloadCls: def __init__(self, ftpserver, port, usrname, pwd, encode1, decode1): self.ftpserver = ftpserver # ftp主机IP self.port = port # ftp端口 self.usrname = usrname # 登陆用户名 self.pwd = pwd # 登陆密码 self.ftp = self.ftpConnect() # 用于中文编码解码, self.encode1 = encode1 self.decode1 = decode1 # ftp连接 def ftpConnect(self): ftp = FTP() try: ftp.connect(self.ftpserver, self.port) ftp.login(self.usrname, self.pwd) # python ftplib 默认的编码方式是latin-1 self.encode1 = ftp.encoding except: raise IOError('\n FTP login failed!!!') else: print(ftp.getwelcome()) print('\n+------- FTP connection successful!!! --------+\n') return ftp # 单个文件下载到本地 def downloadFile(self, ftpfile, localfile): bufsize = 1024 # 要在本地正确的显示中文,需要先通过latin-1编码成unicode,在解码成utf-8或GBK with open(localfile.encode(self.encode1).decode(self.decode1), 'wb') as fid: self.ftp.retrbinary('RETR {0}'.format(ftpfile), fid.write, bufsize) return True # 下载整个目录下的文件,包括子目录文件 def downloadFiles(self, ftpath, localpath): print('FTP PATH: {0}'.format(ftpath)) if not os.path.exists(localpath): os.makedirs(localpath) self.ftp.cwd(ftpath) print('\n+----------- downloading!!! -----------+\n') for i, file in enumerate(self.ftp.nlst()): print('{0} <> {1}'.format(i, file)) local = os.path.join(localpath, file) if os.path.isdir(file): # 判断是否为子目录 if not os.path.exists(local): os.makedirs(local) self.downloadFiles(file, local) else: self.downloadFile(file, local) self.ftp.cwd('..') return True # 退出FTP连接 def ftpDisConnect(self): self.ftp.quit() # 程序入口 if __name__ == '__main__': yesterday = (datetime.datetime.now() - datetime.timedelta(days = 1)) y = yesterday.strftime("%Y%m%d") # 输入参数 ftpserver = '10.20.20.1' # ftp主机IP port = 21 # ftp端口 usrname = 'omcr' # 登陆用户名 pwd = 'abcd.1' # 登陆密码 #ftpath = '/export/home/omcr/UMS8800_WKM_TDL_V3.0.0_26_20171013/LTE_WKM/webapps/WKMService/reportfile/计划报表/20190623/' # 远程文件夹 # 想要将路径中的中文正确发送到ftp服务器,需要先通过本地编码utf-8转换为unicode,在编码为latin-1,这样才能被ftplib模块正确发送给ftp服务器,虽然发送过去的中文编码是乱的 # 但服务器可以识别 ftpath = '/home/omcr/文档/{}'.format(y).encode('utf-8').decode('latin-1') localpath = 'D:/EC/data/{}'.format(y) # 本地文件夹(不要使用中文) Ftp = FtpDownloadCls(ftpserver, port, usrname, pwd, 'latin-1', 'utf-8') Ftp.downloadFiles(ftpath, localpath) Ftp.ftpDisConnect() print("\n+-------- OK!!! --------+\n") # 删除多余文件 dirPath = r'D:/EC/data' x = '' for f in os.listdir(dirPath): if not x in f: os.remove(os.path.join(dirPath, f))
实际使用脚本时,遇到几个问题:
1、没有遵守python语法,没有严格按空4个格的要求编写脚本,导致程序运行失败。
2、路径配置错误,solaris服务器路径从/export/home/......开始,linux服务器从/home/......开始,如果不注意,容易搞混。
3、服务器有两种中文编码:GBK和utf-8,容易搞混。
如果现场不会用cmd,则需要编写一个bat:
py ftpdown_weekendn.py pause
放在py脚本同一目录下,双击bat脚本执行后,cmd窗口会停在最后报错的地方。
第二版:
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/4/12 22:00 # @Author : zengsk in HoHai # edited by wh ''' FTP批量下载数据 ''' import os import sys from ftplib import FTP import datetime class FtpDownloadCls: def __init__(self, ftpserver, usrname, pwd, decode1, port=21, encode1='latin-1'): self.ftpserver = ftpserver # ftp主机IP self.port = port # ftp端口 self.usrname = usrname # 登陆用户名 self.pwd = pwd # 登陆密码 self.ftp = self.ftpConnect() # latin-1 self.encode1 = encode1 # 中文编码UTF-8或GBK self.decode1 = decode1 # ftp连接 def ftpConnect(self): ftp = FTP() try: ftp.connect(self.ftpserver, self.port, 30) ftp.login(self.usrname, self.pwd) self.encode1 = ftp.encoding except: raise IOError('\n FTP login failed!!!') else: print(ftp.getwelcome()) print('\n+------- FTP connection successful!!! --------+\n') return ftp # 单个文件下载到本地 def downloadFile(self, ftpfile, localfile): bufsize = 1024 with open(localfile, 'wb') as fid: self.ftp.retrbinary('RETR {0}'.format(ftpfile), fid.write, bufsize) return True # 下载整个目录下的文件,包括子目录文件 def downloadFiles(self, ftpath, localpath, save='', delete='', saveset=set(), deleteset=set()): ftppath_t = ftpath.encode(self.decode1).decode(self.encode1) print('FTP PATH: {0}'.format(ftpath)) if not os.path.exists(localpath): os.makedirs(localpath) self.ftp.cwd(ftppath_t) print('\n+----------- downloading!!! -----------+\n') flist = set() for i, file in enumerate(self.ftp.nlst()): filename = file.encode(self.encode1).decode(self.decode1) if save in filename and (delete not in filename or delete is ''): flist.add(filename) if saveset: flist = flist.intersection(saveset) flist = flist.difference(deleteset) for i, f in enumerate(flist): file = f.encode(self.decode1).decode(self.encode1) print('{0} <> {1}'.format(i, f)) local = os.path.join(localpath, f) self.downloadFile(file, local) self.ftp.cwd('..') return True # 退出FTP连接 def ftpDisConnect(self): self.ftp.quit() # 程序入口 if __name__ == '__main__': # 取前三天或者前N天的日期 datelist = [(datetime.datetime.now() - datetime.timedelta(days = x)) for x in range(1,4)] # 输入参数 # 服务器中文编码方式,不是UTF-8就是GBK s_code = 'GBK' ftpserver = '10.9.0.25' # ftp主机IP usrname = 'root' # 登陆用户名 pwd = 'aapswd' # 登陆密码 Ftp = FtpDownloadCls(ftpserver, usrname, pwd, s_code) for d in datelist: # 小北向目录格式20190703 y = d.strftime("%Y%m%d") ftppath1 = '/export/home/omcr/UMS_WKM_LTE-35/LTE_WKM/webapps/WKMService/reportfile/计划报表/{}/ENB/小时报表'.format(y) ftppath2 = '/export/home/omcr/UMS_WKM_LTE-35/LTE_WKM/webapps/WKMService/reportfile/计划报表/{}/ENB/天报表'.format(y) # 本地文件夹(不要使用中文) localpath = r'D:/EC/EC_XBX/{}/'.format(y) # 新增核对本地文件夹功能,有时ftp传输不稳定,没有传完就掉线了,需要二次执行脚本,这时本地路径下已有的文件就可以过滤出去,不必再次下载。 if os.path.exists(localpath): existfiles = set(os.listdir(localpath)) else: existfiles = set() # downloadFiles(a,b,c,d,e,f)第3个参数是过滤后留下的,第4个参数是过滤掉的 Ftp.downloadFiles(ftppath1, localpath, '', '', deleteset=existfiles) Ftp.downloadFiles(ftppath2, localpath, '', '', deleteset=existfiles) Ftp.ftpDisConnect() print("\n+-------- OK!!! --------+\n") # 第2组参数 # 服务器中文编码方式,不是UTF-8就是GBK s_code = 'GBK' ftpserver = '10.2.0.12' # ftp主机IP usrname = 'root' # 登陆用户名 pwd = 'root1234' # 登陆密码 Ftp = FtpDownloadCls(ftpserver, usrname, pwd, s_code) for d in datelist: # OMC日期格式2019-07-02 y_m_d = d.strftime("%Y-%m-%d") # 本地路径格式统一为20190703 y = d.strftime("%Y%m%d") ftppath1 = '/export/home/omcrftp/pm/reports/{}'.format(y_m_d) # 本地文件夹(不要使用中文) localpath = r'D:/EC/EC_OMC/{}'.format(y) if os.path.exists(localpath): existfiles = set(os.listdir(localpath)) else: existfiles = set() # downloadFiles(a,b,c,d,e,f)第3个参数是过滤后留下的,第4个参数是过滤掉的 Ftp.downloadFiles(ftppath1, localpath, '级_', '', deleteset=existfiles) Ftp.ftpDisConnect() print("\n+-------- OK!!! --------+\n")
安装python环境时,经常有win7老电脑(32bit)报错如下:
解决办法:
https://www.cnblogs.com/du-hong/p/10247997.html
api-ms-win-crt-process-l1-1-0.dll 丢失是因为缺少下边两个安装包
KB2999226、KB3118401更新下载:
KB2999226 微软下载链接 https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows
FTP登录超时:
修改31行:ftp.connect(self.ftpserver, self.port, 30),增加, 30参数
https://docs.python.org/3/library/ftplib.html#ftplib.FTP.connect