python3+tkinter实践历程(三)——基于requests与tkinter的模拟web登录工具

python3+tkinter实践历程(三)——基于requests与tkinter的模拟web登录工具


系列文章目录

python3+tkinter实践历程(一)——基于requests与tkinter的API工具
python3+tkinter实践历程(二)——基于tkinter的日志检索工具
python3+tkinter实践历程(三)——基于requests与tkinter的模拟web登录工具
python3+tkinter实践历程(四)——模仿CRT完成基于socket通信与tkinter的TCP串口客户端

分享背景

①分享意图在于帮助新入门的朋友,提供思路,里面详细的注释多多少少能解决一些问题。欢迎大佬指点跟交流。
②2021年8月,开始陆续有需求制作一些工具,因为python语言跟tkinter工具相对简单,所以就基于这些做了好几个不同用处的工具。
③分享从完成的第一个工具开始分享,分享到最新完成的工具,对于tkinter的理解也从一开始的摸索入门,到后来逐渐熟练,完成速度也越来越快,所用到的tk的功能点也越来越多。
④这是直至发布前做的倒数第二个工具了,从“python3+tkinter实践历程(二)——基于tkinter的日志检索工具”开始到这个工具,中间还有3个工具,但都过于偏产品功能的调度,所以难以展示。

制作背景

① 产品有允许登录的最大客户端数,测试人员需要打开n个浏览器来登录设备,数量过于庞大,所以使用接口登录的方式来代替浏览器登录。
② 并非所有测试人员都会使用jmeter等工具来进行接口登录,又或者对http没有了解,无法掌握设备的登录流程。
③ 此工具就把设备的登录流程封装好,使用者只需填写IP账号密码、登录个数等信息即可达到同样的登录效果。

最终功能

① 使用者无需接触http,无需接触接口,即可完成对设备的n个登录数量的测试

代码详解

代码中关于产品登录流程及加密方式不展示,不同的设备将登录模块修改成相应的登录流程即可。

import tkinter as tk
import threading
import time
import requests

