1. 程式人生 > >爬蟲入門到放棄系列07:js混淆、eval加密、字型加密三大反爬技術

爬蟲入門到放棄系列07:js混淆、eval加密、字型加密三大反爬技術

## 前言 如果再說IP請求次數檢測、驗證碼這種最常見的反爬蟲技術,可能大家聽得耳朵都出繭子了。當然,也有的同學寫了了幾天的爬蟲,覺得爬蟲太簡單、沒有啥挑戰性。所以特地找了三個有一定難度的網站,希望可以有興趣的手動實踐一下。 此篇文章只作知識擴充套件和思路引導,其中涉及的網站反爬技術,僅做技術學習探討。 ## 字型加密 字型加密總結成一句話:你看到的不是你看到的。 ### 地址 貓眼電影:[https://maoyan.com/films/343568](https://maoyan.com/films/343568) ### 問題還原 最近的哥斯拉大戰金剛看了沒啊,好看不,評分高不高,票房多少了?讓我們去貓眼看一看吧。 ![哥斯拉大戰金剛](https://img-blog.csdnimg.cn/20210331234314505.jpg) 這一看問題就來了:*為什麼評分和票房在原始碼裡都是"口口"*?在頁面中看到的評分和票房去哪兒了? ### 追根溯源 話不多說,先看原始碼: ![](https://img-blog.csdnimg.cn/20210401144814754.png) 看完更疑問了,這個&#x又是啥?這個其實是html中的轉義序列,表示後面跟著的是十六進位制,處理後在控制檯列印一下,如圖: ![](https://img-blog.csdnimg.cn/20210401150150368.png) 這些數字和票房目前是一分錢關係都沒有。那就想辦法讓他們有所關聯。 從網頁中找到了以下程式碼: ![font-face](https://img-blog.csdnimg.cn/20210331234852112.jpg) 其實這就是在css中使用@font-face通過woff檔案自定義了字型,原始碼中的十六進位制數字必須通過這個字型對映才能正確顯示。就像UTF-8和GBK的關係,編碼和解碼一致才不會出現亂碼。 這裡我將woff字型檔案下載到本地並用工具開啟。 ![字型內容](https://img-blog.csdnimg.cn/20210401160901727.jpg) 從網頁上看到票房是5.74億,這裡就主要關注數字5。從上圖可以看出5對應的是glyph11。 使用工具將woff檔案轉換成xml格式: ![](https://img-blog.csdnimg.cn/20210401160901737.jpg) glyph11對應的是id=11的glyph,其對應的name為uniE8CD。接著在xml中找到uniE8CD對應的十六進位制: ![十六進位制對應](https://img-blog.csdnimg.cn/20210401160901789.jpg) 如圖,uniE8CD對應的是0xe8cd,也就是說**數字5對應的是0xe8cd**,正是在控制檯輸出的第一個數字。 ## eval() & JS加密 js被加密後放在eval()中執行。如果想還原js,在開發者控制檯使用console.log()輸出解密後的js。因為不論是eval()還是log(),js解析執行最終都依賴於瀏覽器核心。 ### 地址 TV貓:[https://www.tvmao.com/program/CCTV](https://www.tvmao.com/program/CCTV) ### 問題還原 在頻道劇集頁,分為早間、午間、晚間節目。如圖: ![網頁內容](https://img-blog.csdnimg.cn/20210329221238341.jpg) 在發起請求獲取頻道劇集資料的時候,發現返回內容只有早間節目資料,12點以後的劇集資料獲取不到。 檢視網頁原始碼: ![劇集網頁原始碼](https://img-blog.csdnimg.cn/20210329221238724.jpg) ### 追根溯源 我們在控制檯的請求中,搜尋網頁中的關鍵字"熊熊樂園",害,果不其然,還真搜著了。 ![](https://img-blog.csdnimg.cn/20210329221238251.jpg) 這個響應結果是一個數組,下標0代表標誌位:1代表獲取到了資料,0代表沒有獲取到資料;下標1是資料位,對應介面的返回資料。 解析此響應結果的程式碼比較繁雜,需要對多餘內容進行替換。 程式碼如下: ![解析程式碼](https://img-blog.csdnimg.cn/20210329232233301.jpg) 其實上面程式碼它並不重要!!接著我們順著網線去看他的請求部分: ![請求](https://img-blog.csdnimg.cn/20210329221238202.jpg) 從請求頭中可以看出,請求就一個引數p,1、2、3... 整整186位,你看這個引數它又長悠長,像那寂寥的雨巷。雖然等不來那撐著油紙傘的姑娘,但是至少可以先看看這個引數p是怎麼生成的。 在搜尋框搜尋api和pg關鍵字,找到下面程式碼: ![](https://img-blog.csdnimg.cn/20210330100007480.jpg) 別管其他,帶有ajax字樣十有八九就是ajax請求了,引數p的值是變數a,在生成變數a的程式碼處設定斷點,點選頁面中的"檢視更多"按鈕觸發斷點,接著進入A.d()方法: ![](https://img-blog.csdnimg.cn/20210330100008422.jpg) 往上翻,檢視js上部分: ![](https://img-blog.csdnimg.cn/20210330100008658.jpg) 其實到這裡就已經可以結束了,你看在d()中又呼叫了w(),w()也呼叫了A中其他方法,將這個js中方法呼叫鏈搞清楚,將每個方法程式碼都內聯起來,最後計算出引數p,就可以了。 *那麼,說好的eval呢,說好的加密的js呢?* ![](https://img-blog.csdnimg.cn/20210330135450340.gif) 少俠莫慌,這就帶您繼續看下去。如果你仔細看,你就會發現上面的js的檔名是匿名/臨時的,所以說這不是網站原有的js檔案,而是瀏覽器核心解析後的js。 *那該怎麼找到原來的js檔案?* 不知少俠可知搜尋功能,你看上面的js中有**keyStr**這個關鍵字,咱不妨搜尋一波。 ![](https://img-blog.csdnimg.cn/2021033010000979.jpg) 這不,如圖,eval()有了,加密js也有了,拷貝成文字如下: ``` eval(function(h, b, i, d, g, f) { g = function(a) { return (a < b ? "" : g(parseInt(a / b))) + ((a = a % b) > 35 ? String.fromCharCode(a + 29) : a.toString(36)) } ; if (!"".replace(/^/, String)) { while (i--) { f[g(i)] = d[i] || g(i) } d = [function(a) { return f[a] } ]; g = function() { return "\\w+" } ; i = 1 } while (i--) { if (d[i]) { h = h.replace(new RegExp("\\b" + g(i) + "\\b","g"), d[i]) } } return h }('5 A={z:"1o+/=",1b:"1l=1k",J:j(a){5 b="";5 c,L,M,14,16,O,N;5 i=0;a=A.1g(a);1t(i