逆向思路:通过XHR断点,确定发送XHR请求的位置。然后通过执行栈,找到构造参数的JavaScript代码所在位置。将JavaScript构造参数的逻辑用python实现,从而构造加密参数值,实现正确的url请求。
爬取的网页为:https://dynamic6.scrape.cuiqingcai.com/
首先列表页的请求url为,第一页与第二页的分别为:
能够看出列表页url需要构建的参数为limit,offset,token。其中limit为每页的个数为10,offset可以看作是它的偏移量。第一页为0,第二页10,第三页20。这两个参数可以自己直接构造。主要是token值的构建。
首先我们打一个XHR断点,首先确定发送XHL定位位置。因为对于发送Ajax请求来说,找到列表页url请求发送的位置,就可以往前寻找,一步步找到构建url里边参数的位置。
因url中包含/api/movie,因此我们可以将此作为打断点的内容。
然后通过刷新页面,确定发送XHR(url)的位置。
现在已经确定了请求发送的位置,现在我们只要通过Call Stack找到token构建的位置即可。因为url肯定是构建完token,才能获得完整url然后去请求的。
现在我们给条发送请求的位置打上断点,然后去Call Stack去找token构建位置。打上断点后刷新页面,记得每次打断点之前将原先打的断点先取消。
此时我们就可以一步一步往前走。寻找参数构建位置。通过从上往下依次点击,找到 了在onFetchData中存在token的构建。
可以看到token对应的值为_0x39f52。然后我们去寻找_0x39f52,可以看到其构造过程为
我们可以从onFetchData开头打上断点。一步步调试可以发现每个变量的结果是怎么样的。当调试至上边表达式时,将this后的圈住发现,其指代的就是/api/movie。所以现在我们的主要目的就是前边这个函数了。其实我们要得到的就是_0x376c60['a']的值
我们可以在watch内去查看这个函数,找到函数的位置。将_0x376c60添加入watch内。便可以看到其函数的location。点击便可以跳转到函数所在的位置。
其函数定位至:
也就是说_0x376c60['a']的值就是_0x31b852()的返回值。我们将这个函数用python实现出来也就得到了这个值。
同样在函数开始打断点,一步步看函数的执行过程。播放键右边那个即是单步调试按钮。
我们可以先单步点击,一步步执行完整个函数,可以在scope中看到每个变量执行完的结果。首先观察最前边的 _0x320ba5。可以看到其逻辑大概为一个时间戳的值除以1000四舍五入最后转为字符串。能够看到其执行完后值为159468934。需要注意的是在javascript中的时间戳为毫秒级,而python中的time.time()得到的时间戳为秒级,所以直接使用time.time()就可以,不需要再除以1000。
其python实现过程便为:_0x320ba5 = str(int(time.time()))
继续进行单步调试可以发现:_0x4fef38的值为['/api/movie'],后边随着代码继续运行,,将这个值,与得到的时间戳放在一起,即同一个列表中。其结果也可以通过单步调试发现。
然后开始计算_0x216573:
此句大致意思为将刚刚得到的_0x4fef38,用‘,’将列表里的元素隔开,然后转化为utf-8后再进行sha1加密最后转成十六进制。
这需要注意的逻辑是先执行完(_0x4fef38['join'](',')),后应该先进行encode(),才能进行sha1加密。因此大致逻辑为先用逗号隔开_0x4fef38,然后将其encode为utf-8,然后进行sha1,最后想起结果转为16进制。其Python实现为
之后程序为 ,即将刚才计算出来的结果,与第一步计算的时间戳放在一个列表中用逗号隔开。
最后观察_0x3fc8fd,其为实现一个base64编码的过程。
所以最终_0x93d0aa的值为将_0x322162用‘,’隔开后进行encode()最后进行base64编码,即为最终结果。其Python实现为
base64.b64encode(','.join(_0x322162).encode('utf-8')).decode('utf=8')。
最终便得到了_0x376c60['a']的返回值。即最终的token的值。
得到token后我们列表页url中所有的参数也就算是得到了。通过构建完整的url即可获得详情页的信息。
小胖胖的猪崽