商标局网请收下我的膝盖-反爬与反反爬的奇技淫巧
今天打算写最后一篇的反爬与反反爬的文章了,毕竟奇技淫巧很多,但是万变不离其宗,熟练掌握JS/HTML/CSS,了解HTTP协议,这是内功。熟练使用chrome,神箭手开发框架,这是称手的兵器。剩下的也就是唯手熟尔。
后面打算开一个番外系列,不少人私信问我关于cnn识别验证码的问题,所以打算开一个系列跟大家一起看看咱们用机器学习能解决多少验证码识别的问题。感兴趣的朋友欢迎关注我或者专栏:
专栏:数据黑板-知乎专栏
好了,废话不多说,先上之前的文章列表:
爬虫与汽车之家的Css:Content-反爬与反反爬的奇技淫巧
爬虫与CloudFlare邮箱加密(cfemail)-反爬与反反爬的奇技淫巧
一眼望去已经有不少文章了,不过也应该只覆盖了所有套路的一部分吧,今天既然是压轴,我们就来聊一个难的,诡异的,不一样的,眼前一亮的。常规的单独套路显然就很难符合标准,今天咱们要聊的是一个超级组合拳直接让人怀疑人生的反爬套路--商标局(商标检索平台)。
首先呢,我们的文章只是技术探索的目的。商标局的网站反爬据说是一家专业安全企业的产品-瑞数 ,我们不会在这篇文章中教大家完整去破解这套系统。我们一起来通过研究这套系统,看看我们有什么可以借鉴的地方,这套策略到底有什么牛逼的地方。同时提高我们的反爬与反反爬的能力,当然最重要的是提高JS水平。
好了,既然是组合拳,咱们就一个一个拳头来:
第一拳:防调试
咱们依照套路,直接打开网站,右击打开调试面板。Boom!
直接断点,咱们还啥都没做呢,点击继续,Boom!又断点。这还没上战场,就已经被打残了。
首先不得不说专业的就是专业的,这招简直是不战而屈人之兵。很多人走到这,就已经决定去用无头浏览器了(当然无头浏览器的坑也很多,更致命的是灵活性太差)
这里有一个不算完美的解决方案,就是我安利了无数篇文章的chrome snippets,这里可以明显看到,这个手法是内嵌了一个setinterval的函数,每一个间隔时间,就调用一次debugger让浏览器断点,我们只需要清楚掉这个interval即可,大家可以复制一下下面的代码在console中执行,或者直接保存成snippet每次断点后执行再点继续即可。
for (var i = 1; i < 99999; i++)
window.clearInterval(i);
第二拳:JS验证后跳转
闪过第一拳,第二拳迅速袭来,网页本身并不是直接打开的,而是经过了一次JS跳转,跳转到了这样一个网址上:
http://wsjs.saic.gov.cn/txnT01.do?y7bRbP=KaltkM10zh10zh10triDHWegi3_iGKEpBPgY7GGba.A
JS跳转是很多网站验证真实浏览器的方式(比如还有搜狗搜索),当然商标网的这个JS跳转那也真是成精了。由于直接在Chrome中即使勾上preserved log也拿不到具体页面,我们通过postman来提交一个请求看看真实的返回数据:
这代码看着也真实让人精神抖擞啊,关于这类JS的调试,我已经在上篇文章中,有着相对详细介绍,如果还是没有掌握其中奥义的朋友们,可以自行学习,我就不详细讲了。这里特别注意几个细节:
1.这里不仅仅纯粹JS需要执行,还有一个重要的meta标签和一个外部引用的JS文件都需要模拟到Snippets里去,而且必须要对应上,否则函数名就会错乱。
2.实际代码运行过程中,还有两套JS的eval执行,谨记用console.log替换eval的套路。
3.代码中有部分代码调用了eval.call的方法,注意此方法会将context换成全局的context执行,模拟的时候务必弄清环境以免变量错乱。
4.模拟真实浏览器环境的过程中,类似携程的new Image()套路,这套反爬代码中也下了不少毒。比如navigator的hasOwnProperty,大家在模拟环境变量时一定做到真实模拟,比如内置变量尽量使用定义prototype后new的形式,而不要直接定义一个变量:
Navigator.prototype = {"appVersion":"5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"appCodeName":"Mozilla",
"appName":"Netscape",
"language":"zh-CN",
"platform":"Win32",
"productSub":"20030107",
"product":"Gecko",
"mimeTypes":[
{"type":"application/pdf","description":"","enabledPlugin":{"name":"PDF Viewer"}},
{"type":"application/x-shockwave-flash",suffixes:"swf",
"description":"Shockwave Flash","enabledPlugin":{"name":"Shockwave Flash","description":"Shockwave Flash 26.0 r0"}}
],
"userAgent":site.getUserAgent(),
"languages": ["zh-CN", "zh"],
"plugins":[
{"name":"Shockwave Flash","description":"Shockwave Flash 26.0 r0",length:2,filename:"pepflashplayer64_26_0_0_151.dll"}
]
};
navigator = new Navigator();
5.代码中有大量dom操作,但是我们模拟环境是不可能模拟所有dom操作的(真全部模拟出来就是个无头浏览器了,这工作量不可想象)所以建议先写一个空dom函数的,看看具体的调用形式,比如document.getElementById之类,打印一下看看如何调用,然后在模拟具体场景下的使用,比如获取meta标签的content。
6.调试过程中会发现正常运行可以,但是一旦调试则乱码,此处又是工程师下的剧毒,通过比对执行时间差来判断是否是有人在debug,此处解决方案可执行如下代码替换Date的默认执行来骗过JS:
Date.prototype._getTime = Date.prototype.getTime;
Date.prototype.getTime = function(){
if(!Date._lastTime){
var time = this._getTime();
Date._lastTime = time;
}
Date._lastTime = Date._lastTime+100;
return Date._lastTime;
}
7.耐心!耐心!耐心!由于此处套路之深让携程工程师都看不到底,所以调试的耐心非常重要。
第三拳:Cookie的定时刷新
其实如果我没猜错,第二拳打完,估计地上应该已经全是尸体了,不过记得当年游戏里的一句话:十人九不回,强者尸上行(又暴露年龄了)。
咱们继续前行,看看这第三拳:Cookie定时刷新。此处套路已经要突破天际了,宇宙边缘才是这套路的终点。此处JS通过将点击行为,停留时间等等以加密形式存入Cookie中,并定时刷新,几乎做到让想要模拟的人走投无路,不过值得庆幸的是如果顺利挺过第二拳,这第三拳只需要加上一个对浏览器事件机制的模拟即可顺利过关。
第四拳:浏览器内置函数Hook
估计到了第四拳,不少内功差的朋友已经不知道我在说什么了。如果还能看懂的话,咱们继续:
这套反爬最让我们叹为观止的,就是这第四拳,真的是非常的优雅。又把安全做到了几乎是前段的极致。系统通过对XMLHttpRequest的Hook,将所有的Ajax请求都添加上了get参数,就算普通调试,甚至都完全看不出来get参数是再什么地方加的。不过解决方案当然也很简单,就是对XMLHttpRequest先做一次Hook,在执行代码。
第五拳:表单提交代替链接
这个套路虽然不深,但确实也给调试带来了深深的影响,然而还好走到这的朋友估计已经对这套代码烂熟于心,只需要跳过表单提交,通过其他方案直接获取Url和get参数,同时通过Hook函数document.write就可以完美模拟出表单提交的效果。
话说后面两拳我就不展开了说了,躲过这几拳之后,剩下的就非常简单了,最后的页面连一个ajax都没有,直接xpath就可以全部解析出来。如果大家想把JS提升5678个档次,可以来尝试下商标局网的爬虫。这个爬虫写出来之后,你会发现携程爬虫真的也只算得上小学水平吧。
--------------------------------------------------最后说两句----------------------------------------------------------
咱们反爬和反反爬系列就此告一段落了,还是开头说了,套路很多,一一列举没啥意思,大家掌握思想精髓,做到举一反三,才能真正通往大神之路。
欢迎大家继续关注我和我的专栏,下面开启一个新系列《验证码终结者》,跟大家一起通过新武器-人工智能来会会这个爬虫的老对手(参看爬虫中的验证码识别-反爬与反反爬的奇技淫巧)。
更多回答关注:吴桐-神箭手CEO
更多文章关注:数据黑板-知乎专栏