js混淆反爬破解學習--爬取OpenLaw


一、前言

  前幾天看到了瓜子二手車的廣告,突發奇想想要拿這個網站試試手,可每次都無法成功獲取到頁面。試了很多次都沒有結果之后便去網上搜索方案,才知道原來還有js反爬這種東西(看來我以前選網站的運氣都太好了。。。),又發現了一篇js混淆反爬破解的文章,就拿來模仿學習一下。

學習的文章:JS混淆openlaw反爬破解實踐

文章作者:謝俊傑

二、抓包分析

 1、使用火狐自帶工具進行抓包,發現一次請求加載了兩次html頁面,如下;

2、分別查看一下兩個html  

  首先來看看第一個html;

  

  根據圖片我們可以發現,這是一個簡單的html頁面里包含着一大串JavaScript代碼,<body>里可能是一個招聘郵箱(有興趣的可以聯系試一下。。。國內好像很多網站喜歡在這種地方放招聘信息,我發現好幾個了。。。)。

  接下來我們再來看看第二個html信息;

  可以看出第二個頁面才是我們想要看到的html頁面;所以可以猜測,網頁經過第一個頁面的跳轉才會到達我們想要的頁面,接下來我們就要弄清楚第一個頁面究竟干了些什么。

三、分析第一個頁面js代碼

