Discuz的官方站为例。直接点击网页右上角的登录按钮,会弹出一个带验证码的登录窗口。输入验证码之后,会检查验证码是否正确。然后登录。首先,通过抓包分析,这些过程浏览器和服务器交换了哪些数据。

抓包分析

整个过程产生了5条数据:

第一个是GET请求,返回了一段html代码

<div id="main_messaqge_LZH8S">
<div id="layer_login_LZH8S">
<h3 class="flb">
<em id="returnmessage_LZH8S">
用户登录</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login', 0, 1);" title="关闭">关闭</a></span>
</h3>
<form method="post" autocomplete="off" name="login" id="loginform_LZH8S" class="cl" onsubmit="pwdclear = 1;ajaxpost('loginform_LZH8S', 'returnmessage_LZH8S', 'returnmessage_LZH8S', 'onerror');return false;" action="member.php?mod=logging&amp;action=login&amp;loginsubmit=yes&amp;handlekey=login&amp;loginhash=LZH8S">
<div class="c cl">
<input type="hidden" name="formhash" value="41969484" />
<input type="hidden" name="referer" value="http://www.discuz.net/forum.php" />
<div class="rfm">
<table>
<tr>
<th>
<span class="login_slct">
<select name="loginfield" style="float: left;" width="45" id="loginfield_LZH8S">
<option value="username">用户名</option>
<option value="email">Email</option>
</select>
</span>
</th>
<td><input type="text" name="username" id="username_LZH8S" autocomplete="off" size="30" class="px p_fre" tabindex="1" value="" /></td>
<td class="tipcol"><a href="member.php?mod=register">立即注册</a></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th><label for="password3_LZH8S">密码:</label></th>
<td><input type="password" id="password3_LZH8S" name="password" onfocus="clearpwd()" size="30" class="px p_fre" tabindex="1" /></td>
<td class="tipcol"><a href="javascript:;" onclick="display('layer_login_LZH8S');display('layer_lostpw_LZH8S');" title="找回密码">找回密码</a></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th>安全提问:</th>
<td><select id="loginquestionid_LZH8S" width="213" name="questionid" onchange="if($('loginquestionid_LZH8S').value > 0) {$('loginanswer_row_LZH8S').style.display='';} else {$('loginanswer_row_LZH8S').style.display='none';}">
<option value="0">安全提问(未设置请忽略)</option>
<option value="1">母亲的名字</option>
<option value="2">爷爷的名字</option>
<option value="3">父亲出生的城市</option>
<option value="4">您其中一位老师的名字</option>
<option value="5">您个人计算机的型号</option>
<option value="6">您最喜欢的餐馆名称</option>
<option value="7">驾驶执照最后四位数字</option>
</select></td>
</tr>
</table>
</div>
<div class="rfm" id="loginanswer_row_LZH8S"  style="display:none">
<table>
<tr>
<th>答案:</th>
<td><input type="text" name="answer" id="loginanswer_LZH8S" autocomplete="off" size="30" class="px p_fre" tabindex="1" /></td>
</tr>
</table>
</div>
<span id="seccode_cSA"></span>
<script type="text/javascript" reload="1">updateseccode('cSA', '<div class="rfm"><table><tr><th><sec>: </th><td><sec><br /><sec></td></tr></table></div>', 'member::logging');</script>

<div class="rfm  bw0">
<table>
<tr>
<th></th>
<td><label for="cookietime_LZH8S"><input type="checkbox" class="pc" name="cookietime" id="cookietime_LZH8S" tabindex="1" value="2592000"  />自动登录</label></td>
</tr>
</table>
</div>

<div class="rfm mbw bw0">
<table width="100%">
<tr>
<th>&nbsp;</th>
<td>
<button class="pn pnc" type="submit" name="loginsubmit" value="true" tabindex="1"><strong>登录</strong></button>
</td>
<td>
</td>
</tr>
</table>
</div>

<div class="rfm bw0 ">
<hr class="l" />
<table>
<tr>
<th>快捷登录:</th>
<td>

<a href="http://www.discuz.net/connect.php?mod=login&op=init&referer=http%3A%2F%2Fwww.discuz.net%2Fforum.php&statfrom=login" target="_top" rel="nofollow"><img src="static/image/common/qq_login.gif" class="vm" /></a>

