最近开始研究网页参数的JS加密,但是大型网站的JS文件过于繁杂,不适合新手上路,于是乎找了几个简单的网页来学习学习。
首先要和大家聊的是监听事件型爬虫(推荐FireFox浏览器)。简单介绍一下JS事件监听:
JavaScript之事件概念和监听事件
1、事件的概念:
JavaScript使我们有能力创建动态页面,网页中的每一个元素都可以产生某些触发JavaScript函数的事件。我们可以认为事件是可以被JavaScript侦测到的一种行为。
2、事件流:
事件流主要分为冒泡型事件和捕获型事件。IE浏览器目前只支持冒泡型事件,而支持标准DOM的浏览器比如火狐、Chrome等两者都支持。
3、使用返回值改变HTML元素的默认行为:
HTML元素大都包含了自己的默认行为,例如:超链接、提交按钮等。我们可以通过在绑定事件中加上"return false"来阻止它的默认行为。
4、通用性的事件监听方法:
(1)绑定HTML元素属性:
<input type="button" value="clickMe" onclick="check(this)">
(2)绑定DOM对象属性:document.getElementById("xxx").onclick=test;
(https://www.cnblogs.com/dorra/p/7349747.html)
目标网站:http://ac.scmor.com/
第一次写js类的爬虫,断点调试过程写详细些。
鼠标点击现在访问时,会前往另一个网页。用火狐浏览器打开,元素定位到“现在访问”,可以看到下图:网页链接没有出现在源代码中,相反在<a>标签末尾有一个event;这代表当点击“现在访问”这个事件发生时,会被监听并做出相应的反应。
点击“event”,可以看到一个函数onclick(event),在这个函数里,还有一个visit()函数;这表示当点击“现在访问”发生时,会引发onclick(event)的发生,从而引发visit()函数。
全局搜索(ctrl+shift+f)搜索visit()可以看到下图有一个function visit(url);这就是我们要找的函数啦。(这一步开始使用谷歌浏览器)
来分析一下这个函数:它的变量是url,也就是上图中visit('QSQ7XggEHBUhXDxYLwIFHwh4ZRkwXFI0Pw4jGj5ZXlI=')的QSQ7XggEHBUhXDxYLwIFHwh4ZRkwXFI0Pw4jGj5ZXlI=
给它打断点:
点击“现在访问”:此时url=QSQ7XggEHBUhXDxYLwIFHwh4ZRkwXFI0Pw4jGj5ZXlI=
不断点击(step over next function call),当走完strdecode()函数后,url更新为要访问的页面。下一步就是找到这个函数并分析。
找到的strdecode()函数如下:此时
string='QSQ7XggEHBUhXDxYLwIFHwh4ZRkwXFI0Pw4jGj5ZXlI='
再经过base64decode以后变成了一段乱码:
重新打一次断点:经过base64decode(code)后,返回需要的Url;至此所有的断点调试就完成了。
这是base64decode函数的代码,里面有一个base64DecodeChars的变量,在函数里是没有定义的,因此后期自己加上。
function base64decode(str) {
var c1, c2, c3, c4;
var i, len, out;
len = str.length;
i = 0;
out = "";
while (i < len) {
do {
c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff]
} while (i < len && c1 == -1);
if (c1 == -1) break;
do {
c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff]
} while (i < len && c2 == -1);
if (c2 == -1) break;
out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
do {
c3 = str.charCodeAt(i++) & 0xff;
if (c3 == 61) return out;
c3 = base64DecodeChars[c3]
} while (i < len && c3 == -1);
if (c3 == -1) break;
out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
do {
c4 = str.charCodeAt(i++) & 0xff;
if (c4 == 61) return out;
c4 = base64DecodeChars[c4]
} while (i < len && c4 == -1);
if (c4 == -1) break;
out += String.fromCharCode(((c3 & 0x03) << 6) | c4)
}
return out
}
还有一个问题,最开始visit()的自变量在哪里呢?网页源代码中都有的噢。一共16个镜像对应16个变量。
找到了所有需要的js代码,然后用python还原???不用自己找虐,python提供一个execjs的库,可以直接调用js文件。一共15行代码就可以获得所需的网址啦。
if __name__ == '__main__':
url='http://ac.scmor.com/'
headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
html=requests.get(url,headers=headers).text
soup=BeautifulSoup(html,'lxml')
infs=soup.find('head').find_all('script',type='text/javascript')
infs=re.findall(r'autourl(.*?);',str(infs))
node = execjs.get()
file = '谷歌学术镜像.js'
ctx = node.compile(open(file, encoding='utf-8').read())
for inf in infs:
data=inf.split('=',1)[1][2:-1]
js='strdecode("{}") '.format(data)
print(ctx.eval(js))
最后结果如下:
代码以及Js文件上传到GitHub(https://github.com/zuobangbang/javascript-decode/tree/master/google);觉得不错就star/fork下;有兴趣可以自己做一遍。