爬虫的过程
- 破解加速乐最新反爬虫机制获取cookie
- 传入cookie获取 gt 和 challenge 参数 (破解验证码必须的参数)
- 破解验证码
- 带上cookie,提交参数跳转下一层
- 抓取数据,这就非常简单了
破解加速乐获取cookie
网站更新前是不需要这个步骤的,这次重构代码的时间主要就花在这了。一开始我用 get 方式直接访问 http://www.gsxt.gov.cn/SearchItemCaptcha ,获取 gt 和 challenge 参数 ,但是却返回错误521,于是我发现不仅仅是这个接口,但是发现根本连首页都进不去,返回错误页面403 forbidden,而且细心发现返回的并不是正常的乱码而是一串js代码。
< script >var x = "__jsl_clearance@1515751840@w7ZgszEX@addEventListener@18@Fri@reverse@i@else@l@_phantom@if@captcha@3D@false@Jan@dc@catch@935@var@chips@Expires@Array@cookie@charAt@10@function@@D@__phantomas@vHA@while@GMT@4@attachEvent@setTimeout@cd@for@href@Path@challenge@replace@try@1500@6@length@86w@return@onreadystatechange@12@window@TAGGl@location@40@3@@B@document@0@join@DOMContentLoaded@11@e@2".replace(/@*$/, "").split("@"),y = "k a=r(){w(P.b||P.u){};k B,h='1=2.j|10|';B=n(+[[(+!+[])]+[([-~-~~~![]]+~~{}>>-~-~~~![])]]);k l=['Q',(!{}+[[], -~{}][~~![]]).p(-~[(-~{}<<-~{})]),'3',[{}+[[], -[com.cn.chaomeng.utils.GsxtUtils] - 初始cookie密文:<script>var x="__jsl_clearance@1515751840@w7ZgszEX@addEventListener@18@Fri@reverse@i@else@l@_phantom@if@captcha@3D@false@Jan@dc@catch@935@var@chips@Expires@Array@cookie@charAt@10@function@@D@__phantomas@vHA@while@GMT@4@attachEvent@setTimeout@cd@for@href@Path@challenge@replace@try@1500@6@length@86w@return@onreadystatechange@12@window@TAGGl@location@40@3@@B@document@0@join@DOMContentLoaded@11@e@2 ".replace(/@*$/,"").split("@"),y="k a = r() { w(P.b || P.u) {}; k B, h = '1=2.j|10|'; B = n( + [[( + !+[])] + [([ - ~ - ~~~ ! []] + ~~ {} >> -~ - ~~~ ! [])]]); k l = ['Q', (!{} + [[], -~ {}][~~ ! []]).p( - ~ [( - ~ {} << -~ {})]), '3', [{} + [[], -~ {}][~~ ! []]][10].p(T - ~~~ ! [] - ~~~ ! [] + T), '%', [{} + [[], -~ {}][~~ ! []]][10].p(([ - ~ - ~~~ ! []] + ~~ {} >> -~ - ~~~ ! [])), 'V', ( + {} + [[], -~ {}][~~ ! []]).p(15), 'L', (15 + [] + [[]][( + [])]), 't', ([][~~ {}] + [] + []).p(y), 'v', ( - ~ [] / ~~ ! [] + [[], -~ {}][~~ ! []]).p(J), '%e']; C(k 8 = 10; 8 < l.K; 8++) { B.7()[8] = l[8] }; B = B.11(''); h += B; A('R.D=R.D.G(/[\\?|&]d-F/,\\'\\')', I); W.o = (h + ';m=6, O-g-5 13:q:S x;E=/;');};c((r() { H { M !! P.4; } i(14) { M f; }})()) { W.4('12', a, f);}9 { W.z('N', a);}",z=0,f=function(x,y){var a=0,b=0,c=0;x=x.split("");y=y||99;while((a=x.shift())&&(b=a.charCodeAt(0)-77.5))c=(Math.abs(b)<13?(b+48.5):parseInt(a,36))+y*c;return c},g=y.match(/\b\w+\b/g).sort(function(x,y){return f(x)-f(y)}).pop();while(f(g,++z)-x.length){};eval(y.replace(/\b\w+\b/g, function(y){return x[f(y,z)-1]}));</script> ~{}][~~![]]][10].p(T-~~~![]-~~~![]+T),'%',[{}+[[], -~{}][~~![]]][10].p(([-~-~~~![]]+~~{}>>-~-~~~![])),'V',(+{}+[[], -~{}][~~![]]).p(15),'L',(15+[]+[[]][(+[])]),'t',([][~~{}]+[]+[]).p(y),'v',(-~[]/~~![]+[[], -~{}][~~![]]).p(J),'%e'];C(k 8=10;8<l.K;8++){B.7()[8]=l[8]};B=B.11('');h+=B;A('R.D=R.D.G(/[\\?|&]d-F/,\\'\\')',I);W.o=(h+';m=6, O-g-5 13:q:S x;E=/;');};c((r(){H{M !!P.4;}i(14){M f;}})()){W.4('12',a,f);}9{W.z('N',a);}",z = 0,f = function(x, y) { var a = 0, b = 0, c = 0; x = x.split(""); y = y || 99; while ((a = x.shift()) && (b = a.charCodeAt(0) - 77.5)) c = (Math.abs(b) < 13 ? (b + 48.5) : parseInt(a, 36)) + y * c; return c},g = y.match(/\b\w+\b/g).sort(function(x, y) { return f(x) - f(y)}).pop();while (f(g, ++z) - x.length) {};eval(y.replace(/\b\w+\b/g,function(y) { return x[f(y, z) - 1]})); < /script> /
到这里取cookie只传递了一个__jsluid
的COOKIES值。
__jsluid=8d61794e23c2bff4a5c997b272729fba;
Google 了一下,发现这是 加速乐的一个爬虫防护机制)。浏览器第二次请求的时候会带上 __jsluid
cookies和JS解密计算出来的一个叫做__jsl_clearance
的cookies值,只有这两个cookies验证匹配才认为是合法的访问身份。
这个确实花费了不少时间,知道了问题所在就简单多了,仔细分析上面的js代码就会发现我们要的东西就是这个方法:
eval(y.replace(/\b\w+\b/g,function(y) { return x[f(y, z) - 1]})
接下来就简单,用的是JAVA分析的 ,JAVA的js引擎还是挺好用的。稍微改造下js代码
resHtml = "function getClearance(){" + resHtml+"};"; resHtml = resHtml.replace("</script>", ""); resHtml = resHtml.replace("eval", "return"); resHtml = resHtml.replace("<script>", "");
改造后的代码js:
function getClearance() { var x = "__jsl_clearance@1515751840@w7ZgszEX@addEventListener@18@Fri@reverse@i@else@l@_phantom@if@captcha@3D@false@Jan@dc@catch@935@var@chips@Expires@Array@cookie@charAt@10@function@@D@__phantomas@vHA@while@GMT@4@attachEvent@setTimeout@cd@for@href@Path@challenge@replace@try@1500@6@length@86w@return@onreadystatechange@12@window@TAGGl@location@40@3@@B@document@0@join@DOMContentLoaded@11@e@2".replace(/@*$/, "").split("@"), y = "k a=r(){w(P.b||P.u){};k B,h='1=2.j|10|';B=n(+[[(+!+[])]+[([-~-~~~![]]+~~{}>>-~-~~~![])]]);k l=['Q',(!{}+[[], -~{}][~~![]]).p(-~[(-~{}<<-~{})]),'3',[{}+[[], -~{}][~~![]]][10].p(T-~~~![]-~~~![]+T),'%',[{}+[[], -~{}][~~![]]][10].p(([-~-~~~![]]+~~{}>>-~-~~~![])),'V',(+{}+[[], -~{}][~~![]]).p(15),'L',(15+[]+[[]][(+[])]),'t',([][~~{}]+[]+[]).p(y),'v',(-~[]/~~![]+[[], -~{}][~~![]]).p(J),'%e'];C(k 8=10;8<l.K;8++){B.7()[8]=l[8]};B=B.11('');h+=B;A('R.D=R.D.G(/[\\?|&]d-F/,\\'\\')',I);W.o=(h+';m=6, O-g-5 13:q:S x;E=/;');};c((r(){H{M !!P.4;}i(14){M f;}})()){W.4('12',a,f);}9{W.z('N',a);}", z = 0, f = function(x, y) { var a = 0, b = 0, c = 0; x = x.split(""); y = y || 99; while ((a = x.shift()) && (b = a.charCodeAt(0) - 77.5)) c = (Math.abs(b) < 13 ? (b + 48.5) : parseInt(a, 36)) + y * c; return c }, g = y.match(/\b\w+\b/g).sort(function(x, y) { return f(x) - f(y) }).pop(); while (f(g, ++z) - x.length) {}; return (y.replace(/\b\w+\b/g, function(y) { return x[f(y, z) - 1] }));};
接下来用js引擎执行这段代码。
ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("js"); engine.eval(resHtml); Invocable invocable = (Invocable) engine; String resJs = (String) invocable.invokeFunction("getClearance");
这样就可以得到这段js原来的样子了,并把没用的东西去掉,得到下面的js,我们会发现dc就是我们需要的东西,具体没用的东西怎么去掉就不贴上来了,只要是有window的代码去掉,会报错;dc就是我们要的东西,模仿上个步骤加上 return dc;
就可以了;
var l = function() { var cd, dc = '__jsl_clearance=1515751840.935|0|'; cd = Array( + [[( + !+[])] + [([ - ~ - ~~~ ! []] + ~~ {} >> -~ - ~~~ ! [])]]); var chips = ['TAGGl', (!{} + [[], -~ {}][~~ ! []]).charAt( - ~ [( - ~ {} << -~ {})]), 'w7ZgszEX', [{} + [[], -~ {}][~~ ! []]][0].charAt(3 - ~~~ ! [] - ~~~ ! [] + 3), '%', [{} + [[], -~ {}][~~ ! []]][0].charAt(([ - ~ - ~~~ ! []] + ~~ {} >> -~ - ~~~ ! [])), 'B', ( + {} + [[], -~ {}][~~ ! []]).charAt(2), '86w', (2 + [] + [[]][( + [])]), 'D', ([][~~ {}] + [] + []).charAt(4), 'vHA', ( - ~ [] / ~~ ! [] + [[], -~ {}][~~ ! []]).charAt(6), '%3D']; for (var i = 0; i < chips.length; i++) { cd.reverse()[i] = chips[i] }; cd = cd.join(''); dc += cd; return dc;};
直接执行就行了:
engine.eval(resJs); String learance= (String) invocable.invokeFunction("l");
执行完就是我们要的东西啦:
__jsl_clearance=1515751840.935|0|TAGGltw7ZgszEXf%2BN86wcDOvHAs%3D
将两段cookie拼接起来就是最终的cookie了:
__jsluid=8d61794e23c2bff4a5c997b272729fba; __jsl_clearance=1515751840.935|0|TAGGltw7ZgszEXf%2BN86wcDOvHAs%3D;
接下来带上cookie访问刚刚的接口(http://www.gsxt.gov.cn/SearchItemCaptcha
),就返回200了,成功
{"challenge":"2f5ce96fd594370c49125a3264166df5","status":"ok","validate":"5be4f4ce721a7c7ad2469925800836a6"}
接下来就简单了。
注意
- 首页返回的JS脚本里面有防止 PhantomJS 的机制:
while (window._phantom || window.__phantomas) {};
当发现是_phantom或者__phantomas后就直接进入死循环了。。
- 最新发现,取上面步骤得到cookie访问的后续的页面会报302
解决办法:用得到的cookie再次访问,并从response中取set-cookie,可以得到:
JSESSIONID=AFDB40E58D5E6EC434E0584390629C03-n1:-1; Path=/; HttpOnlytlb_cookie=S172.16.12.67; path=/
再拼接起来才是最终的cookie:
__jsluid=8d61794e23c2bff4a5c997b272729fba; __jsl_clearance=1515751840.935|0|TAGGltw7ZgszEXf%2BN86wcDOvHAs%3D;HttpOnly;secure;JSESSIONID=AFDB40E58D5E6EC434E0584390629C03-n1:-1; Path=/; HttpOnlytlb_cookie=S172.16.12.67; path=/
建议将cookie缓存,2小时更新一次就可以了
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。