# HTTP类
class Http(object):
    def __init__(self, url, username, password):
    	# 必要信息,用于连接设备
        self.url = 'http://' + url
        self.username = username
        self.password = password
		# 登录所需的参数,根据登录方式的不同而变化
        self.sessionId = ""
        self.nonce = ""
        self.token = ""
        self.sessionKey = ""
        # 用于记录是否登录成功
        self.is_logined = False

    def send_requests(self, api, reqhead=None, reqbody="", port="80", returnAll=False):
        """发送请求"""
        try:
        	# 发送某个请求
            resp = requests.post(api, headers=reqhead, data=reqbody, timeout=60)
            if returnAll:
                return resp
            # 返回报文
            return resp.text
        except Exception as e:
            print('发送接口异常:%s' % e)

    def check_is_login(self):
        """查询是否登录状态"""
        # 设备本身某个能检查是否已登录的接口,成功则是已登录状态,失败则是未登录状态
        try:
				if a:
					return True
				else:
					return False
        except Exception as e:
            print('查询是否登录状态异常:%s' % e)
            return False

    def make_login(self):
        """做一次登录操作,并记录相关数据"""
        # 此函数封装登录操作,
        try:
       			# 若登录操作完成,则self.is_logined = True,原默认为False
				
                self.is_logined = True
                return True
            else:
                return res
        except Exception as e:
            print('登录异常:%s' % e)

    def get_req_result(self):
        """
        解析相应报文数据
        try:
        	xx
        except Exception as e:
            print('解析相应xml数据异常:%s' % e)
            return ''

    def make_req_body(self):
        """
        拼接Request Body,根据具体接口的要求带上相应的参数:
        """
        try:
            if encode:
                return req_body.encode()
            return req_body
        except Exception as e:
            print('拼接Request Body异常:%s' % e)

    def get_psd_hash(self):
        """
        密码加密
        """
        try:
                return psd_hash
        except Exception as e:
            print('密码加密异常:%s' % e)

    def make_res_head(self):
        """拼接Request headers"""
        try:
            return req_head
        except Exception as e:
            print('拼接res_head异常:%s' % e)


class Application(tk.Frame):
# 继承于tkinter的Frame类,可使用Frame的布局方式
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        self.create_widgets()			# 构造界面
        self.is_running = False			# 记录是否已正在运行
        self.re_dict = dict()			# 记录创建的HTTP类的对象
        self.LOG_LINE_NUM = 0			# 记录日志打印框的数量

    def create_widgets(self):
        """创建界面"""
        # 一行先定义一个Frame,该行的其他控件就已该Frame为主。类似html开发中的一行一个div
        # 第一行(用于IP、账号、密码)
        row1 = tk.Frame(self)
        row1.grid(row=0, column=0, sticky='w')

        # 设备IP端口	
        dev_url = tk.Label(row1, text="设备IP及端口(xx:xx)")
        dev_url.grid(row=0, column=0)
        dev_url = tk.StringVar()
        dev_url.set("10.100.10.183:80")         # set的作用的预置的文字(在标签内可变的文本)
        self.dev_url = tk.Entry(row1, textvariable=dev_url, width=20)
        self.dev_url.grid(row=0, column=1)

        # 账号
        user_name = tk.Label(row1, text="账号")
        user_name.grid(row=0, column=2)
        user_name = tk.StringVar()
        user_name.set("xxx")		# 预设账号xxx
        self.user_name = tk.Entry(row1, textvariable=user_name, width=20)
        self.user_name.grid(row=0, column=3)

        # 密码
        password = tk.Label(row1, text="密码")
        password.grid(row=0, column=4)
        password = tk.StringVar()
        password.set("123456")			# 预设密码123456
        self.password = tk.Entry(row1, textvariable=password, width=20)
        self.password.grid(row=0, column=5)
		
		# 第二行(用于登录数量框、开始按钮、成功失败数量的显示)
        row2 = tk.Frame(self)
        row2.grid(row=1, column=0, sticky='w')
		
		# 登录数量框,提供给使用者输入
        tk.Label(row2, text="登录数量").grid(row=0, column=0)
        login_num = tk.StringVar()
        login_num.set("0")
        self.login_num = tk.Entry(row2, textvariable=login_num, width=10)
        self.login_num.grid(row=0, column=1)
		
		# 开始登录按钮,绑定登录函数,点击即触发
        tk.Button(row2, text="开始登录", command=self.start_to_login).grid(row=0, column=2, padx=10, pady=10)
        
        # 新建一个Label,用于成功数量的实时显示
        self.success_text = tk.StringVar()
        self.success_text.set('成功:')
        tk.Label(row2, textvariable=self.success_text, width=10, anchor='w').grid(row=0, column=3, padx=(20, 10))
        
        # 新建一个Label,用于成功数量的实时显示
        self.fail_text = tk.StringVar()
        self.fail_text.set('失败:')
        tk.Label(row2, textvariable=self.fail_text).grid(row=0, column=4)
		
		# 第三行(用于日志打印框、注意事项)
        row3 = tk.Frame(self)
        row3.grid(row=2, column=0, sticky='w')
        
		# 日志打印框,用于打印程序运行的相关信息
        self.log_data = tk.Text(row3, width=60, height=20)
        # 滚动条,与日志打印框绑定
        respone_slide_bar = tk.Scrollbar(row3, command=self.log_data.yview, orient="vertical")
        respone_slide_bar.grid(row=0, column=1, sticky='ns')
        self.log_data.grid(row=0, column=0)
        self.log_data.config(yscrollcommand=respone_slide_bar.set)
        
		# 注意事项的Label
        note = """注意事项:\n1、测试前请先重启设备,使设备登录数量清0\n2、经过多台设备测试,最大登录数量一般为xxx\n3、只支持xxxxx版本及以上的设备"""
        tk.Label(row3, text=note, anchor='w', justify='left', width=50, font=('', 11, '')).grid(row=0, column=2, padx=10, sticky='nw')

    def login(self):
    	# 开始登录按钮绑定的函数--开始执行登录操作
        url = self.dev_url.get()			# 获取IP地址
        username = self.user_name.get()		# 获取账号
        password = self.password.get()		# 获取密码
        times = int(self.login_num.get())		# 获取登录个数
        if not url or not username or not password or not times:
            self.write_log_to_Text('请先填写必要的信息')
            return
        if self.is_running:			# 当登录开始时,self.is_running为True,此时再次点击开始按钮会返回
            self.write_log_to_Text('测试已开始,无需重复开始')		# self.write_log_to_Text函数用于打印日志
            return
        self.write_log_to_Text('开始登录')
        self.is_running = True			# 当登录开始时,self.is_running为True
        self.success = 0				# 记录成功个数
        self.fail = 0					# 记录失败个数
        for i in range(1, times + 1):			# 进入循环,从第1个到第times个
            print('第%d个登录开始' % i)
            s = str(i)			# s为当前第几个设备
            self.re_dict[s] = Http(url, username, password)		# self.re_dict字典中记录创建的HTTP对象
          	result = self.re_dict[s].make_login()				# 该对象执行make_login(),即登录操作
            if result:			#	如果返回为True,则登录操作完成,默认登录成功,self.success计数器+1,否则self.fail + 1
                self.success = self.success + 1
                print('第%s个登录成功,token为:%s,sessionId为:%s' % (s, self.re_dict[s].token, self.re_dict[s].sessionId))
                self.success_text.set('成功:%d个' % self.success)				# 利用self.success_text容器实时打印成功个数
            else:
                self.fail = self.fail + 1
                print('第%s个登录失败' % s)
                self.fail_text.set('失败:%d个' % self.fail)						# 利用self.fail_text容器实时打印成功个数
        self.write_log_to_Text('设备登录完成,登录成功:%d,登录失败:%d,等待30秒后检查是否仍在线' % (self.success, self.fail))
        self.write_log_to_Text('等待30秒后检查是否仍在线')
        time.sleep(30)	
        self.online = 0			# 记录设备在线个数
        for s in self.re_dict:
            result = self.re_dict[s].check_is_login()			# 通过遍历self.re_dict中记录的HTTP对象,调用check_is_login()方法,确定每一个对象是否能完成该动作
            if result:
                self.online = self.online + 1
                print('第%s个仍在线' % s)
            if not result:
                print('第%s个不在线' % s)

        self.write_log_to_Text('检查结果:%d个登录成功,其中%d个仍在线' % (self.success, self.online))
        self.is_running = False

    def thread_it(self, func, *args):
        """将函数打包进线程"""
        # 当程序在进行登录操作时,工具主界面不会卡死
        # 创建
        t = threading.Thread(target=func, args=args)
        # 守护 !!!
        t.setDaemon(True)
        # 启动
        t.start()

    def start_to_login(self, *args):
    	# 将登录函数self.login放进线程运行
        self.thread_it(self.login)

    def write_log_to_Text(self, logmsg):
        """日志动态打印"""
        self.LOG_LINE_NUM = int(self.log_data.index('end').split('.')[0]) - 1		# 记录日志的总行数
        if self.LOG_LINE_NUM > 500:					# 当日志行数大于500,将行数从最上方开始清除到剩余500行
            del_target = float(self.LOG_LINE_NUM - 500 - 1)
            self.log_data.delete(1.0, del_target)
        logmsg_in = "%s\n" % logmsg					# 为日志添加换行符
        self.log_data.insert('end', logmsg_in)		# 打印日志
        self.log_data.see('end')					# 滚动条自动跳转跟随日志的最新打印


root = tk.Tk()					# 创建Tk对象
app = Application(master=root)	# 创建Application类的对象app,主界面为root
root.title("模拟web登录工具")	# 设置app标题
root.resizable(False, False)	# 禁止调整窗口大小

sw = root.winfo_screenwidth()   # 得到屏幕宽度
sh = root.winfo_screenheight()  # 得到屏幕高度
# 窗口宽高为800x400
ww = 800
wh = 400
x = (sw-ww) / 2
y = (sh-wh) / 2
root.geometry("%dx%d+%d+%d" % (ww, wh, x, y))       # 设置窗口宽高为800x400,且自适应居中


root.deiconify()        # 显示窗口
app.mainloop()          # 进入消息循环

工具截图展示

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值