以pay.qq.com查询QQ账号Q币信息为例,了解一下网站的二维码登陆大致是如何实现的
首先打开腾讯pay.qq.com主页上的登陆就可以获取到二维码了,使用浏览器的F12分析请求过程
发现通过打开的https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html可以获取到cookies,这个url就先记下来
继续往下,打开下面的url,响应回来的就是二维码了
那这些请求的参数是如何得到的呢,多次请求分析发现只有t是随机变化的,那就给个随机数吧
参数t的python生成方式(python生成的随机数多一位)
import random a=str(random.random()) print(a) print(a[:-1])
当用手机扫了二维码之后,会发现一直请求一个地址,而返回的内容就是判定二维码是否过期的结果。但是请求的url随二维码的更新而变化的
获取是否过期(通过请求的url发现如下规律)
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1300613866&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514654333018&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1641999182&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514655242011&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken=1460309603&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-1514656150867&js_ver=10233&js_type=1&login_sig=pGo5iOnV6O*DY3BgsPM22zAvlWCnVl48PPjrmWIJtQKMHpvYCoWpavmP1JcdWn6g&pt_uistyle=40&aid=11000101&
这些url返回结果如下这样的形式
ptuiCB('66','0','','0','二维码未失效。(2079330212)', '')
那么,这次的url所附带的参数更多了,究竟是如何生成的,由于没有学习过JavaScript,但是猜想这种交互式的网页一定有js控制的。
打开请求主页中所有的js链接,文件中都没有相关信息,于是重头分析请求过程,发现请求了一个url里面返回大量函数,里面有且仅有一个ptqrtoken变量
https://imgcache.qq.com/ptlogin/ver/10233/js/c_login_2.js?max_age=604800&ptui_identifier=000E010D989AA31CE07BA6E98F56BC76012729B221D540BFF0DE375CAC8A
这个url返回的代码里面找到getSubmitUrl函数如下:
三个参数ptqrtoken、action、login_sig。两个参数都在函数中说明了,login_sig同样在这段返回的代码里面,事实上就是cookies里面的pt_login_sig
于是乎可以试着构造一个这样的url,判断二维码是否有效。响应的代码里面跟三个参数有关的代码如下
函数的具体实现—ptqrtoken生成
hash33:function(t){ for(var e=0,i=0,n=t.length;i<n;++i) e+=(e<<5)+t.charCodeAt(i); return 2147483647&e }
函数的具体实现—action生成
,pt.plogin={account:"",at_account:"",uin:"",salt:"",checkState:!1,lastCheckAccount:"",needVc:!1,vcFlag:!1,ckNum:{},action:[0,0],passwordErrorNum:1,isIpad:!1,seller_id:703010802 action.join(“-”)+”-”+(new Date-0)
函数的具体实现—login_sig生成(这个是http响应时返回的)
login_sig=pt.ptui.login.sig
用javascript测试下实现函数功能的代码(不懂js所以先试下运行出来是什么结果)
1、ptqrtoken
<script type="text/javascript"> document.write(isNaN(123)+ "<br />") function test(t){ for(var e=0,i=0,n=t.length;i<n;++i) e+=(e<<5)+t.charCodeAt(i); return 2147483647&e; } document.write(test("l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a")) </script>
2、action
document.write(new Date-0); document.write("<br/>") var t=new Date() action=[0,0] document.write(action.join("-")+"-"+t.getTime())
知道了逻辑,用python重写javascript的函数来实现同样功能
ptqrtoken的生成
t1="l5ReOk*DhvMzPYYjfqWzkYjwSs52j6lzw1Oy6SaMsUNywLorCwuRuP8TbGfzSf*a" def test(t): i=0 e=0 n=len(t) fori in range(n): e=e+(e<<5) e=e+ord(t[i]) print(e) print(2147483647&e) test(t1)
action的生成就只是一个时间函数
import time print(int(time.time()*1000))
继续往下分析连续请求该Url响应用户的扫码登陆状态,发现扫码成功后,也会返回cookies
带着cookies请求个人账户主页https://my.pay.qq.com/account/index.shtml?aid=pay.index.header.acct&ADTAG=pay.index.header.acc
发现返回的内容还是没有Q币的信息,说明内容还是由javascript动态生成
返回的js里面是没有Q币信息的
继续分析下面请求的url
发现了这个 https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_=0.9267836264725212
于是返回的json,qb_balance就是个人账户的Q币
import requests import time import random def ptqrtoken_str(qrsig): #三个函数就是url的三个参数生成 i=0 e=0 n=len(qrsig) for i in range(n): e=e+(e<<5) e=e+ord(qrsig[i]) e=2147483647&e return e def action_str(): a=int(time.time()*1000) b='0-0-'+str(a) return b def pt_loginsig_str(ckiesget): st=ckiesget.headers['Set-Cookie'] return st[st.find('pt_login_sig=')+13:st.find('pt_login_sig=')+77] url_getcookies="https://xui.ptlogin2.qq.com/cgi-bin/xlogin?appid=11000101&target=self&style=40&s_url=https://pay.qq.com/ipay/login-proxy.html" s=requests.session() #requests的session可以自动管理cookies ckget=s.get(url_getcookies) t=str(random.random()) url_getqr="https://ssl.ptlogin2.qq.com/ptqrshow?appid=11000101&e=2&l=M&s=3&d=72&v=4&t="+t[:-1]+"&pt_3rd_aid=0" qrget=s.get(url_getqr) f=open('tmp.png','wb') #将二维码保存为图片手动打开来扫码^_^ f.write(qrget.content) f.close() for i in range(1,7): #简单的循环返回二维码是否失效,循环结束前扫码就获得了cookies time.sleep(3) qrsig=qrget.headers['Set-Cookie'].split(';')[0][6:] url_check_timeout="https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https://pay.qq.com/ipay/login-proxy.html&ptqrtoken="+str(ptqrtoken_str(qrsig))+"&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action="+action_str()+"&js_ver=10233&js_type=1&login_sig="+pt_loginsig_str(ckget)+"&pt_uistyle=40&aid=11000101&" timeoutget=s.get(url_check_timeout) print(timeoutget.status_code) print('----------------text---------------') print(timeoutget.text) print(timeoutget.headers) happy3=s.get("https://my.pay.qq.com/cgi-bin/personal/balance_query_sortflow.cgi?items=qd,qb&_="+str(random.random())) print(happy3.text)