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. RTMPdump 使用说明

    RTMPDump v2.4 2012-07-24RTMPDUMP(1) 名称 rtmpdump - (RTMP流媒体客户端)RTMP streaming media client 使用参数 rtmpd ...

  2. "《算法导论》之‘图’":最小生成树(无向图)

    本文主要参考自<算法>. 加权图是一种为每条边关联一个权值或是成本的图模型.这种图能够自然地表示许多应用.在一幅航空图中,边表示航线,权值则可以表示距离或是费用.在一幅电路图中,边表示导线 ...

  3. Linux - /etc/passwd和/etc/shadow文件结构

    /etc/passwd文件结构 1.账号名称:         就是账号啦!用来对应 UID 的.例如 root 的 UID 对应就是 0 (第三字段):     2.口令:         早期 U ...

  4. Android特效专辑(二)——ViewPager渲染背景颜色渐变(引导页)

    Android特效专辑(二)--ViewPager渲染背景颜色渐变(引导页) 首页:http://blog.csdn.net/qq_26787115/article/details/50439020 ...

  5. PS 色调——老照片效果

    这就是通过调色使照片显得发黄. R_new=0.393*R+0.769*G+0.189*B; G_new=0.349*R+0.686*G+0.168*B; B_new=0.272*R+0.534*G+ ...

  6. Eclipse常见设置

    当新建一个workspace时,习惯做下面的设置: 1. 在eclipse中,默认的Text file encoding是GBK(操作系统是中文简体):如果操作系统是中文繁体,默认是MS950(Big ...

  7. webservice入门简介

    为了梦想,努力奋斗! 追求卓越,成功就会在不经意间追上你 webservice入门简介 1.什么是webservice? webservice是一种跨编程语言和跨操作系统平台的远程调用技术. 所谓的远 ...

  8. 只需几分钟跟小猫学前端(内含视频教程):nodejs基础之用express、ejs、mongdb建设简单的网站

    开门见山视频教程 https://v.qq.com/x/page/d0645s79xrq.html 前 言: 这是小猫的第二篇node教程,第一篇教程是一个简单的试水,小猫的node教程面向对象为没有 ...

  9. 【JDK1.8】JUC——AbstractQueuedSynchronizer

    一.前言 在上一篇中,我们对LockSupport进行了阅读,因为它是实现我们今天要分析的AbstractQueuedSynchronizer(简称AQS)的基础,重新用一下最开始的图: 可以看到,在 ...

  10. MognoDB3.4.2用户访问配置管理

    说在前面,官方文档似乎略有瑕疵. 说一下大规则:把绑定IP换成127.0.0.1IP之后,把security的authorization关闭掉做用户添加操作. 添加用户的方法必须是createUser ...