爬蟲和反爬蟲
爬蟲工程師的手段
從渲染好的 html 頁面直接找到感興趣的節點,然後獲取對應的文本
去分析對應的接口數據,更加方便、精確地獲取數據
反爬蟲:
基於用戶行爲
檢測cookie,封ip
動態網頁
某一時間內請求次數過多
反爬蟲措施
反爬蟲的措施
- 使用HTTPS 協議
- 單位時間內限制掉請求次數過多,則封鎖該賬號
- 前端技術限制 (接下來是核心技術)
比如需要正確顯示的數據爲“19950220”
- 先按照自己需求利用相應的規則(數字亂序映射,比如正常的0對應還是0,但是亂序就是 0 <-> 1,1 <-> 9,3 <-> 8,…)製作自定義字體(ttf)
- 根據上面的亂序映射規律,求得到需要返回的數據 19950220 -> 17730220
- 對於第一步得到的字符串,依次遍歷每個字符,將每個字符根據按照線性變換(y=kx+b)。線性方程的係數和常數項是根據當前的日期計算得到的。比如當前的日期爲“2018-07-24”,那麼線性變換的 k 爲 7,b 爲 24。
- 然後將變換後的每個字符串用“3.1415926”拼接返回給接口調用者。(爲什麼是3.1415926,因爲對數字僞造反爬,所以拼接的文本肯定是數字的話不太會引起研究者的注意,但是數字長度太短會誤傷正常的數據,所以用所熟悉的 Π)
前端拿到數據後再解密,解密後根據自定義的字體 Render 頁面
- 先將拿到的字符串按照“3.1415926”拆分爲數組
- 對數組的每1個數據,按照“線性變換”(y=kx+b,k和b同樣按照當前的日期求解得到),逆向求解到原本的值。
- 將步驟2的的到的數據依次拼接,再根據 ttf 文件 Render 頁面上。
後端需要根據上一步設計的協議將數據進行加密處理
下面以 Node.js 爲例講解後端需要做的事情
- 首先後端設置接口路由
- 獲取路由後面的參數
- 根據業務需要根據 SQL 語句生成對應的數據。如果是數字部分,則需要按照上面約定的方法加以轉換。
- 將生成數據轉換成 JSON 返回給調用者
前端根據服務端返回的數據逆向解密
比如後端返回的是323.14743.14743.1446,根據我們約定的算法,可以的到結果爲1773
- 根據 ttf 文件 Render 頁面 上面計算的到的1773,然後根據ttf文件,頁面看到的就是1995
- 然後爲了防止爬蟲人員查看 JS 研究問題,所以對 JS 的文件進行了加密處理。如果你的技術棧是 Vue 、React 等,webpack 爲你提供了 JS 加密的插件,也很方便處理
- 個人覺得這種方式還不是很安全。於是想到了各種方案的組合拳。比如
反爬升級版
個人覺得如果一個前端經驗豐富的爬蟲開發者來說,上面的方案可能還是會存在被破解的可能,所以在之前的基礎上做了升級版本
- 組合拳1: 字體文件不要固定,雖然請求的鏈接是同一個,但是根據當前的時間戳的最後一個數字取模,比如 Demo 中對4取模,有4種值 0、1、2、3。這4種值對應不同的字體文件,所以當爬蟲絞盡腦汁爬到1種情況下的字體時,沒想到再次請求,字體文件的規則變掉了 😂
- 組合拳2: 前面的規則是字體問題亂序,但是隻是數字匹配打亂掉。比如 1 -> 4, 5 -> 8。接下來的套路就是每個數字對應一個 unicode 碼 ,然後製作自己需要的字體,可以是 .ttf、.woff 等等。
這幾種組合拳打下來。對於一般的爬蟲就放棄了。
反爬手段再升級
上面說的方法主要是針對數字做的反爬手段,如果要對漢字進行反爬怎麼辦?接下來提供幾種方案
- 方案1: 對於你站點頻率最高的詞雲,做一個漢字映射,也就是自定義字體文件,步驟跟數字一樣。先將常用的漢字生成對應的 ttf 文件;根據下面提供的鏈接,將 ttf 文件轉換爲 svg 文件,然後在下面的“字體映射”鏈接點進去的網站上面選擇前面生成的 svg 文件,將svg文件裏面的每個漢字做個映射,也就是將漢字專爲 unicode 碼(注意這裏的 unicode 碼不要去在線直接生成,因爲直接生成的東西也就是有規律的。我給的做法是先用網站生成,然後將得到的結果做個簡單的變化,比如將“e342”轉換爲 “e231”);然後接口返回的數據按照我們的這個字體文件的規則反過去映射出來。
- 方案2: 將網站的重要字體,將 html 部分生成圖片,這樣子爬蟲要識別到需要的內容成本就很高了,需要用到 OCR。效率也很低。所以可以攔截釣一部分的爬蟲
- 方案3: 看到攜程的技術分享“反爬的最高境界就是 Canvas 的指紋,原理是不同的機器不同的硬件對於 Canvas 畫出的圖總是存在像素級別的誤差,因此我們判斷當對於訪問來說大量的 canvas 的指紋一致的話,則認爲是爬蟲,則可以封掉它”。
本人將方案1實現到 Demo 中了。
關鍵步驟
- 先根據你們的產品找到常用的關鍵詞,生成詞雲
- 根據詞雲,將每個字生成對應的 unicode 碼
- 將詞雲包括的漢字做成一個字體庫
- 將字體庫 .ttf 做成 svg 格式,然後上傳到 icomoon 製作自定義的字體,但是有規則,比如 “年” 對應的 unicode 碼是 “\u5e74” ,但是我們需要做一個 愷撒加密 ,比如我們設置 偏移量 爲1,那麼經過愷撒加密 “年”對應的 unicode 碼是“\u5e75” 。利用這種規則製作我們需要的字體庫
- 在每次調用接口的時候服務端做的事情是:服務端封裝某個方法,將數據經過方法判斷是不是在詞雲中,如果是詞雲中的字符,利用規則(找到漢字對應的 unicode 碼,再根據凱撒加密,設置對應的偏移量,Demo 中爲1,將每個漢字加密處理)加密處理後返回數據
- 客戶端做的事情:
- 先引入我們前面製作好的漢字字體庫
- 調用接口拿到數據,顯示到對應的 Dom 節點上
- 如果是漢字文本,我們將對應節點的 css 類設置成漢字類,該類對應的 font-family 是我們上面引入的漢字字體庫
實現的效果
- 頁面上看到的數據跟審查元素看到的結果不一致
- 去查看接口數據跟審覈元素和界面看到的三者不一致
- 頁面每次刷新之前得出的結果更不一致
- 對於數字和漢字的處理手段都不一致
這幾種組合拳打下來。對於一般的爬蟲就放棄了。
建議
- 先設計一個字體圖標的製作規則
- JS 接入之後修改設置字體的處理展示邏輯
- 如果使用傳統的網頁開發技術(比如傳統的 jQuery 模式)建議你將業務設計的 JS 進行 加密混淆,這裏是一個混淆工具,增加反爬成本。如果是使用的 webpack 類的方式那麼可以設置壓縮規則,代碼可讀性也下降了。(當然推薦讀者自己去研究下在使用 webpack 模式下如何讓打包出的代碼更加難以閱讀,因爲我的經驗是即使 Vue、React 腳手架打包出的工程的 js, 在 Chrome 開發者模式下點擊代碼左下角的 {} 按鈕(Pretty Print) 可以對混淆後的代碼進行格式化,可讀性又好一些了,還是方便調試和閱讀)
程序員都不容易,做爬蟲的尤其不容易。可憐可憐他們給他們一小口飯吃吧。沒準過幾天你就因爲反爬蟲做得好,改行做爬蟲了。