1、我們將第一個頁面代碼截取下來,並且格式化一下(我可以很負責任的告訴你們,我是真的格式化了的);

 1 var O01 = 'KkSKpcCfngCdpxGcz5yJvZmbpxHbyVHfyVmcyVmZlJHfjJ3c0V2Z8VGdpJ3d8xnQzwXMwEzX8ZWZyxXawFWeyVWdxpGfkxWaoNEZuVGcwFGflBXYjNXZuVHfENDfl1WYOdWYUlnQzRnbl1WZsVEdldGfr9GfwRHdox3NywHduVWblxWRlRXYlJ3Y8RHcpJ3YzN0M8dXYs5WZw9GMywHTSVFfyFmdFNDf3FGbuVGcvdjM8RWYlhGf05WSlNnchBHflBXYjNXZfxHNzwnchZHfJ90T8Rnbl1Wdj9GZ8hzN8JjN8ZzM8ljM8VGZvNkchh2Qt9mcmxXNzwHduVmbvBXbvNUSSVVZk92YuVGfDNDfFNDf0BXayN2c8Nmczx3Zulmc0NFf0lGbwNHfn5WayR3UvRHfsFmdlxHc4V0ZlJFf3Vmb8VGbph2d8V2YhxGclJHfmlGfu9Wa0Nmb1ZGfuJXd0Vmc8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHfnwCMzEDLyYDLnkSK9tHLwwSKnwFfnwFKwFjLnwFUxwXUxwnUxwHVxwnTxwXTxwXSxwnSxw3SxwHTxw3UxwHWxwHNyw3MywXNywnMywnWxwnVxwXMywXVxw3VxwXWxw3TxwHcxw3axwHaxwXaxwnaxw3Zxw3bxwXbxwHbxwnbxw3cxwXdxwncxwHdxw3Rxwndxw3QxwHRxwXRxwHMywnRxwHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8xHf8x3JcxiQxwSQxwyJclSKpcCXcxFfnwFXchyUucCXcxVMxwnMxw3MxwHNxwHMxwnNxwnV8dFfYxXW8VTM8lTM8RWM8ZWM8VWM8NWM8FWM8JWM8dTM8hTM8pFfUxnR8dEfIxXS8VFfFxHR8pHfBxnQ8NEfnwFXcxSeskHLnwFXctTKpYDKxhCcuEzOpIDKv5yN70FMblyJcxFXcxFXc12JcxFXcxFXchibuETP3AyM7kycuEDK1syJcxFXcxFXc1jdmcCXcxFXcxFXrkyduEDK1syJcxFXcxFXc1TdmcCXcxFXcxFXrcCXcxFXcxFXs1Dd/8CeuI3LvojanwFXcxFXcxVPh5iM7kyJcxFXcxFXchzJcxFXcxFXchyYuETPyAyM7cCXcxFXcxFXiVCOvkTJkVyalUWJ0USalQTJoViZlcWJnwFXcxFXcxVP2AyMnwFXchSfwBiT91XKdN2WrxSKnwFXcd2JcxFXscCXcxlYcxFXcxFXcx1JcxFXrkSYo0kLjtyJcxFXixFXcxFXcxFXnwFXchCTgsEKP5Cc9A3ep01YbtGKQtXKt0yYoI1epQGLlxyasMGLhxCcoEFKKdCXo0HcgcWM91XKdN2WrxSKnw1ZnwFLnwlYcxFXcdCXrkyYoU2KnwlYcxFXcdCXo0WMgwWMooWMuAXPwtXKdN2WrhSaxsXKt0yYosWM70XM9M2O9dCXrcHXcxFXnw1ZxsXKogWM9U2Od1XXltFZgcWM7lSZogWMb1za9lyYoUGf811YbtWPdlyYoU2WktXKt0yYosWM7lSKxFDLv41LooWMucCXnwVIokWM70XKpoXMo8WMuMmOpkXMrMGK4FjLxFzP3FjPpEWJj1zYogyKpkSKh9yYogUMoUmOnw1Jc9TY8MGKnFzepMGKoFTPltXKkxSZssGLjxSYsAHKoFDKuFzJo0Hcg4mc1RXZy1Xfp01YbtGLpcyZnwyJixFXnsSKjhSZrciYcx1JoAHeFdWZSBydl5GKlNWYsBXZy5Cc9A3ep01YbtGKml2ep0SLjhSZslGa3tTfpkiNzgyZulmc0N1b05yY6kSOysyYoUGZvNkchh2Qt9mcm5yZulmc0N1P1MjPpEWJj1zYogyKpkSKh9yYoQnbJV2cyFGcoUmOncyPhxzYo4mc1RXZytXKjhibvlGdj5Wdm1TZ7lCZsUGLrxyYsEGLwhibvlGdj5WdmhCbhZXZ';
 2 function lOO(data) {
 3     var OOOlOI = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
 4     var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, enc = '';
 5     do {
 6         h1 = OOOlOI.indexOf(data.charAt(i++));
 7         h2 = OOOlOI.indexOf(data.charAt(i++));
 8         h3 = OOOlOI.indexOf(data.charAt(i++));
 9         h4 = OOOlOI.indexOf(data.charAt(i++));
10         bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
11         o1 = bits >> 16 & 0xff;
12         o2 = bits >> 8 & 0xff;
13         o3 = bits & 0xff;
14         if (h3 == 64) {
15             enc += String.fromCharCode(o1)
16         } else if (h4 == 64) {
17             enc += String.fromCharCode(o1, o2)
18         } else {
19             enc += String.fromCharCode(o1, o2, o3)
20         }
21     } while (i < data.length);return enc
22 }
23 function OOO(string) {
24     var ret = ''
25       , i = 0;
26     for (i = string.length - 1; i >= 0; i--) {
27         ret += string.charAt(i);
28     }
29     return ret;
30 }
31 eval(lOO(OOO(O01)));
32 window.n = "j_token";
33 eval(function(p, a, c, k, e, d) {
34     e = function(c) {
35         return (c < a ? "" : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
36     }
37     ;
38     if (!''.replace(/^/, String)) {
39         while (c--)
40             d[e(c)] = k[c] || e(c);
41         k = [function(e) {
42             return d[e]
43         }
44         ];
45         e = function() {
46             return '\\w+'
47         }
48         ;
49         c = 1;
50     }
51     ;while (c--)
52         if (k[c])
53             p = p.replace(new RegExp('\\b' + e(c) + '\\b','g'), k[c]);
54     return p;
55 }('1 2$=[\'\\9\\5\\6\\4\\3\\7\\8\'];1 a=2$[0];', 11, 11, '|var|_|x6c|x6e|x70|x65|x61|x77|x6f|'.split('|'), 0, {}));
56 window.v = "_fa16f708d6903a1c4b46a732b68c4c6a";
57 $ = ~[];
58 $ = {
59     ___: ++$,
60     $$$$: (![] + "")[$],
61     __$: ++$,
62     $_$_: (![] + "")[$],
63     _$_: ++$,
64     $_$$: ({} + "")[$],
65     $$_$: ($[$] + "")[$],
66     _$$: ++$,
67     $$$_: (!"" + "")[$],
68     $__: ++$,
69     $_$: ++$,
70     $$__: ({} + "")[$],
71     $$_: ++$,
72     $$$: ++$,
73     $___: ++$,
74     $__$: ++$
75 };
76 $.$_ = ($.$_ = $ + "")[$.$_$] + ($._$ = $.$_[$.__$]) + ($.$$ = ($.$ + "")[$.__$]) + ((!$) + "")[$._$$] + ($.__ = $.$_[$.$$_]) + ($.$ = (!"" + "")[$.__$]) + ($._ = (!"" + "")[$._$_]) + $.$_[$.$_$] + $.__ + $._$ + $.$;
77 $.$$ = $.$ + (!"" + "")[$._$$] + $.__ + $._ + $.$ + $.$$;
78 $.$ = ($.___)[$.$_][$.$_];
79 $.$($.$($.$$ + "\"" + $.$$$$ + $._ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.__ + "\\" + $.__$ + $.$_$ + $.__$ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.$__ + $.___ + "\\" + $.__$ + $.$$_ + $.___ + "(\\" + $.__$ + $.$$_ + $._$$ + ")\\" + $.$__ + $.___ + "{\\" + $.__$ + $.$$_ + $._$_ + $.$$$_ + $.__ + $._ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.$__ + $.___ + "\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $._$_ + ",\\" + $.$__ + $.___ + $.$__ + ")." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "('\\" + $.__$ + $.$_$ + $.$$_ + "')." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "(\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $.___ + ",\\" + $.$__ + $.___ + $.__$ + "))." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "('\\" + $.__$ + $.$$_ + $.___ + "')." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "(\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $.$__ + ",\\" + $.$__ + $.___ + $.$___ + "))." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "('" + $.$$$_ + "')." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "(\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $.__$ + ",\\" + $.$__ + $.___ + $._$_ + "))." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "(\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $.__$ + $.$$_ + "))." + $.$$__ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.$_$_ + $.__ + "(\\" + $.__$ + $.$$_ + $._$$ + ".\\" + $.__$ + $.$$_ + $._$$ + $._ + $.$_$$ + "\\" + $.__$ + $.$$_ + $._$$ + $.__ + "\\" + $.__$ + $.$$_ + $._$_ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + "\\" + $.__$ + $.$__ + $.$$$ + "(" + $.$___ + ",\\" + $.$__ + $.___ + $.__$ + $.$$_ + "));};\\" + $.$__ + $.___ + "\\" + $.__$ + $._$_ + "+" + $.$$$$ + $._ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$__ + $.__ + "\\" + $.__$ + $.$_$ + $.__$ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + "(){" + $.$$_$ + $._$ + $.$$__ + $._ + "\\" + $.__$ + $.$_$ + $.$_$ + $.$$$_ + "\\" + $.__$ + $.$_$ + $.$$_ + $.__ + "." + $.$$__ + $._$ + $._$ + "\\" + $.__$ + $.$_$ + $._$$ + "\\" + $.__$ + $.$_$ + $.__$ + $.$$$_ + "\\" + $.$__ + $.___ + "=\\" + $.$__ + $.___ + "\\\"\\" + $.__$ + $.$_$ + $._$_ + "\\\"\\" + $.$__ + $.___ + "+\\" + $.$__ + $.___ + "\\\"_\\\"\\" + $.$__ + $.___ + "+\\" + $.$__ + $.___ + "\\\"" + $.__ + $._$ + "\\" + $.__$ + $.$_$ + $._$$ + $.$$$_ + "\\" + $.__$ + $.$_$ + $.$$_ + "=\\\"\\" + $.$__ + $.___ + "+\\" + $.$__ + $.___ + "\\" + $.__$ + $.$$_ + $.___ + "(\\" + $.__$ + $.$$_ + $.$$$ + "\\" + $.__$ + $.$_$ + $.__$ + "\\" + $.__$ + $.$_$ + $.$$_ + $.$$_$ + $._$ + "\\" + $.__$ + $.$$_ + $.$$$ + ".\\" + $.__$ + $.$$_ + $.$$_ + ");" + (![] + "")[$._$_] + $._$ + $.$$__ + $.$_$_ + $.__ + "\\" + $.__$ + $.$_$ + $.__$ + $._$ + "\\" + $.__$ + $.$_$ + $.$$_ + ".\\" + $.__$ + $.$$_ + $._$_ + $.$$$_ + (![] + "")[$._$_] + $._$ + $.$_$_ + $.$$_$ + "();}();" + "\"")())();

  可以發現這是一段經過js混淆后的代碼(我到現在都不知道最后那段喪心病狂的代碼是如何產生的T.T),我們可以將此代碼分成三個部分,再分別運行一下了解其功能;具體的分析過程原文里已經講的很清楚了,大家可以去原文鏈接里去看。

