没错,在拔了一颗智齿,害死了三株刚开花的向日葵,停更10天之后,我还活着。
今天还是讲动态爬虫的漏抓案例。(干脆跳槽专门写爬虫算了)
一句话总结: 为了防止阻塞,除了 alert/prompt/confirm,你还得 Hook 更多的函数。
BadCase:
window.showModalDialog 是早期浏览器使用比较频繁的函数,用来弹出一个新页面,并且是阻塞执行的(所以造成爬虫超时被强行杀进程)。后来被 window.open 函数替代。替换的原因有:
showModalDialog 没有导航栏,无法进行后退、前进、收藏等操作
showModalDialog debug非常复杂(只能用alert调试法 2333)
名字又长又难记(迷之猜测)
下图为正常打开的页面与 showModalDialog 打开的页面比较:
目前Chrome最新版已经不支持这个函数了,但Firefox、Safari、IE仍然支持。毫无意外的 PhantomJS 也支持。解决方案很简单,直接 Hook 函数就可以了:
这样的话,加上最开始就被 Hook 的 alert/prompt/confirm,现在已经 Hook 了四个可能会引起阻塞的函数了,是不是还有其他隐藏的存在呢?
写个脚本来检查下:
var page = require('webpage').create();
page.onConsoleMessage = function(msg) {
console.log('> ' + msg );
return true;
};
page.open("http://127.0.0.1:8082", "GET", "", function (status) {
console.log(status);
page.evaluateAsync(function(){
for(var i in window){
try {
if (typeof eval("window." + i) != "function") {
continue
}
}catch (e){
}
// if(i in {"showModalDialog": "1"}){
// continue
// }
try{
console.log(i)
eval("(function(){" + i + "();})()");
}
catch (e){
// console.log(e)
}
}
}, 10)
});
用 PhantomJS 加载任意页面,然后遍历 window 对象。首先出现阻塞卡顿的函数是 showModalDialog,再次运行脚本,跳过 showModalDialog 函数,然后....
顺畅的运行完成,说好的 alert/prompt/confirm 函数导致的阻塞呢?
复制脚本到浏览器中运行,倒是成功复现了 alert/prompt/confirm/print 导致的阻塞:
分析原因,应该是PhantomJS在封装onAlert、onPrompt、onConfirm接口的时候就对这几个可能产生阻塞的函数做了处理。
同样的原理,可以套用在其他的动态解析器上。举个栗子,在Chrome Headless里需要 Hook 哪些接口,你现在知道了吗?
参考资料: