上次我们学到了redis的一些操作,下面来实际运用以下。

这里我们先来学习一下什么是cookie和session。

什么是Cookie

其实简单的说就是当用户通过http协议访问一个服务器的时候,这个服务器会将一些Name/Value键值对返回给客户端浏览器,并将这些数据加上一些限制条件。在条件符合时,这个用户下次再访问服务器的时候,数据又被完整的带给服务器。

因为http是一种无状态协议,用户首次访问web站点的时候,服务器对用户一无所知。而Cookie就像是服务器给每个来访问的用户贴的标签,而这些标签就是对来访问的客户端的独有的身份的一个标识,这里就如同每个人的身份证一样,带着你的个人信息。而当一个客户端第一次连接过来的时候,服务端就会给他打一个标签,这里就如同给你发了一个身份证,当你下次带着这个身份证来的时候,服务器就知道你是谁了。所以Cookie是存在客户端的,这里其实就是在你的浏览器中。

Cookie中包含了一个由名字=值(name=value)这样的信息构成的任意列表,通过Set-Cookie或Set-Cookie2HTTP响应(扩展)首部将其贴到客户端身上。

Cookie的分类

这里Cookie主要分为两种:

会话Cookie:不设置过期时间,保存在浏览器的内存中,关闭浏览器,Cookie便被销毁

普通Cookie:设置了过期时间,保存在硬盘上

关于Session

上面我们知道了Cookie可以让服务器端跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量,而Session的出现正是为了解决这个问题。

同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个ID这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有了一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NANE为JSESIONID的一个Cookie。所以Session其实是利用Cookie进行信息处理的。

cookie和session的共同之处在于:cookie和session都是用来跟踪浏览器用户身份的会话方式。

cookie和session的区别是:cookie数据保存在客户端,session数据保存在服务器端。

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session,当然也没有绝对的安全,只是相对cookie,session更加安全

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE

cookie和session各有优缺点,所以将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中。

实例:

先来验证用session登录的程序,分析:

首先先设计一个登录的程序,生成session写入redis,然后设计一个查询程序,传入session进行校验。

第一次登录:从my_user表中验证用户是否存在,用户存在且密码正确的场合生成session(规则:(当前时间戳+username))存入redis。

第二次登录查看:

#1、先验证用户是否登陆,username,session
#2、验证session是否正确,判断和redis里边是否一致
#3、如果一致返回查询结果
#4、如果不一致,提示session非法
#              session不存在,则提示用户未登录
#              session不一致,登陆失败
#在K-V中传入session

以下是常用工具,放在lib目录的tools文件中:

#常用工具
import pymysql,hashlib,time
import redis
from conf import setting
##def op_mysql(host,user,passwd,db,sql,port=3306,charset='utf8'):
def op_mysql(sql):conn=pymysql.connect(host=setting.MYSQL_HOST,user=setting.USER,passwd=setting.PASSWORD,port=setting.PORT,db=setting.DB,charset='utf8')cur=conn.cursor(cursor=pymysql.cursors.DictCursor)cur.execute(sql)sql_start=sql[:6].upper()if sql_start=='SELECT':#取sql的前6位,判断它是什么类型的语句。res=cur.fetchall()else:conn.commit()#res='ok'cur.close()conn.close()return res
def op_redis(k,v=None,expired=0,db=0):
#def op_redis(host,passwd,k,v=None,port=6379,db=1):#r=redis.Redis(host=host,password=passwd,port=port,db=db)r=redis.Redis(host=setting.REDIS_HOST,password=setting.REDIS_PASSWORD,port=setting.REDIS_PORT,db=db)if v:r.setex(k,v,expired)res='ok'else:#res=r.get(k).decode()#获取不到的时候返回none,none不能直接进行decode操作res=r.get(k)if res:res=res.decode()else:res='none'return resdef md5_password(st:str):#规定传参的类型必须是str类型#st = hashlib.md5()bytes_st=st.encode()m=hashlib.md5(bytes_st)return m.hexdigest()

#main.py

