前言:
第一篇,分析青果教务管理系统登陆模块,理清思路
第二篇,使用常规的python常用库 requests来实现模拟登陆
第三篇,使用scrapy来实现模拟登陆
目的在于了解模拟登陆网站的要点和方法,了解http请求的一些知识。
青果教务管理系统是许多大学正在使用的教务管理系统,现在市面上我知道使用比较多的两个教务系统,一个是青果教务管理系统(大概几百所,我大概查了查),一个是正方教务管理系统(官网上号称一千多所)。我们来看一下,这两个教务系统的登陆界面(这里找了两个大学的教务登陆界面):
说实话啊,都不好看。曾经我也用java模拟登陆过青果教务,但是没有成功。这次我又重新尝试了一下,成功了。
虽然我没有模拟登陆过正方教务,但是两个大同小异。 下面我会介绍其中的一些细节,如果对python不太熟悉的,也可以用java实现,原理都是一样的。
想必能看到这一篇文章的也就是大学生了。所以我就假设大家有青果教务管理系统的账号密码。(没有也行,但是你就不能验证你是否成功了。)
需要用到的工具 goole浏览器,Fiddler(没有也行,抓包用的)。
网址:http://jwglxt.aynu.edu.cn/ 这个是我学校的教务管理的地址
在访问之前,打开goole 浏览器的控制台(F12),访问
看见登陆模块:
其中控制台:
我们会发现,首先请求了 http://jwglxt.aynu.edu.cn/
然后又请求了登陆模块的这个链接:http://jwglxt.aynu.edu.cn/_data/home_login.aspx
(我们想看关注的请求的时候,可以看下type类型,document文档一般都是我们需要看的。还可以看下Name 的名称,你感觉挺相识的就可以看看。)
我们来看下home_login.aspx的链接,发现对应就是登陆的(这里只是乱码),其中下面有 Headers,preview,response,cookies。都可以点开看看。我们说到哪里看哪里。
请求前,先清空一下控制台
我们先使用错误的账号密码,登陆一次。
肯定提示登陆失败,我们来观察控制台:
我们主要关注 login请求发送的地址,发送的参数等
首先登陆的网址:http://jwglxt.aynu.edu.cn/_data/home_login.aspx
请求的参数(好多):
__VIEWSTATE: dDwtNjMyNzQ3NTkxO3Q8O2w8aTwwPjtpPDE+O2k8Mj47PjtsPHQ8cDxsPFRleHQ7PjtsPOWuiemYs+W4iOiMg+WtpumZojs+Pjs7Pjt0PHA8bDxUZXh0Oz47bDxcPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiXD4KZnVuY3Rpb24gQ2hrVmFsdWUoKXsKIHZhciB2VT0kKCdVSUQnKS5pbm5lckhUTUxcOwogdlU9dlUuc3Vic3RyaW5nKDAsMSkrdlUuc3Vic3RyaW5nKDIsMylcOwogdmFyIHZjRmxhZyA9ICJZRVMiXDsgaWYgKCQoJ3R4dF9hc21jZGVmc2Rkc2QnKS52YWx1ZT09JycpewogYWxlcnQoJ+mhu+W9leWFpScrdlUrJ++8gScpXDskKCd0eHRfYXNtY2RlZnNkZHNkJykuZm9jdXMoKVw7cmV0dXJuIGZhbHNlXDsKfQogZWxzZSBpZiAoJCgndHh0X3Bld2Vyd2Vkc2Rmc2RmZicpLnZhbHVlPT0nJyl7CiBhbGVydCgn6aG75b2V5YWl5a+G56CB77yBJylcOyQoJ3R4dF9wZXdlcndlZHNkZnNkZmYnKS5mb2N1cygpXDtyZXR1cm4gZmFsc2VcOwp9CiBlbHNlIGlmICgkKCd0eHRfc2RlcnRmZ3NhZHNjeGNhZHNhZHMnKS52YWx1ZT09JycgJiYgdmNGbGFnID09ICJZRVMiKXsKIGFsZXJ0KCfpobvlvZXlhaXpqozor4HnoIHvvIEnKVw7JCgndHh0X3NkZXJ0ZmdzYWRzY3hjYWRzYWRzJykuZm9jdXMoKVw7cmV0dXJuIGZhbHNlXDsKfQogZWxzZSB7ICQoJ2RpdkxvZ05vdGUnKS5pbm5lckhUTUw9J1w8Zm9udCBjb2xvcj0icmVkIlw+5q2j5Zyo6YCa6L+H6Lqr5Lu96aqM6K+BLi4u6K+356iN5YCZIVw8L2ZvbnRcPidcOwogICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgidHh0X3Bld2Vyd2Vkc2Rmc2RmZiIpLnZhbHVlID0gJydcOwogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoInR4dF9zZGVydGZnc2Fkc2N4Y2Fkc2FkcyIpLnZhbHVlID0gJydcOyAKIHJldHVybiB0cnVlXDt9CiB9CmZ1bmN0aW9uIFNlbFR5cGUob2JqKXsKIHZhciBzPW9iai5vcHRpb25zW29iai5zZWxlY3RlZEluZGV4XS5nZXRBdHRyaWJ1dGUoJ3VzcklEJylcOwogJCgnVUlEJykuaW5uZXJIVE1MPXNcOwogc2VsVHllTmFtZSgpXDsKIGlmKG9iai52YWx1ZT09IlNUVSIpIHsKICAgZG9jdW1lbnQuYWxsLmJ0bkdldFN0dVB3ZC5zdHlsZS5kaXNwbGF5PScnXDsKICAgZG9jdW1lbnQuYWxsLmJ0blJlc2V0LnN0eWxlLmRpc3BsYXk9J25vbmUnXDsKICB9CiBlbHNlIHsKICAgIGRvY3VtZW50LmFsbC5idG5SZXNldC5zdHlsZS5kaXNwbGF5PScnXDsKICAgIGRvY3VtZW50LmFsbC5idG5HZXRTdHVQd2Quc3R5bGUuZGlzcGxheT0nbm9uZSdcOwogIH19CmZ1bmN0aW9uIG9wZW5XaW5Mb2codGhlVVJMLHcsaCl7CnZhciBUZm9ybSxyZXRTdHJcOwpldmFsKCJUZm9ybT0nd2lkdGg9Iit3KyIsaGVpZ2h0PSIraCsiLHNjcm9sbGJhcnM9bm8scmVzaXphYmxlPW5vJyIpXDsKcG9wPXdpbmRvdy5vcGVuKHRoZVVSTCwnd2luS1BUJyxUZm9ybSlcOyAvL3BvcC5tb3ZlVG8oMCw3NSlcOwpldmFsKCJUZm9ybT0nZGlhbG9nV2lkdGg6Iit3KyJweFw7ZGlhbG9nSGVpZ2h0OiIraCsicHhcO3N0YXR1czpub1w7c2Nyb2xsYmFycz1ub1w7aGVscDpubyciKVw7CnBvcC5tb3ZlVG8oKHNjcmVlbi53aWR0aC13KS8yLChzY3JlZW4uaGVpZ2h0LWgpLzIpXDtpZih0eXBlb2YocmV0U3RyKSE9J3VuZGVmaW5lZCcpIGFsZXJ0KHJldFN0cilcOwp9CmZ1bmN0aW9uIHNob3dMYXkoZGl2SWQpewp2YXIgb2JqRGl2ID0gZXZhbChkaXZJZClcOwppZiAob2JqRGl2LnN0eWxlLmRpc3BsYXk9PSJub25lIikKe29iakRpdi5zdHlsZS5kaXNwbGF5PSIiXDt9CmVsc2V7b2JqRGl2LnN0eWxlLmRpc3BsYXk9Im5vbmUiXDt9Cn0KZnVuY3Rpb24gc2VsVHllTmFtZSgpewogICQoJ3R5cGVOYW1lJykudmFsdWU9JE4oJ1NlbF9UeXBlJylbMF0ub3B0aW9uc1skTignU2VsX1R5cGUnKVswXS5zZWxlY3RlZEluZGV4XS50ZXh0XDsKfQp3aW5kb3cub25sb2FkPWZ1bmN0aW9uKCl7Cgl2YXIgc1BDPU1TSUU/d2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQrd2luZG93Lm5hdmlnYXRvci5jcHVDbGFzcyt3aW5kb3cubmF2aWdhdG9yLmFwcE1pbm9yVmVyc2lvbisnIFNOOk5VTEwnOndpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50K3dpbmRvdy5uYXZpZ2F0b3Iub3NjcHUrd2luZG93Lm5hdmlnYXRvci5hcHBWZXJzaW9uKycgU046TlVMTCdcOwp0cnl7JCgncGNJbmZvJykudmFsdWU9c1BDXDt9Y2F0Y2goZXJyKXt9CnRyeXskKCd0eHRfYXNtY2RlZnNkZHNkJykuZm9jdXMoKVw7fWNhdGNoKGVycil7fQp0cnl7JCgndHlwZU5hbWUnKS52YWx1ZT0kTignU2VsX1R5cGUnKVswXS5vcHRpb25zWyROKCdTZWxfVHlwZScpWzBdLnNlbGVjdGVkSW5kZXhdLnRleHRcO31jYXRjaChlcnIpe30KfQpmdW5jdGlvbiBvcGVuV2luRGlhbG9nKHVybCxzY3IsdyxoKQp7CnZhciBUZm9ybVw7CmV2YWwoIlRmb3JtPSdkaWFsb2dXaWR0aDoiK3crInB4XDtkaWFsb2dIZWlnaHQ6IitoKyJweFw7c3RhdHVzOiIrc2NyKyJcO3Njcm9sbGJhcnM9bm9cO2hlbHA6bm8nIilcOwp3aW5kb3cuc2hvd01vZGFsRGlhbG9nKHVybCwxLFRmb3JtKVw7Cn0KZnVuY3Rpb24gb3Blbldpbih0aGVVUkwpewp2YXIgVGZvcm0sdyxoXDsKdHJ5ewoJdz13aW5kb3cuc2NyZWVuLndpZHRoLTEwXDsKfWNhdGNoKGUpe30KdHJ5ewpoPXdpbmRvdy5zY3JlZW4uaGVpZ2h0LTMwXDsKfWNhdGNoKGUpe30KdHJ5e2V2YWwoIlRmb3JtPSd3aWR0aD0iK3crIixoZWlnaHQ9IitoKyIsc2Nyb2xsYmFycz1ubyxzdGF0dXM9bm8scmVzaXphYmxlPXllcyciKVw7CnBvcD1wYXJlbnQud2luZG93Lm9wZW4odGhlVVJMLCcnLFRmb3JtKVw7CnBvcC5tb3ZlVG8oMCwwKVw7CnBhcmVudC5vcGVuZXI9bnVsbFw7CnBhcmVudC5jbG9zZSgpXDt9Y2F0Y2goZSl7fQp9CmZ1bmN0aW9uIGNoYW5nZVZhbGlkYXRlQ29kZShPYmopewp2YXIgZHQgPSBuZXcgRGF0ZSgpXDsKT2JqLnNyYz0iLi4vc3lzL1ZhbGlkYXRlQ29kZS5hc3B4P3Q9IitkdC5nZXRNaWxsaXNlY29uZHMoKVw7Cn0KZnVuY3Rpb24gY2hrcHdkKG9iaikgeyAgaWYob2JqLnZhbHVlIT0nJykgIHsgICAgdmFyIHM9bWQ1KGRvY3VtZW50LmFsbC50eHRfYXNtY2RlZnNkZHNkLnZhbHVlK21kNShvYmoudmFsdWUpLnN1YnN0cmluZygwLDMwKS50b1VwcGVyQ2FzZSgpKycxMDQ3OScpLnN1YnN0cmluZygwLDMwKS50b1VwcGVyQ2FzZSgpXDsgICBkb2N1bWVudC5hbGwuZHNkc2RzZHNkeGN4ZGZnZmcudmFsdWU9c1w7fSBlbHNlIHsgZG9jdW1lbnQuYWxsLmRzZHNkc2RzZHhjeGRmZ2ZnLnZhbHVlPW9iai52YWx1ZVw7fSB9ICBmdW5jdGlvbiBjaGt5em0ob2JqKSB7ICBpZihvYmoudmFsdWUhPScnKSB7ICAgdmFyIHM9bWQ1KG1kNShvYmoudmFsdWUudG9VcHBlckNhc2UoKSkuc3Vic3RyaW5nKDAsMzApLnRvVXBwZXJDYXNlKCkrJzEwNDc5Jykuc3Vic3RyaW5nKDAsMzApLnRvVXBwZXJDYXNlKClcOyAgIGRvY3VtZW50LmFsbC5mZ2ZnZ2ZkZ3R5dXV5eXV1Y2tqZy52YWx1ZT1zXDt9IGVsc2UgeyAgICBkb2N1bWVudC5hbGwuZmdmZ2dmZGd0eXV1eXl1dWNramcudmFsdWU9b2JqLnZhbHVlLnRvVXBwZXJDYXNlKClcO319Clw8L3NjcmlwdFw+Oz4+Ozs+O3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDA+Oz47bDx0PHA8bDxUZXh0Oz47bDxcPG9wdGlvbiB2YWx1ZT0nU1RVJyB1c3JJRD0n5a2m44CA5Y+3J1w+5a2m55SfXDwvb3B0aW9uXD4KXDxvcHRpb24gdmFsdWU9J1RFQScgdXNySUQ9J+W3peOAgOWPtydcPuaVmeW4iOaVmei+heS6uuWRmFw8L29wdGlvblw+Clw8b3B0aW9uIHZhbHVlPSdTWVMnIHVzcklEPSfluJDjgIDlj7cnXD7nrqHnkIbkurrlkZhcPC9vcHRpb25cPgpcPG9wdGlvbiB2YWx1ZT0nQURNJyB1c3JJRD0n5biQ44CA5Y+3J1w+6Zeo5oi357u05oqk5ZGYXDwvb3B0aW9uXD4KOz4+Ozs+Oz4+Oz4+Oz4+Oz5PljMPZQszJKdQlITFUV4oL8mjUw==
pcInfo: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36undefined5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 SN:NULL
typeName: (unable to decode value)
dsdsdsdsdxcxdfgfg: 0AA23E6EF9E0255322E98E6EE6A118
fgfggfdgtyuuyyuuckjg: F2ED41A0A0E7D33C6E9183D98D5954
Sel_Type: STU
txt_asmcdefsddsd: 1111
txt_pewerwedsdfsdff:
txt_sdertfgsadscxcadsads:
在请求的参数中,好像并没有我们的账号和密码。那是因为这一部分做了加密处理。而且它额外携带了几个参数。
我们可以看下登陆这一块的源码:
我们找到整个 from 表单:
其中,我们会发现很多隐藏元素,
在很多网站上的登陆有这种额外的字段。
__VIEWSTATE ,pcInfo,typeName 就和请求的参数对上了。
注意: 在我们看到的请求参数中 typeName: (unable to decode value) 这里其实是一个“学生”,但是编码方式不对,所有没有显示出来。
那 dsdsdsdsdxcxdfgfg 和 fgfggfdgtyuuyyuuckjg 的 input 中是没有 value 属性的,说明这两个值是 通过 js 赋值进去的。
其实这两个字段一个是 验证码, 一个是 用户密码。 都通过了加密处理。可能针对不同的学校不一样,我就直接展示出来了。
看一下加密的js,这个 js 的调用,我们可以在密码 和 验证码 的input 框上,看见
οnblur="chkyzm(this)" οnkeyup="chkyzm(this) 类似这样的。 然后你再找一下整个网页上,不难发现有这两个js
function chkpwd(obj) {
if (obj.value != '') {
var s = md5(document.all.txt_asmcdefsddsd.value + md5(obj.value).substring(0, 30).toUpperCase() + '10479').substring(0, 30).toUpperCase();
document.all.dsdsdsdsdxcxdfgfg.value = s;
} else {
document.all.dsdsdsdsdxcxdfgfg.value = obj.value;
}
}
function chkyzm(obj) {
if (obj.value != '') {
var s = md5(md5(obj.value.toUpperCase()).substring(0, 30).toUpperCase() + '10479').substring(0, 30).toUpperCase();
document.all.fgfggfdgtyuuyyuuckjg.value = s;
} else {
document.all.fgfggfdgtyuuyyuuckjg.value = obj.value.toUpperCase();
}
}
chkpwd 是加密密码的,chkyzm 是加密验证码的。 加密方式是 md5 一顿加密。
md5(document.all.txt_asmcdefsddsd.value + md5(obj.value).substring(0, 30).toUpperCase() + '10479').substring(0, 30).toUpperCase();
这里不过多介绍,因为网站可能不一样。我们到时候会把这些加密,编程python的写法。
其他的字段 Sel_Type , txt_asmcdefsddsd ,txt_pewerwedsdfsdff , txt_sdertfgsadscxcadsads 都是表单中的,由于加密了密码和验证码,密码和验证码的字段都没有再提交了。都是空值
到时候我们在模拟请求的时候,将这些参数都携带就可以了。
根据分析,这就是验证码访问的链接,http://jwglxt.aynu.edu.cn/sys/ValidateCode.aspx?t=198
其中t 这个参数,应该是一个0-999 的随机数,也是为了防止get 请求,怕浏览器有缓存设计的。
如果我们要模拟请求,肯定要将验证码正确的输入,才能进入系统。那么对验证码的处理可能就会麻烦一点。
现在有这几种方式:
(1)知道验证码的链接,将验证码图片保存到本地,我们在本地查看后,手动输入。
(2)由于这些验证码比较简单,利用文字识别技术,即将验证码图片中的文字识别为文本,自动输入。
我们可能会用到第三方的,比如百度的文字识别,或者我们自己用python开源的学习库训练一个识别验证码的。
(3)使用打码平台,说白了就是你把验证码发给打码平台,打码平台使用人工给你输入验证码,当然针对很难的验证码,可能需要这样。
那我们就先使用第一种方式。
通过上面的说明,我们已经知道了登陆请求的参数和验证码。那么我们还需要关注的就是cookie和session
由于http协议是无状态的,同一个客户端的这次请求和上次请求是没有对应关系。那么我们需要跟踪用户的会话,就需要用到cookie和session。
关于cookie和session,可以看看这个https://www.cnblogs.com/linguoguo/p/5106618.html
在这里,我就只说我们需要cookie 和session干嘛
我们从一开始访问我们登陆的网站,都会分配一个 cookie存放在浏览器本地,我们可以在控制台看见。
cookie 的用途就是用来标识用户,比如你开启一个goole 浏览器,再开启一个 360 浏览器。你会发现 cookie 值是不一样的。在我们模拟登陆的时候,我们要保证发出的请求都是同一个cookie ,这样的操作才能归为同一个会话。
比如我们获取验证码图片的时候,如果cookie 值不一样,获取回来的验证码图片肯定是不对的,因为不在同一个会话中,在后台认证的时候,肯定无法验证通过。
session 的用途就是用来确认用户,通常session 中都存放用户的信息,我们在请求一些需要登陆之后才能访问的网页时,就是看在session中是否有你的信息。
请求头用于说明是谁或什么在发送请求、请求源于何处,或者客户端的喜好及能力。服务器可以根据请求头部给出的客户端信息,试着为客户端提供更好的响应。来源:https://blog.csdn.net/jeffasd/article/details/60140344
一般我们按照正常的请求头就没啥问题,就是改改user-agent。
但是由于青果教务管理系统加了一些请求头信息,比如Referer 和 origin 。
详细可以看这个:https://blog.csdn.net/zdavb/article/details/51161130
https://www.cnblogs.com/bonelee/p/7875163.html
我们只要在请求的时候,加上即可。没啥别的
模拟登陆就是在模仿使用浏览器的登陆过程,就是把浏览器给发送的请求头,请求参数,我们也模仿发送,最终我们也就实现了登陆。下一篇,我们会用普通的python 常用库request来实现模拟登陆。
感觉不错可以给点个赞。