python 模拟点击第三方软件_使用Python模拟腾讯第三方认证-篇2

上篇分析了模拟登陆的流程,以及HTTP请求和回应,下面我们开始编码实现。

编码

准备

安装requests, pip install requests

使用requests请求比使用urllib方便了很多,下面简单封装了一个http请求函数fetch:

'''

默认为GET,如果赋值data后则为POST方式

'''

def fetch(self, url, data=None, **kw):

if data is None:

func = self.session.get

else:

kw['data'] = data

func = self.session.post

return func(url, **kw)

使用QQ登录

self.jkqqurl='http://passport.jikexueyuan.com/connect/qq'

response = self.fetch(self.jkqqurl)

self.state = re.findall('&state=(.*?)\&', response.url)[0] #(.*?), 括号为返回匹配值,即=后面的

self.client_id = re.findall('&client_id=(.*?)\&', response.url)[0]

因为下面向腾讯请求认证需要学院返回的这两个参数:STATE, CLIENTID, 这里记录下来。

请求登录页面

通过上步请求后,虽然学院发起了向腾讯认证服务器的请求,但是因为没有登录会被重新定向至登录授权页面,

这里我们手动请求一次封装在IFrame中的登录页面:

self.xloginurl='http://xui.ptlogin2.qq.com/cgi-bin/xlogin'

g = self.fetch(self.xloginurl, params = {

'appid': self.appid,

'style': 23,

'login_text': '授权并登录',

'hide_title_bar': 1,

'target': 'self',

's_url': self.loginjumpurl,

'pt_3rd_aid': 101119675,

'pt_feedback_link': self.feedbackurl,

}).text

这步操作理论上会产生一些登录请求的会话信息,还是尽量模拟浏览器操作,后面再作精简。

登录校验

分析来看,腾讯根据登录请求类型来产生校验码图片或文字型校验码(如果不需要校验码图片),看代码:

self.checkurl2='http://check.ptlogin2.qq.com/check'

g = self.fetch(self.checkurl2, params = {

'regmaster': '',

'pt_tea': 1,

'pt_vcode': 1,

'uin': self.user,

'appid': self.appid,

'js_ver': 10120,

'js_type': 0,

'login_sig': self.session.cookies['pt_login_sig'],

'u1': self.loginjumpurl,

}).text

v = re.findall('\'(.*?)\'', g)

vcode = v[1]

uin = v[2]

这里pt_login_sig是从session中取得,requests从session中获取参数还是很方便的。

返回值格式:

ptui_checkVC(

'0', #参数为是否需要校验码

'!JCD', #系统生成的校验码

'\x00\x00\x00\x00\x3x\x2x\x3x\x3x', #用户ID进行转化后的值

'47e6754aafb6138d4cdcdfdd1602bc8df9d29893cc705484d148adb079105ebba462f8cd7c18025441c5309c1b50378059fb5a0fcd18b206', #ptvfsession,后面登录使用

'0');

登录

登录时判断是否需要校验码,如果需要则下载校验码图片。

开篇说过,腾讯第三方登录认证是不需要校验码的,从上面结果也能看出v[0]一直为0

self.loginurl2='http://ptlogin2.qq.com/login'

if v[0] == '1': # 需要校验码

vcode = self.getVerifyCode(vcode) #获得校验码

g = self.fetch(self.loginurl2, params = {

'u': self.user,

'verifycode': vcode,

'pt_vcode_v1': 0,

'pt_verifysession_v1': self.session.cookies['ptvfsession'],

'p': self.pwdencode(vcode, uin, self.pwd),

'pt_randsalt': 0,

'u1': self.loginjumpurl,

'ptredirect': 0,

'h': 1,

't': 1,

'g': 1,

'from_ui': 1,

'ptlang': 2052,

'action': self.action,

'js_ver': 10138,

'js_type': 0,

'login_sig': self.session.cookies['pt_login_sig'],

'pt_uistyle': 33,

'aid': self.appid,

'pt_3rd_aid': 101119675,

}).text

登录处理这块处理的东西较多,分开看:

ptvfsession和pt_login_sig都是从cookies中取得

密码加密

为了防止密码被截取,肯定做足了混淆加密,具体算法可以参考c_login_2.js中的实现,这里参考了qqlib的代码http://www.jianshu.com/p/4217d8f3574b:

def fromhex(self, s):

# Python 3: bytes.fromhex

return bytes(bytearray.fromhex(s))

#pip install rsa

pubKey=rsa.PublicKey(int(

'F20CE00BAE5361F8FA3AE9CEFA495362'

'FF7DA1BA628F64A347F0A8C012BF0B25'

'4A30CD92ABFFE7A6EE0DC424CB6166F8'

'819EFA5BCCB20EDFB4AD02E412CCF579'

'B1CA711D55B8B0B3AEB60153D5E0693A'

'2A86F3167D7847A0CB8B00004716A909'

'5D9BADC977CBB804DBDCBA6029A97108'

'69A453F27DFDDF83C016D928B3CBF4C7',

16

), 3)