import flask,time,hashlib
from lib.tools import  op_mysql,op_redis,md5_password
import json
server=flask.Flask(__name__)
@server.route('/login',methods=['post'])
def login():username=flask.request.values.get('name','')password=flask.request.values.get('passwd','')sql="select * from my_user where username='%s';"%(username)if username and password:if op_mysql(sql):print(op_mysql(sql))if password==op_mysql(sql)[0]['passwd']:session=md5_password(str(time.time())+username)op_redis('session:%s'%username,session,expired=6000,db=2)response={'code':200,'msg':'登陆成功','session':session}else:response={'code':101,'msg':'密码不正确'}else:response={'code':102,'msg':'用户不存在'}else:response={'code':103,'msg':'用户名或密码不能为空'}return json.dumps(response,ensure_ascii=False)

启动服务后,在postman中调用127.0.0.1:8088/login?name=pei&passwd=123456,执行一个正确的用户登录,:

{"msg": "登陆成功", "code": 200, "session": "28b14dea0c7a668650fbb19f6364f482"}

查看到redis里边已经插入了一个session数据:

下面进行第二部,传入用户名、session,如果验证正确则查询中表中的数据:

@server.route('/getall',methods=['post','get'])
def getall():username=flask.request.values.get('name')session=flask.request.values.get('session')k='session:%s'%(username)redis_session=op_redis(k,db=2)if username and session:if redis_session:if redis_session==session:sql="select red,blue from seq "response = op_mysql(sql)else:response={'code':101,'msg':'session非法'}else:response={'code':102,'msg':'未登录'}else:response={'code':103,'msg':'必填参数为空'}return  json.dumps(response,ensure_ascii=False)

以上是在k-v参数中传入session值,如需需要在cookie中传入session,代码如下:

就是把session=flask.request.values.get('session')改为session=flask.request.cookies.get('session')则取值就是在cookie中进行取值了。

@server.route('/getall_cookie',methods=['post','get'])
def getall_cookie():username=flask.request.values.get('name')session=flask.request.cookies.get('session')k='session:%s'%(username)redis_session=op_redis(k,db=2)if username and session:if redis_session:if redis_session==session:sql="select red,blue from seq "response = op_mysql(sql)else:response={'code':101,'msg':'session非法'}else:response={'code':102,'msg':'未登录'}else:response={'code':103,'msg':'必填参数为空'}return  json.dumps(response,ensure_ascii=False)

在我们登录购物网站的话,如果勾选记住密码,一般情况下就是在客户端浏览器上添加了cookie,这样用户打开网站后后台会自动校验cookie信息,不用每次都传一次,如下是设置cookie的代码:

要在页面添加cookie需要先response=flask.make_response(),然后response.set_cookie('session',session)set上要添加的cookie信息

@server.route('/login_setcookie',methods=['post'])
def login_setcookie():username=flask.request.values.get('name','')password=flask.request.values.get('passwd','')sql="select * from my_user where username='%s';"%(username)if username and password:if op_mysql(sql):print(op_mysql(sql))if password==op_mysql(sql)[0]['passwd']:session=md5_password(str(time.time())+username)op_redis('session:%s'%username,session,expired=6000,db=2)response=flask.make_response()response.set_cookie('session',session)msg={'code':200,'msg':'登陆成功','session':session}else:msg={'code':101,'msg':'密码不正确'}else:msg={'code':102,'msg':'用户不存在'}else:msg={'code':103,'msg':'必填参数为空'}return response

添加cookie后,我们在调用getall_cookie时只传入name,就能直接获取到seq表中的数据了。

补充:

mysql注入原理

上述代码中存在的sql语句如下:

sql="select * from my_user where username='%s';"%(username)

在获取username时,由于存在‘’,所以存在漏洞;

我们知道‘1’=‘1’是恒为真的,我们可以通过‘’,来模拟制造出这种恒等式,使sql在执行时跳过一些校验,从而进阶访问系统。

当我们输入name=“' or '1'='1”

我们将上述name的值带入sql如下:

sql="select * from my_user where username='' or '1'='1';"

