Python使用scp/paramiko获取文件时触发时间格式解析异常
环境信息
- Python 3.9
- scp 0.14.4
- 运行环境:Mac OSX Ventura 13.0
执行代码
def createSSHClient(server, port, user, password): client = SSHClient() client.load_system_host_keys() client.set_missing_host_key_policy(AutoAddPolicy()) client.connect(server, port, user, password) return client def get_file(): ssh = createSSHClient('myhost.com', 2022, 'username', 'mypassword') banner = ssh.exec_command('\n') scp = SCPClient(ssh.get_transport()) scp.get(remote_path='/mnt/users/username/file.txt', local_path='./file.txt', preserve_times=False) if __name__ == '__main__': get_file()
抛出异常
Traceback (most recent call last): File "/git/projects/diet/scp-example/.venv/lib/python3.9/site-packages/scp.py", line 437, in _set_time mtime = int(times[0]) ValueError: invalid literal for int() with base 10: b'his'
问题分析
异常源于scp库错误解析了服务器的登录Banner内容。即便设置了preserve_times=False,仍触发了时间解析逻辑。服务器返回的Banner内容如下:
Unauthorized use of this system is prohibited. Anyone using this system expressly consents to the monitoring of his or her system use and understands that evidence of criminal activity discovered by system personnel may be reported to law enforcement officials.
异常中的b'his'正是来自Banner里的对应字段。曾尝试在scp.get前执行命令清空Banner,但无效;手动通过CLI执行scp操作则可正常完成。
解决思路
彻底清理SSH通道的Banner输出:初始化SCPClient前,通过交互式shell读取所有缓冲区内容,避免后续scp命令读取到非预期文本:
def get_file(): ssh = createSSHClient('myhost.com', 2022, 'username', 'mypassword') # 清理Banner输出 shell = ssh.invoke_shell() while shell.recv_ready(): shell.recv(1024) scp = SCPClient(ssh.get_transport()) scp.get(remote_path='/mnt/users/username/file.txt', local_path='./file.txt', preserve_times=False)修改scp库的时间解析逻辑:找到scp安装目录下的
scp.py文件,修改_set_time方法,增加异常捕获忽略无法解析的内容:def _set_time(self, dest, times): if not self.preserve_times: return try: mtime = int(times[0]) atime = int(times[1]) if len(times) > 1 else mtime os.utime(dest, (atime, mtime)) except (ValueError, IndexError): # 跳过无法解析的非时间内容 pass改用paramiko的SFTP替代scp:SFTP不受Banner影响,稳定性更强,直接用内置功能实现文件下载:
def get_file(): ssh = createSSHClient('myhost.com', 2022, 'username', 'mypassword') sftp = ssh.open_sftp() sftp.get('/mnt/users/username/file.txt', './file.txt') sftp.close() ssh.close()
内容的提问来源于stack exchange,提问作者millerwa
相关产品推荐
相关产品推荐

