有时候我们需要从FTP下载文件并做数据分析,首先我们需要能连接到ftp才能做到取文件并进行数据分析。按照正常的思路来解决这个问题是不难的。下面的代码是改良过得,借鉴了别人的一部分哦。下面是我的实现过程:
首先,我们需要引用连接ftp的插件,还有要建立与服务通信的话需要创建socket模块。socket的思路我理解是这样的过程,先是需要绑定本地ip和端口,监听连接是否是通的;然后循环接受来自客户端的连接请求,并把接受传来的数据发送给对方数据,最后关闭连接。整个过程官网的解释是通过套接字来关联起来的,不管是怎么说的,总之如果要取文件,必定需要建立一个媒介(可理解为搭桥),让A通过这个渠道把东西运送到目的地。
插件都构建完成后再来创建连接ftp服务器的方法
from ftplib import FTP
import socket
class GetFtpFile:
def __init__(self, host, port=21):
# print("__init__()---> host = %s ,port = %s" % (host, port))
self.host = host #ftp的ip地址
self.port = port # ftp地址的端口号
self.ftp = FTP()
# 设置编码方式
self.ftp.encoding = 'gbk'
self.log_file = open("log.txt", "a")
self.file_list = []
第二步,创建登录方法
def login(self, username, password): #传参-用户名和登录密码
try:
timeout = 60
socket.setdefaulttimeout(timeout)
# 0主动模式 1 #被动模式
self.ftp.set_pasv(True)
self.debug_print('开始尝试连接到 %s' % self.host)
self.ftp.connect(self.host, self.port)
self.debug_print('成功连接到 %s' % self.host)
self.debug_print('开始尝试登录到 %s' % self.host)
self.ftp.login(username, password)
self.debug_print('成功登录到 %s' % self.host)
self.debug_print(self.ftp.welcome)
except Exception as err:
self.deal_error("FTP 连接或登录失败 ,错误描述为:%s" % err)
pass
第三步,核心的部分了,下载服务器上的文件,这里分两步加一步判断,判断文件是否与下载过得文件大小相同,相同的不再下载了
def download_file_tree(self, local_path, remote_path): #local_path-本地路径,remote_path-ftp上的文件路径
print("download_file_tree()---> local_path = %s ,remote_path = %s" % (local_path, remote_path))
try:
self.ftp.cwd(remote_path)
except Exception as err:
self.debug_print('远程目录%s不存在,继续...' % remote_path + " ,具体错误描述为:%s" % err)
return
if not os.path.isdir(local_path):
self.debug_print('本地目录%s不存在,先创建本地目录' % local_path)
os.makedirs(local_path)
self.debug_print('切换至目录: %s' % self.ftp.pwd())
self.file_list = []
# 方法回调
self.ftp.dir(self.get_file_list)
remote_names = self.file_list
self.debug_print('远程目录 列表: %s' % remote_names)
for item in remote_names:
file_type = item[0]
file_name = item[1]
local = os.path.join(local_path, file_name)
if file_type == 'd':
print("download_file_tree()---> 下载目录: %s" % file_name)
self.download_file_tree(local, file_name)
elif file_type == '-':
print("download_file()---> 下载文件: %s" % file_name)
self.download_file(local, file_name)
self.ftp.cwd("..")
self.debug_print('返回上层目录 %s' % self.ftp.pwd())
return True
def is_same_size(self, local_file, remote_file):
"""判断远程文件和本地文件大小是否一致"""
try:
remote_file_size = self.ftp.size(remote_file)
except Exception as err:
remote_file_size = -1
try:
local_file_size = os.path.getsize(local_file)
except Exception as err:
local_file_size = -1
self.debug_print('local_file_size:%d , remote_file_size:%d' % (local_file_size, remote_file_size))
if remote_file_size == local_file_size:
return 1
else:
return 0
def download_file(self, local_file, remote_file): #is_same_size方法先判断文件是否相同
self.debug_print("download_file()---> local_path = %s ,remote_path = %s" % (local_file, remote_file))
if self.is_same_size(local_file, remote_file):
self.debug_print('%s 文件大小相同,无需下载' % local_file)
return
else:
try:
self.debug_print('>>>>>>>>>>>>下载文件 %s ... ...' % local_file)
buf_size = 1024
file_handler = open(local_file, 'wb')
self.ftp.retrbinary('RETR %s' % remote_file, file_handler.write, buf_size)
file_handler.close()
except Exception as err:
self.debug_print('下载文件出错,出现异常:%s ' % err)
return
if __name__ == "__main__":
my_ftp = GetFtpFile("ftp服务器ip地址")
my_ftp.login("ftp用户名", "密码")
# 下载目录
my_ftp.download_file_tree("本地文件路径", "ftp服务器文件路径")
my_ftp.close() #最后记得关闭服务器哦,以免消耗内存
其实还有提升的空间,如何上传文件到服务器呢? 我觉得这个应该需要有写入权限才可以的,后面再更新吧,写的不好欢迎大师多多指教~
附执行效果:
下载到本地的文件