XML文件如何通过FTP下载 Python脚本登录FTP获取XML

6次阅读

常见错误是未正确处理被动模式、账号密码格式错误、未用二进制模式下载xml导致乱码或解析失败,以及路径错误或命令不支持等问题。

XML文件如何通过FTP下载 Python脚本登录FTP获取XML

ftplib 下载 XML 文件时连不上 FTP 服务器

常见错误是没处理被动模式(PASV)或账号密码传错格式。很多 FTP 服务默认要求 PASV,而 ftplib.FTP 初始化后默认开启 PASV,但有些防火墙或 NAT 环境下它会失败;此时得手动关掉:ftp.set_pasv(False)。另外,login() 的参数顺序是 user 在前、passwd 在后,空密码不能传 None,得传空字符串 ''

  • 检查 FTP 地址是否带 ftp:// 前缀——ftplib 不认这个,只接受纯主机名或 IP
  • 端口不填默认是 21,如果服务跑在非标端口(比如 2121),得显式传 FTP(host, user, passwd, port=2121)
  • 遇到 530 Login incorrect,先确认账号密码大小写、是否需要域名前缀(如 domainuser

下载的 XML 文件内容乱码或不完整

根本原因是没用二进制模式传输。XML 虽然是文本,但 FTP 协议里必须明确指定传输模式:RETR 前必须调用 ftp.cwd() 切到目录后,用 ftp.retrbinary() 而不是 ftp.retrlines()。后者会按行转换换行符,破坏 XML 声明和编码声明(比如把 <?xml version="1.0" encoding="UTF-8"?> 里的 rn 搞错,导致解析失败)。

  • retrbinary()回调函数里直接写入文件,别用 decode()——文件对象要以 'wb' 模式打开
  • 如果 XML 本身含中文且声明为 encoding="GBK",下载完再用对应编码读取,不要在 FTP 层做解码
  • 下载大文件时加个回调打点进度,避免卡住无感知:Lambda data: fp.write(data) 就够,不用额外计数

脚本跑在 linux 服务器上却提示 ftplib.error_perm: 550 Failed to change Directory

这通常不是权限问题,而是路径写错了。FTP 的根目录不等于服务器系统根目录,ftp.cwd('/') 切的是 FTP 用户的 home 目录(比如 /var/ftp/user/),不是系统 /。而且路径分隔符必须用 '/',不能用 ''os.sep

  • 先用 ftp.pwd() 打印当前路径,再用 ftp.nlst() 看有哪些文件,确认目标 XML 确实在那儿
  • 路径中含空格或中文?FTP 协议对这类字符支持差,优先改名或换路径,别硬上 urllib.parse.quote()
  • 某些 FTP 服务(如 vsftpd)禁用了 SYSTMLSD 命令,nlst() 可能返回空列表,这时得靠 dir() 解析文本输出——但不推荐,容易因格式变化崩

想自动下载最新 XML,但 FTP 不支持通配符或时间筛选

FTP 协议本身没有“按修改时间排序”或“匹配 *.xml”的功能。你只能先 nlst() 拿全量文件名,再用 python 自己过滤和排序。注意:返回的文件名不含路径,nlst('data/')nlst() 结果不同,前者只列子目录内容,后者列当前目录。

立即学习Python免费学习笔记(深入)”;

  • sorted(ftp.nlst(), key=lambda f: f.lower()) 按字母排,适用于命名含日期(如 report_20240520.xml
  • 如果文件名无规律,只能靠 ftp.sendcmd('MDTM filename.xml') 拿修改时间(返回形如 213 20240520142312),但不是所有 FTP 服务都支持 MDTM
  • 别在循环里反复 retrbinary() 每个文件——先筛出目标文件名,再下,否则网络开销翻倍

事情说清了就结束。FTP 没有状态、不记上下文,每一步都要自己确认当前路径、文件存在性、传输模式,靠猜不如多打一行 print(ftp.pwd())

text=ZqhQzanResources