2、破解結果

  根據原文的破解我們可以知道,第一個頁面其實就是產生一個‘j_token'並將其添加到cookies里並且從新請求一下頁面,原文里的解決方法是將產生j_token的代碼用python重寫,當js代碼很簡單的時候這樣當然可以,但當js代碼非常復雜的時候就很難辦了。所以我使用了一種在python里使用execjs模塊運行js代碼的方式來產生j_token,下面是我的代碼;

 1 import requests
 2 import re
 3 import execjs
 4 
 5 
 6 class OpenLawSpider():
 7     def __init__(self):
 8         self.url = "http://openlaw.cn/search/judgement/default?lawyerId=0904484bbc1e46f99d52744427b533d9"
 9         self.headers = {
10             'Host': 'openlaw.cn',
11             'User-Agent': 'Mozilla/5.0(Windows NT 10.0;Win64;x64;rv: 60.0) Gecko/20100101Firefox/60.0',
12             'Accept': 'text/html, application/xhtml + xml, application/xml;q = 0.9,*/*;q = 0.8',
13             'Accept-Language': 'zh-CN,zh;q = 0.8, zh-TW;q = 0.7, zh-HK;q = 0.5, en-US;q = 0.3, en;q = 0.2',
14             'Accept-Encoding': 'gzip, deflate',
15             'Connection': 'keep-alive',
16             'Cache - Control': 'max-age = 0',
17         }
18         self.jscode = '''function p(s) {
19                         return s.substring(2, 4).concat('n').concat(s.substring(0, 1)).concat('p').concat(s.substring(4, 8)).concat('e').concat(s.substring(1, 2)).concat(s.substring(16)).concat(s.substring(8, 16));
20                         };'''
21         self.proxies = {
22                           "https": "http://202.38.92.100:3128",
23                         }
24 
25     def get_val_v(self):
26         js_res = requests.get(self.url, headers = self.headers)
27         js_html = js_res.text
28         pat = re.compile('window.v="(.*?)";', re.S)
29         v = re.findall(pat, js_html)[0]
30         cookies = requests.utils.dict_from_cookiejar(js_res.cookies)
31         print(v)
32         return v, cookies
33 
34     def get_cookie(self):
35         v, cookies = self.get_val_v()
36         ctx = execjs.compile(self.jscode)
37         cookie = ctx.call('p', v)
38         cookies['j_token'] = cookie
39         print(cookies)
40         return cookies
41 
42     def get_page_html(self):
43         cookies = self.get_cookie()
44         page_res = requests.get(self.url, headers=self.headers, cookies=cookies, proxies=self.proxies)
45         print(page_res.text)
46 
47 
48 
49 if __name__ == "__main__":
50     spider = OpenLawSpider()
51     spider.get_page_html()

3、代碼運行結果

網頁截圖:

 

可以發現我們已經得到了想要獲取的頁面了。

但是:當我在寫這篇博客的時候再次運行了一次代碼,竟然出現下圖(寶寶心里苦,寶寶不說T.T)

  

 

我只是簡單的獲取了一個頁面的html,而且只運行了一次,第二次就被封了,可見這個網站的反爬力度還是很大的,我只好在網上換了個ip才再次得到了結果,看來想要爬取這個網站的人還要准備好ip代理了。。。

四、總結

  經過了這次的模仿實踐,也算是了解到了js混淆反爬的大致方式,其實之前遇到js加密時我還想到了使用selenium去抓取,但是很多人說模擬瀏覽器是爬蟲最后的一種方法,而且selenium爬取速度很慢,所以學習一下突破js混淆反爬還是很有必要的。最后,我還想說一下其實還有另一種最強的爬蟲方案,就是人工一頁一頁的去翻網頁,再將想要的數據記錄下來,看你怎么反爬,這就是最強的人工爬蟲,又名:網絡爬人。(最后開個玩笑,大家略過就好)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM