1.背景。

最近接到一个任务,需要写一个python脚本,从客户公司的服务器拉取图片存放到我们公司的sftp服务器。

由于没头没脑,所以我采用无限遍历,将对方服务器中文件的路径原原本本的复制到我们公司的服务器。、

后来发现对方数据量过于庞大,所以决定将路径分别存放到多个csv中,csv就充当了数据库

然后第二个脚本是在csv里获取需要下载的图片地址将他存入sftp。

流程图

python sftp服务器 python搭建sftp服务器_服务器

2.ftp

刚开始写的是这样一个版本,后来因为运行到一半的时候,由于ftp连接断掉,脚本抛出异常停了,重头开始需要很多时间,所以后来又做了断点续传

import time
from ftplib import FTP
import os
import csv
"""
1.操作日志
2.
"""
data_num = 1

class FTP_OP(object):
    def __init__(self, host, username, password, port):
        """
        初始化ftp
        :param host: ftp主机ip
        :param username: ftp用户名
        :param password: ftp密码
        :param port:  ftp端口 (默认21)
        """
        self.host = host
        self.username = username
        self.password = password
        self.port = port
        self.csv = None

    def ftp_connect(self):
        """
        连接ftp
        :return:
        """
        ftp = FTP()
        ftp.set_debuglevel(0)  # 不开启调试模式
        ftp.connect(host=self.host, port=self.port)  # 连接ftp
        ftp.login(self.username, self.password)  # 登录ftp
        return ftp
    def download_file(self, dst_file_path ):
        """
        从ftp下载文件到本地
        :param dst_file_path: 本地存放路径
        :return:
        """
        ftp = self.ftp_connect()
        print(ftp.getwelcome() ) #显示登录ftp信息
        ftp.cwd("ftpstufGAP")
        for dir in ftp_file_path:
            ftp.cwd(dir)
            for file_name in ftp.nlst(ftp.pwd()):
                self.judge_file_dir(ftp, file_name, dst_file_path)
            ftp.cwd("..")
        ftp.quit()

    def judge_file_dir(self,ftp,file_name,dst_file_path):
        '''
        递归便利文件
        :param ftp: 
        :param file_name: 
        :param dst_file_path: 
        :return: 
        '''
        if file_name.find(".") != -1:
            if file_name.lower().endswith(".jpg") or file_name.lower().endswith(".png"):
                print("记录成功",file_name)
        else:
            ftp.cwd(file_name)
            for file_name in ftp.nlst(ftp.pwd()):
                res = self.judge_file_dir(ftp,file_name,dst_file_path)
                if not res:
                    continue
            ftp.cwd("..")

    def write_csv(self,ftp_file):
        '''将self.csv的数据写入data.csv文件'''
        global data_num
        ### 1万条写一个csv
        if len(self.csv)>10000:
            data_num +=1
            self.csv.clear()
            self.csv = [["Number", "FolderBane", "BarCode", "FileName"]]

        with open('downLoad/data/data%s.csv'%data_num, 'w',encoding="utf-8", newline='')as csv_file:
            # 获取一个csv对象进行内容写入
            writer = csv.writer(csv_file)
            for row in self.csv:
                # writerow 写入一行数据
                writer.writerow(row)
        return True

if __name__ == "__main__":
    host = "127.0.0.1"
    username = "anonymous"
    password = ""
    port = 21
    ftp_file_path = ["2020","2019"] # 下载的文件夹子
    dst_file_path = os.getcwd()
    ftp = FTP_OP(host=host, username=username, password=password, port=port)
    start_time = time.time()
    print("记录开始")
    ftp.download_file(dst_file_path)
    between_time = time.time()
    print("记录结束,用时%.2fs"%(between_time-start_time))

3.sftp 图片上传

将本地的文件上传到sftp服务器,由于paramiko,没有提供一次行创建多层目录的功能,所以采用了一个笨办法,把目录按"/"切割成字符串

在逐步拼接出目录,使用 sftp.listdir(sftp_path) 方法,如果抛出异常则目录不存在是用 sftp.mkdir(sftp_path)创建出这一级目录。

class SFTP_OP(object):
    def __init__(self, host, username, password, port):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.set= set()

    def sftp_upload(self,local_list,remote):
        sf = paramiko.Transport((self.host,self.port))
        sf.connect(username = self.username,password = self.password)
        sftp = paramiko.SFTPClient.from_transport(sf)
        for local_url in local_list:
            sftp_url = os.path.join(remote,local_url.split("downLoad/")[-1])
            sftp_path_list = sftp_url.split("/")[4:-1]
            sftp_path = "/upload/pim/photobaseimages"
            for path in sftp_path_list:
                sftp_path = sftp_path + "/" +path
                if sftp_path in self.set:
                    continue
                else:
                    try:
                        sftp.listdir(sftp_path)
                        self.set.add(sftp_path)
                    except Exception as e:
                        sftp.mkdir(sftp_path)
                        self.set.add(sftp_path)
            print("local_url"+local_url)
            print("sftp_url"+sftp_url)
            sftp.put(local_url,sftp_url)#上传文件
            print("上传成功",sftp_url)
        sf.close()