You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

request.urlopen访问FTP含西里尔字符文件报550找不到文件编码问题求解

解决方案

方案1:优先推荐 - 自定义FTPHandler指定编码(无侵入,可灵活传编码参数)

原生urllib未暴露FTP编码配置入口,可通过继承FTPHandler重写连接逻辑实现自定义编码,完全满足你传入编码自动赋值给ftplib.FTP实例的需求:

from urllib.request import FTPHandler, build_opener
import ftplib

class EncodedFTPHandler(FTPHandler):
    def __init__(self, ftp_encoding='utf-8', *args, **kwargs):
        self.ftp_encoding = ftp_encoding
        super().__init__(*args, **kwargs)
    
    def connect_ftp(self, user, passwd, host, port, dirs, timeout=None):
        ftp = ftplib.FTP(timeout=timeout)
        # 自定义编码赋值,支持utf-8、cp1251任意切换
        ftp.encoding = self.ftp_encoding
        ftp.connect(host, port)
        ftp.login(user, passwd)
        # 对应你之前的UTF8开启逻辑,非UTF8编码可跳过
        if self.ftp_encoding == 'utf-8':
            try:
                ftp.sendcmd('OPTS UTF8 ON')
            except:
                pass
        ftp.cwd('/'.join(dirs))
        return ftp

调用方式如下,返回的响应和原生urlopen完全一致,是addinfourl对象,不影响你后续解析大体积XML:

# 需要cp1251时直接修改ftp_encoding参数即可
opener = build_opener(EncodedFTPHandler(ftp_encoding='utf-8'))
url = 'ftp://login:password@ftpaddr:21/folder/Message_БП_TT.xml'
# 无需手动做编码转换,直接传入原始URL
resp = opener.open(url)

方案2:全局猴子补丁修改默认编码(适合快速验证场景)

如果不需要多编码灵活切换,可直接修改ftpwrapper的全局默认配置:

from urllib.request import ftpwrapper
import ftplib

original_init = ftpwrapper.__init__
def patched_init(self, host, user, passwd, acct, timeout=None):
    original_init(self, host, user, passwd, acct, timeout)
    # 全局修改FTP编码为utf-8
    self.ftp.encoding = 'utf-8'
    try:
        self.ftp.sendcmd('OPTS UTF8 ON')
    except:
        pass
ftpwrapper.__init__ = patched_init

# 后续调用原生urlopen无需额外处理
from urllib import request
url = 'ftp://login:password@ftpaddr:21/folder/Message_БП_TT.xml'
resp = request.urlopen(url)

多FTP服务兼容逻辑

你遇到的部分服务正常、部分报错的问题,本质是不同FTP服务端的默认文件名编码不同:开启了UTF8支持的服务用utf-8编码,俄语区未开UTF8的服务默认用cp1251编码,可增加降级逻辑自动适配:

def get_ftp_resp(url, encodings=['utf-8', 'cp1251']):
    for encoding in encodings:
        opener = build_opener(EncodedFTPHandler(ftp_encoding=encoding))
        try:
            return opener.open(url)
        except Exception as e:
            if '550 The system cannot find the file specified' in str(e):
                continue
            raise
    raise Exception("所有编码均无法匹配当前FTP服务配置")

内容的提问来源于stack exchange,提问作者Skaper1101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 06:45:03