Python爬取js加密后的图片
在使用Python想爬取某网站的图片,使用Python的requests模块的get()后,获取到了html文件。结果发现图片的src是动态加载,而且还加密了。
在img标签下发现一个className=lazy:
在script标签下发现:
查阅资料后发现这是一个lazyload插件的启动代码。
在f12检查元素的资源下找到lazyload.js,可以发现:
在$.ajax()中可以看到参数url是密文的地址,success的匿名函数的参数res是访问url后的返回结果,可以看到该方法中调用了一个desDecrypt(res),解密密文的函数,返回结果是base64加密后的一段字符串。
图片的密文被放在一个.txt的文件中,利用抓包工具可发现一个encrypt.min.js的js文件,格式化后如下
eval(function(p, a, c, k, e, r) { e = function(c) { return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) } ; if (!''.replace(/^/, String)) { while (c--) r[e(c)] = k[c] || e(c); k = [function(e) { return r[e] } ]; e = function() { return '\\w+' } ; c = 1 } ;while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c]); return p }('1 e="B";1 8="G";f N(a){1 5=0.2.3.4(8);1 7=0.2.3.4(e);9 b=0.u.v(a,7,{l:5,6:0.6.n,o:0.p.q,r:0.k.m});1 x=b.h();d x}f F(a){1 5=0.2.3.4(8);1 7=0.2.3.4(e);9 b=0.u.y(a,7,{l:5,6:0.6.n,o:0.p.q,r:0.k.m});d 0.2.3.J(b)}f C(a){1 5=0.2.3.4(8);1 7=0.2.3.4(e);9 b=0.u.v(a,7,{l:5,6:0.6.n,o:0.p.q,r:0.k.m});d b.A.h(0.2.z)}f D(a){a=a.E(/\\s*/g,"");1 5=0.2.3.4(8);9 b=0.2.3.4(e);9 c=0.H.y({A:0.2.z.4(a)},b,{l:5,6:0.6.n,o:0.p.q,r:0.k.m});d c.h(0.2.3)}f I(a,b){1 j=(K L()).M();1 t=0.O("i"+b+"P"+j+"Q").h();1 w=a+"?j="+j+"&t="+t;d w}', 53, 53, 'CryptoJS|let|enc|Utf8|parse|tmpiv|mode|key|base_lv|var||||return|asc_key|function||toString||ts|format|iv|OpenSSL|CBC|padding|pad|Pkcs7|formatter||token|AES|encrypt|result_url|result|decrypt|Base64|ciphertext|jeH3O1VX|desEncrypt|desDecrypt|replace|aesDecrypt|nHnsU4cX|DES|desVideoUrl|stringify|new|Date|getTime|aesEncrypt|MD5|am|IronMan'.split('|'), 0, {}))
显然上面的js代码是加密过后的,百度搜索js在线解密,可以恢复原来的js代码,发现其中有个desDecypt(a)的方法,也就是上面提到的方法,该方法用于解密密文,该js插件依赖于crypto-js.js文件。
let asc_key = "********"; //8位秘钥 let base_lv = "********"; //8位秘钥偏移量 function desDecrypt(a) { a = a.replace(/\s*/g, ""); let tmpiv = CryptoJS.enc.Utf8.parse(base_lv); var b = CryptoJS.enc.Utf8.parse(asc_key); var c = CryptoJS.DES.decrypt({ ciphertext: CryptoJS.enc.Base64.parse(a) }, b, { iv: tmpiv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, formatter: CryptoJS.format.OpenSSL }); return c.toString(CryptoJS.enc.Utf8) }
那么js插件加密的密文怎么解码呢?查阅资料发现在python中有一个可以调用js文件的模块PyexecJs
在cmd使用 pip install PyexecJs 安装模块
import execjs import base64 #实例化一个node对象 node = execjs.get() #要调用的js文件 file = 'mm.js' #编译js文件 cjs = node.compile(open(file, encoding='utf-8').read()) #js中要执行的函数 其中res就是密文 js = 'desDecrypt("{0}")'.format(res)' #执行js代码 dec_data = cjs.eval(js) #将解密后的明文执行base64解码,并生成图片 b64_data = dec_data.split(';base64,')[1] data = base64.b64decode(b64_data) with open(filename,'wb') as file: file.write(data)
事先把desDecrypt(a)函数和crypto-js.js的核心代码写入mm.js,方便execjs模块的调用。
大体思路就如上所述~~