我们在sqlyog中my_user表中执行这个语句,查询出了所有的用户信息,

在一些查询操作中,很容易产生漏洞,造成信息的泄露。

还有一种注入方式是:username="' show tabales ; --"

sql="select * from my_user where username='' show tabales ; --';"

sql语句中--表示注释掉后边的语句,这样就查询出了所有的表,可以对数据库随意进行操作。

为了防止sql的注入,在编写sql的时候我们尽量避免使用‘’,写成如下方式:

sql="select * from my_user where username=%s;",username

这样在传参的时候,可以直接传到输入的参数进行取值,例如:

def op_mysql_new(sql,*data):#第一个是位置参数,第二个是可变参数cur.execute(sql,data)#data是一个元祖,*data获取出所有传过去的参数print(cur.fetchall())
sql="select * from users where name=%s and passwd=%s;"
name='pei'
passwd='123456'
op_mysql_new(sql,name,passwd)

###################################################33

传参:
def test(a,b):print(a,b)li=[1,2]
test(*li)#一个星代表把list里边的数据穿进去
d={'a':'123','b':'456'}
test(**d)#两个星代表从字典里边的数据传进去

python自动化测试学习笔记-6urllib模块&request模块

python3的urllib 模块提供了获取页面的功能。

urllib.request.urlopen(urldata=None, [timeout, ]*cafile=Nonecapath=Nonecadefault=Falsecontext=None)

-         url:  需要打开的网址

-         data:Post提交的数据

-         timeout:设置网站的访问超时时间

直接用urllib.request模块的urlopen()获取页面,page的数据格式为bytes类型,需要decode()解码,转换成str类型。

import urllib.request# import json
# import requests
url="http://api.nnzhp.cn/api/user/stu_info?stu_name=xiaohei"
req=urllib.request.urlopen(url)
res=req.read().decode()
print(res)

执行:

{
        "error_code": 2,
        "msg": "无结果"
}

urllib 中实现post数据请求

urlopen()的data参数默认为None,当data参数不为空的时候,urlopen()提交方式为Post。

url1='http://api.nnzhp.cn/api/user/login '
data={'username':'niuhanyang','passwd':'aA123456'
}
#urlencode()主要作用就是将url附上要提交的数据。经过urlencode()转换后的data数据为?username=niuhanyang&passwd=aA123456,
## Post的数据必须是bytes或者iterable of bytes,不能是str,因此需要进行encode()编码
data=urllib.parse.urlencode(data).encode('utf-8')
#最终提交的url是http://api.nnzhp.cn/api/user/login?username=niuhanyang?passwd=aA123456
req=urllib.request.Request(url1,data=data)
page=urllib.request.urlopen(req).read()
print(page.decode())

执行查看结果:

{
        "error_code": 0,
        "login_info": {
                "login_time": "20180129202722",
                "sign": "7e4c46e5790ca7d5165eb32d0a895ab1",
                "userId": 1
        }
}

我们看到使用urllib会比较麻烦,需要转码,赋值等操作,request模块可以更加简便的完成请求操作,如下:

1、首先需要安装Request模块

pip install requests

2、导入request模块

import requests

各种接口操作如下:

import requests
import json
#发送无参数的get请求
url='http://www.baidu.com'
req=requests.get(url)
print(req.text)#返回的字符串类型#发送有参数的request请求
url1='http://api.nnzhp.cn/api/user/stu_info?stu_name=feifei'
req1=requests.get(url1)
print(req1.json())#返回的字典列表#发送post请求
url2='http://api.nnzhp.cn/api/user/login '
data={'username':'niuhanyang','passwd':'aA123456'
}
req=requests.post(url2,data)#发送的post氢气,第一个参数是url,第二个参数是请求的数据
print(req.json())#发送入参是json类型的post请求
url3='http://api.nnzhp.cn/api/user/add_stu'
data={'name':'feifei','phone':'13121111112','grade':'1000'
}req=requests.post(url3,json=data)
print(req.json())#发送带有cookie的post请求
#添加cookie
url4='http://api.nnzhp.cn/api/user/gold_add'
data={'stu_id':230,'gold':88888
}
cookies={'feifei':'a2b454c3830e20e7d9916f6b52d6a3a7'}
req=requests.post(url4,data,cookies=cookies)
print(req.json())#发送带有Referer请求的post请求
#
url5='http://api.nnzhp.cn/api/user/all_stu'
data={'Referer':'http://api.nnzhp.cn/'
}
req=requests.get(url5,headers=data)
print(req.json())#下载文件请求url6='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1517138333609&di=327abc49fc6d63fed19124cdf826d130&imgtype=0&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201510%2F17%2F20151017223821_ZSWBc.jpeg'
r=requests.get(url6)#下载直接请求url然后进行保存
#print(r.status_code)#请求状态码是二进制
res=r.content#获取二进制格式
fw=open('feifei.jpg','wb')
fw.write(res)#保存文件
fw.close()#上传文件url7='http://api.nnzhp.cn/api/file/file_upload'
f=open('E:\\besttest\\python\\besttest_code\\练习\\day7笔记\\api\\feifei.jpg','rb')
r=requests.post(url7,files={'file':f})
print(r.json())
#
#下载页面
url='http://www.runoob.com/python/python-intro.html'
r=requests.get(url)
f=open('python.html','wb')
f.write(r.content)
f.close()

python自动化测试学习笔记-6excel操作xlwt、xlrd、xlutils模块

python中通过xlwt、xlrd和xlutils操作xls

  • xlwt模块用于在内存中生成一个xls/xlsx对象,增加表格数据,并把内存中的xls对象保存为本地磁盘xls文件;
  • xlrd模块用于把本地xls文件加载到内存中,可以读取xls文件的表格数据,查询xls文件的相关信息;
  • xlwt可以生成xls文件,xlrd可以读取已经存在的xls文件,但是如果要修改本地已经存在的xls文件,就需要用到xlutils模块。
  • xlutils模块是xlrd和xlwt之间的桥梁,可以使用xlutils模块中的copy模块,拷贝一份通过xlrd读取到内存中的xls对象,就可以在拷贝对象上像xlwt中那样修改xls表格的内容,并保存到本地

要使用这些模块首先要安装导入:

pip install xlrd

pip install xlwt

pip install xluntils

安装好后进行导入

import xlrd
import xlwt
from xlutils.copy import copy
#创建一个excel
book=xlwt.Workbook()
#添加一个sheet
sheet=book.add_sheet('sheet1')
#向sheet中添加数据,行、列、value值
sheet.write(0,0,'id')
sheet.write(0,1,'name')
sheet.write(0,2,'age')
sheet.write(0,3,'sex')
#保存xls,微软的office不能以xlsx为结尾,wps随意
book.save('peitest.xls')

执行后生成了一个excel文件,查看内容

但是像这样一个单元格一个单元格的插入又很浪费时间,我们可以用循环来实现,如下:

##############################
#利用循环写数据
#创建一个excel
book=xlwt.Workbook()
#添加一个sheet
sheet=book.add_sheet('sheet2')
row=0
col=0
list=[['id','name','age','sex'],['01','wang','13','女'],['02','li','23','女'],['03','hang','34','男'],['04','wu','16','女'],['05','ma','22','女']
]
#循环行
for r in range(6):#循环列for c in range(4):#根据行和列找到要赋值的valuesheet.write(r,c,list[r][c])c+=1r+=1
#保存excel
book.save('peitest.xls')

执行查看结果:

上述方法是已知数据的行和列来循环的,如果行和列太多的时候就不方便了,我们可以通过循环list来添加数据,如下:

#创建一个excel
book=xlwt.Workbook()
#添加一个sheet
sheet=book.add_sheet('sheet3')
list=[['id','name','age','sex'],['01','wang','13','女'],['02','li','23','女'],['03','hang','34','男'],['04','wu','16','女'],['05','ma','22','女']
]r=0
for stu in list:c=0for s in stu:sheet.write(r,c,s)c+=1r+=1
book.save('peitest.xls')