<a href="plugin.php?id=wechat:login"><img src="source/plugin/wechat/image/wechat_login.png" class="vm" /></a>
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
<div id="layer_lostpw_LZH8S" style="display: none;">
<h3 class="flb">
<em id="returnmessage3_LZH8S">找回密码</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login')" title="关闭">关闭</a></span>
</h3>
<form method="post" autocomplete="off" id="lostpwform_LZH8S" class="cl" onsubmit="ajaxpost('lostpwform_LZH8S', 'returnmessage3_LZH8S', 'returnmessage3_LZH8S', 'onerror');return false;" action="member.php?mod=lostpasswd&amp;lostpwsubmit=yes&amp;infloat=yes">
<div class="c cl">
<input type="hidden" name="formhash" value="41969484" />
<input type="hidden" name="handlekey" value="lostpwform" />
<div class="rfm">
<table>
<tr>
<th><span class="rq">*</span><label for="lostpw_email">Email:</label></th>
<td><input type="text" name="email" id="lostpw_email" size="30" value=""  tabindex="1" class="px p_fre" /></td>
</tr>
</table>
</div>
<div class="rfm">
<table>
<tr>
<th><label for="lostpw_username">用户名:</label></th>
<td><input type="text" name="username" id="lostpw_username" size="30" value=""  tabindex="1" class="px p_fre" /></td>
</tr>
</table>
</div>

<div class="rfm mbw bw0">
<table>
<tr>
<th></th>
<td><button class="pn pnc" type="submit" name="lostpwsubmit" value="true" tabindex="100"><span>提交</span></button></td>
</tr>
</table>
</div>
</div>
</form>
</div>
</div>

<div id="layer_message_LZH8S" style="display: none;">
<h3 class="flb" id="layer_header_LZH8S">
<em>用户登录</em>
<span><a href="javascript:;" class="flbc" onclick="hideWindow('login')" title="关闭">关闭</a></span>
</h3>
<div class="c"><div class="alert_right">
<div id="messageleft_LZH8S"></div>
<p class="alert_btnleft" id="messageright_LZH8S"></p>
</div>
</div>

<script type="text/javascript" reload="1">
var pwdclear = 0;
function initinput_login() {
document.body.focus();
if($('loginform_LZH8S')) {
$('loginform_LZH8S').username.focus();
}
simulateSelect('loginfield_LZH8S');
}
initinput_login();

function clearpwd() {
if(pwdclear) {
$('password3_LZH8S').value = '';
}
pwdclear = 0;
}
</script>

登录窗口

看起来就是登录窗口。

特别注意到,这段代码中有

loginhash=LZH8S
<input type="hidden" name="formhash" value="41969484" />

'LZH8S'在代码中频繁出现,formhash出现两次。

刷新之后,loginhash和formhash发生了变化。

第二个GET请求返回了一段JavaScript代码

 if($('seccode_cSA')) {
     if(!$('vseccode_cSA')) {
         var sectpl = seccheck_tpl['cSA'] != '' ? seccheck_tpl['cSA'].replace(/<hash>/g, 'codecSA') : '';
         var sectplcode = sectpl != '' ? sectpl.split('<sec>') : Array('<br />',': ','<br />','');
         var string = '<input name="seccodehash" type="hidden" value="cSA" /><input name="seccodemodid" type="hidden" value="member::logging" />' + sectplcode[0] + '验证码' + sectplcode[1] + '<input name="seccodeverify" id="seccodeverify_cSA" type="text" autocomplete="off" style="ime-mode:disabled;width:100px" class="txt px vm" onblur="checksec(\'code\', \'cSA\', 0, null, \'member::logging\')" />' +
             ' <a href="javascript:;" onclick="updateseccode(\'cSA\');doane(event);" class="xi2">换一个</a>' +
             '<span id="checkseccodeverify_cSA"><img src="' + STATICURL + 'image/common/none.gif" width="16" height="16" class="vm" /></span>' +
             sectplcode[2] + '<span id="vseccode_cSA">请输入下面动画图片中的字符<br /><img onclick="updateseccode(\'cSA\')" width="100" height="35" src="misc.php?mod=seccode&update=18644&idhash=cSA" class="vm" alt="" /></span>' + sectplcode[3];
         evalscript(string);
         $('seccode_cSA').innerHTML = string;
     } else {
         var string = '请输入下面动画图片中的字符<br /><img onclick="updateseccode(\'cSA\')" width="100" height="35" src="misc.php?mod=seccode&update=18644&idhash=cSA" class="vm" alt="" />';
         evalscript(string);
         $('vseccode_cSA').innerHTML = string;
     }

 }