def pwdencode(self, vcode, uin, pwd):

# uin is the bytes of QQ number stored in unsigned long (8 bytes)

salt = uin.replace(r'\x', '')

h1 = hashlib.md5(pwd.encode()).digest()

s2 = hashlib.md5(h1 + self.fromhex(salt)).hexdigest().upper()

rsaH1 = binascii.b2a_hex(rsa.encrypt(h1, self.pubKey)).decode()

rsaH1Len = hex(len(rsaH1) // 2)[2:]

hexVcode = binascii.b2a_hex(vcode.upper().encode()).decode()

vcodeLen = hex(len(hexVcode) // 2)[2:]

l = len(vcodeLen)

if l < 4:

vcodeLen = '0' * (4 - l) + vcodeLen

l = len(rsaH1Len)

if l < 4:

rsaH1Len = '0' * (4 - l) + rsaH1Len

pwd1 = rsaH1Len + rsaH1 + salt + vcodeLen + hexVcode

saltPwd = base64.b64encode(

tea.encrypt(self.fromhex(pwd1), self.fromhex(s2))

).decode().replace('/', '-').replace('+', '*').replace('=', '_')

return saltPwd

获取校验码:

#这里只是给出给参考,从WebQQ登录查询校验码过程获得

self.imgurl='http://captcha.qq.com/getimage'

def getVerifyCode(self, vcode):

r = self.fetch(self.imgurl, params = {

'r':0,

'appid':self.appid,

'uin':self.user,

'vc_type':vcode,

})

tmp = tempfile.mkstemp(suffix = '.jpg')

os.write(tmp[0], r.content)

os.close(tmp[0])

os.startfile(tmp[1])

vcode = input('Verify code: ')

os.remove(tmp[1])

return vcode

如果登录成功则返回值如下:

ptuiCB('0','0','http://openapi.qzone.qq.com/oauth/login_jump','0','登录成功!', 'XXXX');

登录跳转

代码很简单:

self.loginjumpurl='http://openapi.qzone.qq.com/oauth/login_jump'

g = self.fetch(self.loginjumpurl).text

这一步会返回这样一个页面:

document.domain = 'qq.com';

if(parent.agree){

parent.agree()

}else{

parent.isAgreed = true;

}

这一步,对于模拟情况作用不大,对于浏览器的话会执行上报报告,表格提交等操作,后面会模拟。

重点是JS块中的parent.agree详细操作流程,可以从qlogin_v2.js中分析到。

上传报告

这两个报告没有特别的:

self.appsupporturl='http://appsupport.qq.com/cgi-bin/appstage/mstats_report'

self.reporturl='http://cgi.connect.qq.com/report/report_vm'

g = self.fetch(self.appsupporturl, params = {

'report_type': '4',

'platform': 8,

'app_id': '101119675',

'result': 0,

'act_type': 2,

'uin': self.user,

'login_status': 2,

'via': 1,

't': int(time.time()),

}).text

#正确的话返回{"ret":0,"msg":"成功"}

g = self.fetch(self.reporturl, params = {

'tag': 0,

'log': '101119675_10613_0',

't': int(time.time()),

}).text

#正确的话返回{"ec":0}

获取授权

self.authurl='https://graph.qq.com/oauth2.0/authorize'

#更新请求头,防止被屏蔽

self.session.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240'})

token = self.gettoken()

data = {

'response_type': 'code',

'client_id': 101119675,

'redirect_uri': 'http://passport.jikexueyuan.com/connect/success?t=qq',

'scope': 'get_user_info',

'state': self.state,

'src': '1',

'update_auth': '1',

'openapi': '80901010',

'g_tk': token,

'auth_time': int(time.time()),

'ui': '556F791F-682E-47B7-BC66-CE179327DB04',#UID,可以随机生成,这里简单使用了抓包结果

}

response = self.fetch(self.authurl, data = data)

gettoken定义如下:

def gettoken(self):

str = self.session.cookies['skey']

hash = 5381

for i in str:

t = (hash << 5) + ord(i)

hash = hash + t

return hash & 0x7fffffff

如果成功的话,则会跳转至学院主页。

如果失败,需要分析是哪一步错了,主要有:密码,STATE, pt_login_sig. ptvfsession。

试验

self.session.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240'})

g = self.fetch('http://www.jikexueyuan.com/course/2185_1.html?ss=1').text

print g

查看打印信息,看是否已经登录即可。

总结

编码流程基本是针对登录过程抓包的实现,比较原始,并且刚开始写python程序,后面再整理出一个干净的版本。

到现在为止所做的足够对学院进行爬虫分析了,后续更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值