执行查看结果:

读取excel的数据是通过xlrd模块来实现的,如下:

###############################################################################
#读取excel数据
book=xlrd.open_workbook('peitest.xls')
#获取sheet,通过index
sheet=book.sheet_by_index(0)
#获取sheet通过sheet名称
#sheet=book.sheet_by_name('sheet3')
value=sheet.cell(0,0).value
value1=sheet.cell(0,1).value
value2=sheet.cell(0,2).value
value3=sheet.cell(0,3).valueprint(value)
print(value1)
print(value2)
print(value3)

执行查看结果:

id
name
age
sex

同样的,如果我们要读取出excel所有的数据,也可以用循环来实现:

#####################################33
#循环来实现读取excel数据
#打开excel
book=xlrd.open_workbook('peitest.xls')
#获取sheet
sheet=book.sheet_by_name('sheet3')
#获取sheet中的行数
row=sheet.nrows
#获取sheet中的列数
col=sheet.ncols
#获取每一行的数据
for i in sheet.get_rows():print(i)
#获取某一行的数据,通过循环获取出所有数据
for r in range(row):print(sheet.row_values(r))
#获取某一列的数据,通过循环获取出所有数据
for c in range(col):print(sheet.col_values(c))

执行查看结果:

[text:'id', text:'name', text:'age', text:'sex']
[text:'01', text:'wang', text:'13', text:'女']
[text:'02', text:'li', text:'23', text:'女']
[text:'03', text:'hang', text:'34', text:'男']
[text:'04', text:'wu', text:'16', text:'女']
[text:'05', text:'ma', text:'22', text:'女']
['id', 'name', 'age', 'sex']
['01', 'wang', '13', '女']
['02', 'li', '23', '女']
['03', 'hang', '34', '男']
['04', 'wu', '16', '女']
['05', 'ma', '22', '女']
['id', '01', '02', '03', '04', '05']
['name', 'wang', 'li', 'hang', 'wu', 'ma']
['age', '13', '23', '34', '16', '22']
['sex', '女', '女', '男', '女', '女']

我们看到上面第一种方法,每一个数据都带一个text,不方便进行后续操作,所以一般用第二种方式来实现。

修改文件

#######################################
import xlrd
import xlwt
from xlutils.copy import copy
#修改excel文件
#打开文件
book=xlrd.open_workbook('peitest.xls')
#复制一份文件用于修改
book2=copy(book)
#获取要修改的sheet
sheet=book2.get_sheet(0)
#修改指定的行和列
sheet.write(0,0,'序号')
#保存为新的excel
book2.save('peitest1.xls')

执行查看结果:

好了  这次就学习到这了哦!

还想学习的话,记得收藏及关注哦.

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

① 2000多本软件测试电子书(主流和经典的书籍应该都有了)

② 软件测试/自动化测试标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python编程语言、API接口自动化测试、web自动化测试、App自动化测试(适合小白学习)
————————————————

⑤ Python学习路线图(告别不入流的学习)

在我的QQ技术交流群里(技术交流和资源共享,广告进来腿给你打断)

可以自助拿走,群号768747503备注(csdn999768747503备注(csdn999))群里的免费资料都是笔者十多年测试生涯的精华。还有同行大神一起交流技术哦。

————————————————
版权声明:本文为CSDN博主「自动化测试君」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Yanan990830/article/details/120874523

