ftp连接失败常见原因为服务器启用ftps或被动模式被拦截,应改用ftp_tls并调用auth()和prot_p();上传中断因socket超时未设,需初始化时传timeout参数;定时任务失败多因环境差异,须设工作目录、绝对路径及日志;备份应加时间戳命名并校验文件完整性。

FTP连接失败:账号密码正确但ftplib.FTP.login()报错
常见现象是抛出 ftplib.error_perm: 530 Login incorrect,即使确认账号密码无误。这通常因为服务器启用了 FTPS(隐式/显式 TLS)或被动模式被防火墙拦截。
实操建议:
- 先用命令行验证连接:
ftp -p your-server.com(-p 表示被动模式),若失败再试lftp -u user,pass ftps://your-server.com - 若服务器要求加密,改用
ftplib.FTP_TLS,并立即调用auth()和prot_p():ftp = ftplib.FTP_TLS('your-server.com') ftp.login('user', 'pass') ftp.prot_p() # 启用数据通道加密 - 主动模式(PORT)在 NAT 或云主机上大概率失败,务必启用被动模式:
ftp.set_pasv(True)(默认就是 True,但显式写上更稳妥)
上传大文件时中断或卡住:storbinary()没响应
本质是 socket 超时未设置,尤其在低带宽、高延迟链路下,storbinary() 默认不设 timeout,可能挂起数分钟甚至更久。
实操建议:
- 初始化 FTP 对象时必须传入
timeout参数:ftp = ftplib.FTP(host, timeout=30) - 上传前检查本地文件是否存在且可读:
os.path.isfile(local_path) and os.access(local_path, os.R_OK) - 用
storbinary()时传入回调函数监控进度(非必需但实用):def progress(block): print('.', end='', flush=True) <p>with open(local_path, 'rb') as f: ftp.storbinary(f'STOR {remote_filename}', f, blocksize=8192, callback=progress) </p>
定时任务执行失败:cron 或 Windows 任务计划器里脚本不上传
根本原因不是 FTP 逻辑,而是环境差异——脚本在终端能跑,但定时任务中缺失工作目录、环境变量或 Python 路径。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
实操建议:
- 在脚本开头强制切换工作目录:
os.chdir(os.path.dirname(os.path.abspath(__file__))) - cron 中使用绝对路径调用 Python 和脚本:
0 2 * * * /usr/bin/python3 /home/user/backup.py - Windows 任务计划器中,“起始于”字段必须填脚本所在目录,否则
open('backup.zip')会找不到文件 - 加日志输出到文件,避免“静默失败”:
logging.basicConfig(filename='/var/log/ftp-backup.log', level=logging.INFO)
备份覆盖风险:同名文件被直接替换,无法回溯
直接用固定远程文件名(如 backup.zip)上传,等于每次覆盖,一旦上传损坏或源文件出错就丢数据。
实操建议:
- 生成带时间戳的远程文件名:
f'backup_{datetime.now().strftime("%Y%m%d_%H%M%S")}.zip' - 上传前用
ftp.nlst()检查是否存在同名文件(可选);更推荐定期清理旧备份,比如只保留最近 7 天:now = datetime.now() for name in ftp.nlst(): if name.startswith('backup_') and name.endswith('.zip'): try: dt = datetime.strptime(name[7:21], '%Y%m%d_%H%M%S') if (now - dt).days > 7: ftp.delete(name) except ValueError: continue # 名字格式不对,跳过
FTP 本身不提供原子上传或断点续传,上传中途失败就会留下残缺文件。如果备份文件大于 100MB,建议先压缩加密再上传,并在上传后用 ftp.size() 校验大小,或上传完成后执行一次 ftp.retrbinary('RETR '+remote_name, ...) 回拉校验 MD5——这点容易被忽略,但对关键备份很必要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










