首先将指定文件夹压缩,然后通过sftp协议上传到远程服务器上
注: 如果开启定时任务在每天凌晨将前一天的文件夹上传到远程,后续产生的文件夹须以日期进行命名
1、使用python3 main.py --first命令会将本地指定路径下所有文件上传
2、使用python3 main.py命令会开启定时任务
main.py
# -*- coding: utf-8 -*-
# @Author: lcb
# @Time: 2021/9/3
# @Desc: 定时任务
# @注意事项:1、操作本地主机家目录外的文件需求权限时,需要root权限运行此程序
# 2、注意必须修改第34行SERIAL 的标识,否则不同主机的文件全部存放在一个文件夹下会产生覆盖
import os
import sys
import zipfile
import datetime
import logging
try:
import paramiko
except:
print("install module paramiko...")
os.system("pip3 install -i http://pypi.douban.com/simple/ paramiko --trusted-host pypi.douban.com")
import paramiko
try:
from apscheduler.schedulers.blocking import BlockingScheduler
except:
print("install module APScheduler...")
os.system("pip3 install -i http://pypi.douban.com/simple/ APScheduler --trusted-host pypi.douban.com")
from apscheduler.schedulers.blocking import BlockingScheduler
LOCAL_PATH = "本地路径"
SERVER_PATH = "远程路径"
HOST = "远程服务器ip"
PORT = 22
USERNAME = "用户名"
PASSWORD = "密码"
# 不同主机的标识,根据标识在远程服务器上创建该命名对应的文件夹,此后把本地主机上的文件全部存放在此文件夹下
SERIAL = "1"
log_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "upfile.log")
# 日志记录
def init_log(file='./upfile.log'):
formatter = logging.Formatter('%(asctime)s %(pathname)s [line: %(lineno)d] %(levelname)s %(message)s')
logger = logging.getLogger('server-log')
logger.setLevel(logging.DEBUG)
filehandle = logging.FileHandler(file)
filehandle.setLevel(logging.INFO)
filehandle.setFormatter(formatter)
logger.addHandler(filehandle)
return logger
# 压缩文件夹
def zip_file(file_path):
"""
@param file_path: 要压缩的文件夹
@return:
"""
file_news = file_path + '.zip' # 压缩后文件夹的名字
z = zipfile.ZipFile(file_news, 'w', zipfile.ZIP_DEFLATED)
for dir_path, dir_names, file_names in os.walk(file_path):
f_path = dir_path.replace(file_path, '') # 这一句很重要,不replace的话,就从根目录开始复制
f_path = f_path and f_path + os.sep or '' # 实现当前文件夹以及包含的所有文件的压缩
for filename in file_names:
z.write(os.path.join(dir_path, filename), f_path + filename)
z.close()
return file_news
# 上传文件(只上传单个文件,不上传文件夹)
def sftp_upload(file_path):
"""
@param file_path: 本地文件
@return:
"""
# 创建ssh对象
s = paramiko.SSHClient()
# 允许链接不在know_hosts文件中的主机
s.set_missing_host_key_policy(paramiko.AutoAddPolicy)
# 连接服务器
s.connect(hostname=HOST, port=PORT, username=USERNAME, password=PASSWORD)
# 执行linux命令, 创建对应的文件夹
s.exec_command('mkdir -p %s' % (os.path.join(SERVER_PATH, SERIAL)))
sftp = s.open_sftp()
# 拼接远程服务器路径
file_name = file_path.split(os.sep)[-1]
server_path = os.path.join(SERVER_PATH, SERIAL, file_name)
try:
sftp.put(file_path, server_path)
logger.info(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " " + file_path + " 上传结束!")
return True, file_name
except Exception as e:
logger.error('上传失败!error:%s' % e)
return False, file_name
def task_start(first=False):
# 第一次上传,直接运行python main.py --first, 会将除今天外的所有的文件夹打包发送
if first:
logger.info("*****************first time to upload*******************")
for dir in os.listdir(LOCAL_PATH):
if os.path.join(LOCAL_PATH, dir).endswith(".zip"):
continue
# 压缩文件夹
file_path = zip_file(os.path.join(LOCAL_PATH, dir))
# 上传压缩包
res, file_name = sftp_upload(file_path)
if res:
# 删除压缩包
os.remove(os.path.join(LOCAL_PATH, file_name))
else:
logger.error("上传文件 " + file_name + " 到远程服务器失败!")
# 执行完第一次上传任务后,运行python main.py, 开启定时任务,每天凌晨00:00将前一天的文件夹打包发送
else:
logger.info("*******************crontab task begin********************")
yesterday = datetime.datetime.today()-datetime.timedelta(days=1)
date = yesterday.strftime("%Y-%m-%d")
file_dir = os.path.join(LOCAL_PATH, date)
if not os.path.exists(file_dir):
logger.info("不存在 %s 目录" % file_dir)
return
file_path = zip_file(file_dir)
res, file_name = sftp_upload(file_path)
if res:
os.remove(os.path.join(LOCAL_PATH, file_name))
else:
logger.error("上传文件 " + file_name + " 到远程服务器失败!")
logger = init_log(file=log_file)
if __name__ == "__main__":
if len(sys.argv) == 2 and sys.argv[1] == "--first":
print("first")
task_start(first=True)
elif len(sys.argv) == 1:
print("not first")
scheduler = BlockingScheduler()
# 定时任务,每天00:00点执行一次
scheduler.add_job(task_start, 'cron', hour='00', minute='00')
try:
scheduler.start()
except Exception as e:
pass
else:
print("args error...")