反爬十
之前搞的有反爬的网站基本都是采用debug,然后扣代码的方式,扣出来核心的代码,自己通过node运行或者使用python运行,但是有些情况下难以扣出来核心的代码,或者说这样做的效率非常低,所以还有另一种方式就是拿出全部js,然后直接运行我们需要的方法,如果报错再去定位问题,具体解决。下面列举两个网站的例子。
信用邯郸
网址:https://credit.hd.gov.cn/xyxxgs/
请求列表页时,需要以上参数,其中nonceStr、queryContent、sign都是通过js代码通过一定的逻辑生成的。
首先看nonceStr参数:
我们定位到H.uuid()之后,里面还调用了其他方法,按照以往的做法,就是把所有被调用的方法都扣出来,但是考虑到一种情况就是层层调用的方法特别多(懂的都懂,不细说了)
那这里可以采用的另一种方法就是拿出全部的js,不过注意这个网站的js是一个自执行的function,调用时传入的参数包含this,所以可以改写为普通function,然后再调用,传入参数为空(测试一下大概率是没问题的);然后在文件开头定义个全局的window对象,window = global;
,然后在H方法定义的地方,将其保存到window对象中,之后在最后直接调用即可。
1 | function get_uuid(){ |
queryContent参数,注意看是图中的i,而i主要是ls.sm4.encrypt生成的
同样的,在适当的地方将ls方法保存到window对象window.ls = ls
,之后直接调用
1 | function get_query_content(i){ |
这里面参数值的问题是一些细节问题,就不详细展开了,调试的时候都能看得到。
sign参数,是图中的o,生成的代码是o = Zi(o = ls.sm2.signature(a, e.appSignPrivateKey, e.appSignPublicKey, e.appId))
同样的,在适当的地方将Zi方法保存到window对象window.Zi = Zi
,之后直接调用
1 | function get_sign(a){ |
同样的针对返回的数据解密方法也是利用这样的套路1
2
3
4
5
6
7
8function sm4_decrypt(text){
try {
return window.kr.sm4.decrypt(text, "dbb78b8b64d640bb130255c69e959973", {output: "string"});
} catch (err) {
console.error(err.message)
return ''
}
}
信用安徽
地址:
https://credit.ah.gov.cn/ms/credit/temp/selectQueryTableTmp.do?queryId=54474&activeTitle=%E8%A1%8C%E6%94%BF%E7%AE%A1%E7%90%86%E4%BF%A1%E6%81%AF
网址可能打不开,需要从首页点进去。
这个详情页请求时,sign参数是通过加密的js生成的。
定位到sign生成的地方
这里去一段段的扣Js比较麻烦,我们也是采用直接拿全部js的方法,拿出来之后,我们本身是知道直接传入参数,调用radms方法就能获取需要的参数的
1 | res = radms("65885665-a675-494f-97ce-15a28d86ef7f", "78890", 1716446852342) |
直接调用测试,会报一些错误,根据报错提示和代码行数,定位到问题进行修复
报错:Uncaught ReferenceError ReferenceError: window is not defined
解决办法:在文件开头定义window全局对象,window = global;
报错:Uncaught ReferenceError ReferenceError: CryptoJS is not defined
解决办法:导入包,CryptoJS = require('crypto-js')
报错:Uncaught ReferenceError ReferenceError: navigator is not defined
解决办法:在开头定义var navigator = {};
报错:Cannot read properties of undefined (reading 'webdriver')
报错行数 3943, var _uu = window['navigator'][_0x2246a3(0x176)], _aa = '0';
这里 _0x2246a3(0x176) 就是 webdriver
这一步骤就是为了给_uu赋值,我们回到浏览器中,运行一下window['navigator'][_0x2246a3(0x176)]
拿到值,直接在这里写死就好了
以上问题解决完之后,基本就可以运行得到sign的值了。
node express包
node 的express包可以把node代码部署为服务,只要通过下述代码即可快速运行
1 | const express = require("express"); // 先安装一下express包 |
在自定义的js代码中需要先导出这里想要执行的方法,module.exports = {radms:radms};
这里是使用res.send将生成的参数返回,返回的格式是字符串,如果需要以json格式返回,则先预先定义一个json,然后使用res.json(result)返回。
这个简单的demo基本已经可以应付日常任务了,如果还需要更复杂的功能,则查看express文档即可。
pm2
pm2 是 nodejs 的进程管理器,默认支持负载均衡,能够守护进程。还支持查看应用运行时的性能,资源占用情况等
pm2支持后台运行:普通启动方式:node index.js,关闭终端就结束进程;pm2可以后台运行,终端关闭不影响。
pm2安装:npm install pm2 -g(全局)
PM2常用命令:
启动进程:pm2 start server.js / pm2 start 文件夹
pm2 start app.js –watch 当文件变化时自动重启应用
pm2 list / pm2 status 查看所有启动的应用列表(状态)
pm2 monit 显示每个应用程序的CPU和内存占用情况
pm2 show [app-id/app-name] 显示指定应用程序的所有信息
pm2 log 显示应用程序的日志信息
pm2 log [app-id/app-name] 显示指定应用程序的日志信息
pm2 flush 清空所有日志文件
pm2 stop all 停止所有应用程序
pm2 stop [app-id/app-name] 停止指定应用程序
pm2 restart all 重启所有应用程序
pm2 restart [app-id/app-name] 重启指定应用程序
pm2 delete all 关闭并删除所有应用程序
pm2 delete [app-id/app-name] 删除指定的应用程序
pm2 reload all 重启所有应用程序
pm2 reload [app-id/app-name] 重启指定的应用程序
restart 会同时杀死和重启所有相关进程,在短暂时间内服务是不可用的。 reload 的话则是一个个销毁和重启进程,保证至少一个进程可用,做到零停机部署。
但是如果是直接pm2 start server.js未设置多进程并发,restart和reload没什么区别,只有利用-i参数设置并发时,才有区别。
pm2 start server.js -i 5(启动应用程序,5个进程)