v2主要依据是核心 JS 文件mkd_v2.js 版本,如下图所示:
第一次 https://passport.baidu.com/cap/init 接口,请求的 ak
是固定值,当然不同场景不同网站是不一样的,_
时间戳,ver=1,返回值 as
、tk
都是后面会用到的。
请求https://passport.baidu.com/cap/style接口,会用到tk值,得到验证码图片,如下图:
请求https://passport.baidu.com/cap/log接口,会用到fs值,得到验证结果,如下图:
fs值计算方式:
v2 版本分析
v2 版本和 v1 版本基本上差不多,区别在于 rzData
的结构不太一样,ac_c
的计算方法不一样,以及 AES 的 IV 不一样,先看 AES 的 IV,v2 版本是 as 值加上固定值 appsapi2
:
然后再看看 rzData
,common
字段下基本上就是 v1 的 rzData
的格式,captchalist
下,至少有 spin-0
(旋转)、`puzzle-0
(滑块)、click-0
(点选)三种,ac_c
依旧是旋转角度占比、滑动占比以及点选坐标信息,其他的依旧是写死或者置空就行。
然后就是 ac_c
的计算方法了,首先是旋转验证码,直接搜索 ac_c
:
往上跟栈,有个 percent 的地方,一个三目表达式,e 是固定值 290,e - 52 = 238
,238 也就是滑动条能够滑动的最大长度:
如果我们识别出来的是旋转角度 angle
,则 ac_c
计算方法如下:
var distance = angle * 238 / 360
var ac_c = Number((distance / (290 - 52)).toFixed(2))
// 也可以直接写成:
var ac_c = Number((angle / 360).toFixed(2))
而对于滑块验证码就有所不同,同样是这个地方的三目表达式,但是要走后面的逻辑:
如果我们识别出来的是滑动距离 distance
,则滑块 ac_c
的计算方法如下:
var ac_c = Number((distance / 290).toFixed(2))
同样对于点选验证码来说,也不一样,ac_c
的值是点击的 xy 坐标以及时间戳:
其他问题
前面我们说了百度的验证应该有两次,对于第二次验证,也就是 v1 的 viewlog/c
接口,v2 的 cap/c
接口,即便你第一次校验通过了,这个 c 接口校验也有可能不通过,出现这种情况的原因是通过的时间太短了,随机 time.sleep
1-3 秒即可,如果时间太短,c 接口可能会报以下验证错误:
{'code': 1, 'isRectified': False, 'msg': 'Verification Failed'}
还有一种情况就是提示存在安全风险,请再次验证
,出现这种情况你会发现去浏览器手动滑也是一样的,所以在本地加个再次验证的逻辑就行了,一般来说第二次验证就能通过。
{'code': 0, 'msg': 'success', 'data': {'f': {'feedback': 'https://www.baidu.com/passport/ufosubmit.html', 'reason': '存在安全风险,请再次验证'}}}
然后就是请求 header 里没有 Referer
或者 Referer
不正确的话,会报错:
// v1 没有 Referer
{'code': 1, 'msg': 'Unregistered Host'}
// v1 Referer 不正确
{'code': 1, 'msg': 'Invalid Request', 'data': []}
// v2 没有 Referer 或者 Referer 不正确
{'code': 100600, 'msg': 'Unauthorized Host'}