code info

其中的update值在刷新和点击换一个验证码之后产生变化

src="misc.php?mod=seccode&update=18644&idhash=cSA"

第三个GET请求的头文件包含

GET http://www.discuz.net/misc.php?mod=seccode&update=18644&idhash=cSA HTTP/1.1
Accept: image/webp,image/*,*/*;q=0.8

根据Accept属性可知返回的是一张图片,请求链接中包含了上一条请求的update值。

第4个GET请求的链接为

GET http://www.discuz.net/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash=cSA&secverify=e38p 

最后的secverify=e38p为验证码,返回的文本为

<?xml version="1.0" encoding="gbk"?>
<root><![CDATA[succeed]]></root>

根据链接中的action=check和返回的文本推断,这是在检查输入的验证码是否正确。

第5个为POST请求,headers为

 POST http://www.discuz.net/member.php?mod=logging&action=login&loginsubmit=yes&handlekey=login&loginhash=LZH8S&inajax=1 HTTP/1.1
 Host: www.discuz.net
 Connection: keep-alive
 Content-Length: 200
 Cache-Control: max-age=0
 Origin: http://www.discuz.net
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
 Content-Type: application/x-www-form-urlencoded
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
 Referer: http://www.discuz.net/forum.php
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.8
 Cookie: t7asq_4ad6_saltkey=X3kj05VV; t7asq_4ad6_lastvisit=1496539605; t7asq_4ad6_nofavfid=1; t7asq_4ad6_ulastactivity=1496722517%7C0; t7asq_4ad6_lastcheckfeed=3051978%7C1496722517; t7asq_4ad6_security_cookiereport=798bNiNKvpmS%2BJb6aMC1CK0u2rBbgm%2Bl4RHOagb%2FADNc1uz1WEc6; t7asq_4ad6_connect_is_bind=0; t7asq_4ad6_forum_lastvisit=D_10_1496722811; pgv_pvi=7116158144; pgv_info=ssi=s5527714008; t7asq_4ad6_seccode=14415.a12e22e835ed3df84a; t7asq_4ad6_lastact=1496730222%09misc.php%09seccode

 formhash=41969484&referer=http%3A%2F%2Fwww.discuz.net%2Fforum.php&loginfield=username&username=123&password=123&questionid=0&answer=&seccodehash=cSA&seccodemodid=member%3A%3Alogging&seccodeverify=e38p

请求的链接中含有loginhash=LZH8S,提交的数据中含有formhash=41969484和验证码seccodeverify=e38p和没有被加密的用户名和密码。

因为用户名和密码是随便输入的,所以返回的文本为

<?xml version="1.0" encoding="gbk"?>
<root><![CDATA[登录失败,您还可以尝试 4 次<script type="text/javascript" reload="1">if(typeof errorhandle_login=='function') {errorhandle_login('登录失败,您还可以尝试 4 次', {'loginperm':'4'});}</script>]]></root>

下面进行模拟登录,注意要获取loginhash、formhash和update的值。

模拟登录

登录过程中的5个请求的headers都不同,在模拟请求时,完全复制抓包到的headers。