python自动化测试学习笔记合集三相关推荐

  1. python自动化测试学习笔记合集

    python自动化测试学习笔记-1 一.什么是自动化 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程.直白的就是为了节省人力.时间或硬件资源,提高测试效率,便引入了通过软件或程序自动化执行 ...

  2. python自动化测试学习笔记合集二

    python自动化测试学习笔记-4内置函数,处理json 函数.全局变量 写代码时注意的几点事项: 1.一般写代码的时候尽量少用或不用全局变量,首先全局变量不安全,大家协作的情况下,代码公用容易被篡改 ...

  3. Python学习笔记合集(总结)

    Python学习笔记合集(总结) 第一天主要讲了Python基本语句(上) 注释 输出 标识符 多行语句 第二天主要讲了Python基本语句(下) 行与缩进 关键字 数据类型 第三天主要讲了impor ...

  4. (小甲鱼python)集合笔记合集一 集合(上)总结 集合的简单用法 集合的各种方法合集:子、交、并、补、差、对称差集、超集

    一.基础复习 集合与字典区别 集合中所有元素都是独一无二的,并且也是无序的. 集合具有唯一性.无序性.有限性 >>> type({}) #字典 <class 'dict'> ...

  5. HTML基础学习笔记合集

    HTML学习笔记 基础认知 基本概念 常用标签 排版标签 标题标签 段落标签 换行标签(单标签) 水平线标签(单标签) 文本格式化标签 图片标签(单标签) 音频标签(双标签) 视频标签(双标签) 链接 ...

  6. 江科大51单片机入门学习笔记合集

    文章目录 软件下载 介绍 STC89C52RC 命名规则 芯片介绍 开发板介绍 逻辑运算 C语言语法 函数在C语言基础上做的拓展 重入函数 中断函数 外部函数 sfr sbit 51单片机最小系统组成 ...

  7. 【用pandas_alive几行代码绘制竞赛动图】全网首发pandas_alive数据可视化中文学习笔记合集,学不会来打我(配置好的venv虚拟环境+拿来即用测试代码+测试数据集+参数api解析)

    目录 专栏说明 一.效果图展示 1.1 水平条形图 1.2 竖直条形图 2. 折线图 3. 散点图 4.饼状图 5. 气泡图 6.1 地理空间点图 6.2 多边形地理空间图 7.多个图表 8.城市人口 ...

  8. 【动画消消乐】纯CSS加载/过渡动画学习笔记合集(1-50)

    Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 自我介绍一下 ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入 ...

  9. python基本使用-python基本用法笔记合集

    PYTHONPATH PYTHONPATH是python moudle的搜索路径.即import xxx会从$PYTHONPATH寻找xxx. 中文编码问题 coding=utf-8 查看导入的包的路 ...

最新文章

  1. cmd运行Java中文乱码,无法加载主类Error: Could not find or load main class
  2. PullToRefreshScrollView下拉刷新开源组件分析
  3. 如何利用webmin在Linux主机中添加网站
  4. ADO.NET Entity Framework Extensions 简单应用
  5. webxml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)
  6. 使用bootstrap的相关配置
  7. Visual Studio 剪切板新特性
  8. rz/sz命令参数解释
  9. 【Kafka】kafka Removed ✘✘✘ expired offsets in ✘✘✘ milliseconds.
  10. 企业做网络推广关键词设置的几点个人看法
  11. springboot 整合 shiro (Web Applications)避坑一 ,请看shiro官网
  12. [读书笔记]《Windows游戏编程之从零开始》(零)
  13. 计算机故障排除pdf,计算机常见故障排除方法【藏】.pdf
  14. 使用ceres库将经纬度坐标GCJ02到WGS84精确转换
  15. 测试Java Stream流 parralle与 sequential的效率
  16. 用计算机视觉描述机器人,一文读懂计算机视觉和机器人视觉
  17. 无线射频专题《射频基础,射频特征,波长,频率,振幅,相位》
  18. 网页三栏布局常用方法
  19. Linux字体相关文件存放的目录位置
  20. python constrain_python约束 – 约束金额

热门文章

  1. 终于好了,自动生成支付宝自定义收款码
  2. JITStack超融合一体机_高性能分布式存储_面向企业私有云
  3. 《程序原本-追溯程序原本之书》读书笔记
  4. 由“微博”的发展史预测“轻博客”的命途
  5. 基于计算机视觉的Android手机摄像头实现长度测量
  6. Qt操作Excel表格
  7. 你管这叫操作系统源码(二)
  8. 【思路】2021美国大学生数学建模竞赛(美赛)思路+参考文献获取/【2021美国大学生数学建模】
  9. 利用MQL进行MQL解析
  10. 解决伪原创视频 改变视频md5原创