摘要

本博文将详细的介绍的python的相关error问题与解决方案。

一、python 出现paramiko.ssh_exception.SSHException:

aramiko模块上传文件失败,提示paramiko.ssh_exception.SSHException: Channel closed.

使用python3 paramiko库实现向远程服务器上传文件,脚本如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid
import os

class Haproxy(object):

def __init__(self):
self.host = '10.224.96.87'
self.port = 22
self.username = 'root'
self.pwd = 'tahoe.webex'
self.__k = None

def create_file(self):
file_name = str(uuid.uuid4())
with open(file_name,'w') as f:
f.write('sb')
return file_name

def run(self):
self.connect()
self.upload()
# self.rename()
#self.close()

def connect(self):
transport = paramiko.Transport((self.host,self.port))
transport.connect(username=self.username,password=self.pwd)
self.__transport = transport
print("Connected to %s as %s" % (self.host, self.username))

def close(self):

self.__transport.close()

def upload(self):
# 连接,上传
#file_name = self.create_file()
localpath= r'C:\PF\cpu_memory.py'
remotepath = r'/home/test.py'
sftp = paramiko.SFTPClient.from_transport(self.__transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put(localpath, remotepath)
print("File %s has uploaded to %s" % (localpath, remotepath))
def rename(self):

ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# 执行命令
stdin, stdout, stderr = ssh.exec_command('mv /home/root/tttttttttttt.py /home/root/ooooooooo.py')
# 获取命令结果
result = stdout.read()


ha = Haproxy()
ha.run()

1.1 报错显示

但运行时报错如下:

C:\Users\yunliu3\AppData\Local\Programs\Python\Python39\python.exe C:/PF/test_bak.py
Connected to 10.224.96.87 as root
Traceback (most recent call last):
File "C:\PF\test_bak.py", line 77, in <module>
ha.run()
File "C:\PF\test_bak.py", line 43, in run
self.upload()
File "C:\PF\test_bak.py", line 62, in upload
sftp = paramiko.SFTPClient.from_transport(self.__transport)
File "C:\Users\yunliu3\AppData\Local\Programs\Python\Python39\lib\site-packages\paramiko\sftp_client.py", line 169, in from_transport
chan.invoke_subsystem("sftp")
File "C:\Users\yunliu3\AppData\Local\Programs\Python\Python39\lib\site-packages\paramiko\channel.py", line 72, in _check
return func(self, *args, **kwds)
File "C:\Users\yunliu3\AppData\Local\Programs\Python\Python39\lib\site-packages\paramiko\channel.py", line 283, in invoke_subsystem
self._wait_for_event()
File "C:\Users\yunliu3\AppData\Local\Programs\Python\Python39\lib\site-packages\paramiko\channel.py", line 1226, in _wait_for_event
raise e
paramiko.ssh_exception.SSHException: Channel closed.

Process finished with exit code 1

1.2 问题原因与解决方案

原因:因为服务器sftp的服务未开启

解决:

# 1.打开/etc/ssh/sshd_config

[root@frdsa002 ~]# vim /etc/ssh/sshd_config

# 2.加入下面的代码(首先查询一下sftp-server的路径)

[root@frdsa002 ~]# find / -name sftp-server

/usr/libexec/openssh/sftp-server

# 重启的sftp-server

Subsystem sftp /usr/libexec/openssh/sftp-server

二、 python 中如果出现Error reading SSH protocol banner

在使用paramiko的过程中很快就发现了一个问题,由于是在代码里面去实现,在需要进行交互的时候才去连接上流sftp,所以经常由于网络问题出现Exception: Error reading SSH protocol banner,通过traceback发现实际上是socket.timeout()引发的异常

2.1 原因分析:

对于这个问题,异常描述里面已经很明确了,是socket.timeout,由于上流服务器是在国外,所以我首先能想到的是由于网络问题,导致连接不稳定的情况,超时出现的频率也反映了这一点,所以我找到了源代码中banner_time这个属性,实际在初始化的时候就已经定义了,如下:默认设置了15s (self.banner_timeout = 15)

python——相关error问题与解决方案_json

2.2 解决方案:

  清楚了问题原因,解决起来就轻而易举了,我是这样做的,初始化Transport之后直接去修改其banner_timeout属性,这里我重新设置超时为60s,经测试是有效的。

transport = paramiko.Transport(sock=('hostname', 22))
print(f'transport src banner_timeout: {transport.banner_timeout}')
transport.banner_timeout = 60
print(f'transport tag banner_timeout: {transport.banner_timeout}')

2.3 如果设置到60s还是解决问题

如果设置到60s还是解决问题,实际上很多时候这样并解决不了问题,因为这个相当于是网络不好的情况下或者说服务器不在内地的情况下可能出现的情况,在这个时候我看到网上另外一种解决方法是因为发现了端口给错了实际上不止是端口服务器IP账号密码错误都有可能导致这个问题,所以在报错后应该看看除开网络外的其它问题。有可能是磁盘空间,或者是的内存100%或者是网络的连接问题。 

三、python中的requests模块

# 安装requests并导入
pip install requests
import requests


# 下边对于https的链接请求时会带上”verify=False“参数,因为默认Python会进行证书校验如果不是信任的证书会报错,带上”verify=False“指示不进行证书校验。

# get请求

import requests

url='https://www.baidu.com'
r = requests.get(url,verify=False)
print(r.status_code)

# post请求

import requests

url='https://www.baidu.com'
data='username=ls&password=toor'
r = requests.post(url,data=data,verify=False)
print(r.status_code)

当前很多api是以json形式提交的,所以在使用post的时候我们可能想提交json数据。
提交json有两步:一是data要编码成json形式(python中的字典形式上和json一样但本质上不一样所以要编码),二是设置“Content-type”头的值为application/json(设置头部参见下面2.5,这里先用)

import json
import requests

# 一定要设置Content-Type值为application/json
headers={}
headers['Content-Type']='application/json'

url='https://www.baidu.com'
data={"username":"ls","password":"toor"}
# 一定要用json.dumps把data格式化成json
# r = requests.post(url,headers=headers,data=json.dumps(data),verify=False)
# 或者直接使用json参数代替data,此时requests会自动进行格式化和设置Content-Type头的工作
r = requests.post(url,json=data,verify=False)
print(r.status_code)

# 使用代理进行访问

import requests

url='http://docs.python-requests.org/en/master/'
proxies={
'http':'http://127.0.0.1:8080',
'https':'http://127.0.0.1:8080'
}
r = requests.get(url,proxies=proxies)
print(r.status_code)

# 自定义header访问

import requests

url='http://docs.python-requests.org/en/master/'
headers={
'User-Agent':'self-defind-user-agent',
'Cookie':'name=self-define-cookies-in header'
}
r = requests.get(url,headers=headers)
print(r.status_code)

# 自定义Cookie访问

import requests

url='http://docs.python-requests.org/en/master/'
cookies={'name1':'cookie1','name2':'cookies2'}
#cookies=dict(name1='cookie1',name2='cookies2')
r = requests.get(url,cookies=cookies)
print(r.status_code)

# 会话保执 经常很多请求只有在登录后才能进行,实现登录效果一般的做法是执行登录请求,然后从返回结果中提取sessionid放入自定义cookie中。

这种方法在requests中也行得通,但requests提供了更为简单的方法,直接使用request.Session类来请求即可,其保持登录的原理是保留之前请求中服务端通过set-cookie等设置的参数。

s = Session()
url='http://docs.python-requests.org/en/master/'
# 所有方法和直接使用requests时一样用即可
s.get(url)

四、博文参考