定义函数:

 import requests
 session=requests.session()

 #获取登录窗口中的loginhash和formhash
 def get_login_window():
     url='http://www.discuz.net/member.php?mod=logging&action=login&infloat=yes&handlekey=login&inajax=1&ajaxtarget=fwin_content_login'
     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','X-Requested-With':'XMLHttpRequest','Accept':'*/*','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
     #清空原来的headers
     session.headers.clear()
     #更新headers
     session.headers.update(headers)
     r=session.get(url)
     #获取loginhash
     p=r.text.find('loginhash')+len('loginhash')+1
     loginhash=r.text[p:p+5]
     #获取formhash
     p=r.text.find('formhash')+len('formhash" value="')
     formhash=r.text[p:p+8]
     return (loginhash,formhash)

 #获取update
 def get_code_info():
     url='http://www.discuz.net/misc.php?mod=seccode&action=update&idhash=cSA&0.3916181418197131&modid=member::logging'
     r=session.get(url)
     p=r.text.find('update=')
     update=r.text[p+7:p+12]
     return update

 #获取验证码
 def get_code(update):
     url='http://www.discuz.net/misc.php?mod=seccode&update='+update+'&idhash=cSA'
     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Accept':'image/webp,image/*,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
     session.headers.clear()
     session.headers.update(headers)
     r=session.get(url)
     if(r.content[:3]==b'GIF'):
         #保存验证码图片
         file=open('code.gif','wb')
         file.write(r.content)
         file.close()
     else:
         #打印错误信息
         print(r.text)

 #检查验证码是否正确
 #通过人工识别验证码code,:)
 def check_code(code):
     url='http://www.discuz.net/misc.php?mod=seccode&action=check&inajax=1&modid=member::logging&idhash=cSA&secverify='+code
     headers={'Host':'www.discuz.net','Connection':'keep-alive','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Accept':'image/webp,image/*,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate, sdch','Accept-Language':'zh-CN,zh;q=0.8'}
     session.headers.clear()
     session.headers.update(headers)
     r=session.get(url)
     return r.text

 #模拟登录
 def login(loginhash,formhash,code,username,password):
     url='http://www.discuz.net/member.php?mod=logging&action=login&loginsubmit=yes&handlekey=login&loginhash='+loginhash+'&inajax=1'
     data={'formhash':formhash,
           'referer':'http://www.discuz.net/forum.php',
           'loginfield':'username',
           'username':username,
           'password':password,
           ',
           'answer':'',
           'seccodehash':'cSA',
           'seccodemodid':'member::logging',
           'seccodeverify':code}
     headers={','User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36','Content-Type':'application/x-www-form-urlencoded','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','Referer':'http://www.discuz.net/forum.php','Accept-Encoding':'gzip, deflate','Accept-Language':'zh-CN,zh;q=0.8'}
     session.headers.clear()
     session.headers.update(headers)
     r=session.post(url,data)
     print(r.text)

模拟登录:

(loginhash,formhash)=get_login_window()
get_code(get_code_info())
code=input()#人工识别 :)
check_code(code)
#[CDATA[succeed]]
login(loginhash,formhash,code,username,password)
#欢迎您回来,现在将转入登录前页面

测试:

此页面只有在登录后才能显示

url='http://www.discuz.net/home.php?mod=space&do=pm'

标题为 ”用户名 -  Discuz! 官方站 -  Powered by Discuz!“

如果未登录,则标题为 ”提示信息 -  Discuz! 官方站 -  Powered by Discuz!“

session.headers.clear()
r=session.get(url)
p=r.text.find('<title>')+len('<title>')
print(r.text[p:r.text.find('<',p)])

如果打印出了 ”用户名 -  Discuz! 官方站 -  Powered by Discuz!“,则证明登录成功。

在Python中用Request库模拟登录(三):Discuz论坛(未加密,有验证码,有隐藏验证)的更多相关文章

  1. 在Python中用Request库模拟登录(一):字幕库(无加密,无验证码)

    字幕库的登录表单如下所示,其中省去了无关紧要的内容: <form class="login-form" action="/User/login.html" ...

  2. 在Python中用Request库模拟登录(四):哔哩哔哩(有加密,有验证码)

    !已失效! 抓包分析 获取验证码 获取加密公钥 其中hash是变化的,公钥key不变 登录 其中用户名没有被加密,密码被加密. 因为在获取公钥的时候同时返回了一个hash值,推测此hash值与密码加密 ...

  3. 基于python的request库,模拟登录csdn博客

    以前爬虫用urllib2来实现,也用过scrapy的爬虫框架,这次试试requests,刚开始用,用起来确实比urllib2好,封装的更好一些,使用起来简单方便很多. 安装requests库     ...

  4. Python:GUI库tkinter(三)

    这一章是对前两章的总结: Python:GUI库tkinter(一) Python:GUI库tkinter(二) 前两章是对控件的介绍,第一章可以知道各控件使用时的具体参数,第二章以具体的例子展示了每 ...

  5. Python手动构造Cookie模拟登录后获取网站页面内容

    最近有个好友让我帮忙爬取个小说,这个小说是前三十章直接可读,后面章节需要充值VIP可见.所以就需要利用VIP账户登录后,构造Cookie,再用Python的获取每章节的url,得到内容后再使用 PyQ ...

  6. python之cookie, cookiejar 模拟登录绕过验证

    0.思路 如果懒得模拟登录,或者模拟登录过于复杂(多步交互或复杂验证码)则人工登录后手动复制cookie(或者代码读取浏览器cookie),缺点是容易过期. 如果登录是简单的提交表单,代码第一步模拟登 ...

  7. Python 爬虫实战5 模拟登录淘宝并获取所有订单

    经过多次尝试,模拟登录淘宝终于成功了,实在是不容易,淘宝的登录加密和验证太复杂了,煞费苦心,在此写出来和大家一起分享,希望大家支持. 本篇内容 python模拟登录淘宝网页 获取登录用户的所有订单详情 ...

  8. python之简单POST模拟登录

    宿舍自从换了校园网的认证系统就不再用客户端了,只能在网页登录.每次上网都要打开浏览器的话很不方便,而且我有时在ubuntu控制台上想联网但终端文本浏览器似乎不支持页面跳转,既然如此,何不写个客户端呢? ...

  9. 《转载》python爬虫实践之模拟登录

    有些网站设置了权限,只有在登录了之后才能爬取网站的内容,如何模拟登录,目前的方法主要是利用浏览器cookie模拟登录.   浏览器访问服务器的过程   在用户访问网页时,不论是通过URL输入域名或IP ...

随机推荐

  1. 根据分析查看相关知识点分析iOS 三种录制视频方式

    这篇文章讨论了关于如何配置视频捕获管线 (pipeline) 和最大限度地利用硬件性能的一些不同选择. 这里有个使用了不同管线的样例 app,可以在 GitHub 查看. 第一种:UIImagePic ...

  2. BP 神经网络

    BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一.BP ...

  3. how tomcat works 总结 二

    第五章 servlet容器 第 5 章讨论 container 模块.container 指的是 org.apache.catalina.Container 接口,有4 种类型的 container: ...

  4. Spring的声明式事务管理

    在service类前加上@Transactional,声明这个service所有方法需要事务管理.每一个业务方法开始时都会打开一个事务. Spring默认情况下会对运行期例外(RunTimeExcep ...

  5. Nginx的内部(进程)模型

    nginx是以多进程的方式来工作的,当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式.nginx采用多进程的方式有诸多好处. (1)nginx在启动后 ...

  6. mq常用命令

    IBM MQ常用命令   常用命令 创建队列管理器crtmqm –q QMgrName-q是指创建缺省的队列管理器删除队列管理器dltmqm QmgrName启动队列管理器strmqm QmgrNam ...

  7. Storm 常用命令

    1.启动Nimbus bin/storm nimbus & 2.启动Supervisor bin/storm supervisor & 3.启动UI bin/storm ui & ...

  8. centos6-7克隆主机网卡无法启动问题

    1,centos6和redhat6左右的版本  第一,先找到网卡的mac地址,将其配置在配置文件中,重新启动网卡. 故障产生的原因: 由于克隆虚拟机,vmware只是修改了虚拟机的名字等信息,并没有修 ...

  9. 摘抄详细的VUE生命周期

     Vue所有的生命周期钩子自动绑定在this上下文到实例中,因此你可以访问数据,对属性和方法进行运算.这意味着你不能使用箭头函数来定义一个生命周期方法.这是因为箭头函数绑定了父上下文,因此this与你 ...

  10. Terminating app due to uncaught exception 'CALayerInvalid', reason: 'layer <CALayer: 0x7fda42c66e30> is a part of cycle in its layer tree'

    iOS App里面所有的View构成一个组件树,这个树里面如果有了闭环就会出现这个报错,最常见的你不小在某UIViewController里面写了这样的代码: someView.addSubView( ...