當前位置:
首頁 > 知識 > 從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

摘要

  • 上一篇以知乎網為例簡單分享網路請求分析。這一篇主要分享一種應對反爬蟲的方法,前端數據混淆。

目的

  • 之前寫https://github.com/wycm/zhihu-crawler項目的時候,需要用到免費的http代理,然後找到了這個http://www.goubanjia.com/這個網站。現在需要把這個網站上的ip和port爬取下來,有興趣的朋友也可以嘗試自己爬取一下。

開始打開這個網站首頁,然後控制台查看ip和port的對應標籤。

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

如上圖(圖一),從控制台的標籤中可以看出ip加了一些無關不顯示的標籤來混淆數據,這裡混淆的原理其實很簡單,通過標籤的stylex="display:none"屬性來達到混淆的目的,也就是包含這個屬性的標籤是不會顯示在頁面上的。知道了這一點就比較好處理了,只需要在解析的時候把包含stylex="display:none"屬性的標籤去掉。就可以輕鬆的拿到ip和port數據了。 代碼如下

1 package com.cnblogs.wycm;
2
3 import org.jsoup.Jsoup;
4 import org.jsoup.nodes.Document;
5 import org.jsoup.nodes.Element;
6 import org.jsoup.select.Elements;
7 import java.io.IOException;
8 import java.net.URL;
9
10 /**
11 *
12 * 數據的解析採用的是Jsoup框架,Jsoup是一個操作HTML標籤的Java庫,它提供了非常方便的API來提取和操縱庫,支持類似jquery的選擇器來查找標籤。
13 * 由於請求比較單一,這裡的網路請求並沒有採用上一篇所使用HttpClient框架。直接通過Jsoup來執行http請求的。
14 * 關於Jsoup的使用可以參考http://www.open-open.com/jsoup/
15 *
16 */
17 public class Chapter1 {
18 public static void main(String[] args) throws IOException {
19 Document document= Jsoup.parse(new URL("http://www.goubanjia.com/"), 10000);
20 //獲取class="table"的table的所有子節點tr
21 Elements elements = document.select("table[class=table] tr");
22 for (int i = 1; i < elements.size; i++){ 23 //獲取td節點 24 Element td = elements.get(i).select("td").first; 25 /** 26 * 查找所有style屬性包含none字元串的標籤(頁面上未顯示的標籤),並移除 27 * 包括以下兩種 28 * stylex=display: none; 29 * stylex=display:none; 30 */ 31 for(Element none : td.select("[style*=none;]")){ 32 none.remove; 33 } 34 //移除空格 35 String ipPort = td.text.replaceAll(" ", ""); 36 //列印 37 System.out.println(ipPort); 38 } 39 } 40 } 41 /* 42 第一次運行列印結果: 43 183.129.246.228:8132 44 222.92.136.206:8987 45 54.238.186.100:8988 46 ... 47 第二次運行列印結果: 48 183.129.246.228:8377 49 222.92.136.206:9059 50 54.238.186.100:8622 51 ... 52 */

  • ip地址能夠準確的拿到了,卻發現port被做了混淆,而且每次返回的port還在動態改變。大家可以通過把瀏覽器的JavaScrip腳本關閉後,然後刷新這個網頁。會發現每次的port都不一樣。我們每次看到的正確port都是通過JavaScript腳本處理後的。如果採用普通爬蟲的方式拿到的port都是錯誤的。現在要想拿到正確的port,可以通過分析它JavaScrip腳本還原數據的邏輯。
  • 同樣打開控制台->選擇Sources->選擇一行js代碼打斷點(點擊行編號),如下圖

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

  • 刷新網頁—>頁面Paused in debugger—>選擇Elements->右鍵td節點->Break on...->subtree modifications。這兩個步驟就是在設置斷點調試,也就是在td節點發生改變的時候paused。

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

  • 選擇Sources->F8(繼續執行),這個時候又會有一次pause,也就是js腳本在還原正確port的時候(如下圖)

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

  • 函數的調用棧有好多層,如何快速定位哪一個函數的技巧就是,看它局部變數表的變數變化,因為這裡是port在發生改變,然後找到對應變數和對應邏輯函數。簡單分析可以確定到port發生改變的函數是一個匿名函數,如下圖

從零實現一個高性能網路爬蟲(二)應對反爬蟲之前端數據混淆

  • 格式化後,代碼如下:

    1 var _$ = ["x2ex70x6fx72x74", "x65x61x63x68", "x68x74x6dx6c", "x69x6ex64x65x78x4fx66", "x2a", "x61x74x74x72", "x63x6cx61x73x73", "x73x70x6cx69x74", "x20", "", "x6cx65x6ex67x74x68", "x70x75x73x68", "x41x42x43x44x45x46x47x48x49x5a", "x70x61x72x73x65x49x6ex74", "x6ax6fx69x6e", ""]; 2 $(function { 3 $(_$[0])[_$[1]](function { 4 var a = $(this)[_$[2]]; 5 if (a[_$[3]](_$[4]) != -0x1) { 6 return 7 } 8 ;var b = $(this)[_$[5]](_$[6]); 9 try { 10 b = (b[_$[7]](_$[8]))[0x1]; 11 var c = b[_$[7]](_$[9]); 12 var d = c[_$[10]]; 13 var f = ; 14 for (var g = 0x0; g < d; g++) { 15 f[_$[11]](_$[12][_$[3]](c[g])) 16 } 17 ;$(this)[_$[2]](window[_$[13]](f[_$[14]](_$[15])) >> 0x3) 18 } catch (e) {} 19 }) 20 })

  • 這段代碼採用了16進位進行混淆,還原後如下:

    1 var _$ = [".port", "each", "html", "indexOf", "*", "attr", "class", "split", " ", "", "length", "push", "ABCDEFGHIZ", "parseInt", "join", ""]; 2 $(function { 3 $(".port").each(function { 4 var a = $(this).html; 5 if (a.indexOf("*") != -0x1) { 6 return 7 } 8 ;var b = $(this).attr("class"); 9 try { 10 b = (b.split(" "))[0x1]; 11 var c = b.split(""); 12 var d = c.length; 13 var f = ; 14 for (var g = 0x0; g < d; g++) { 15 f.push("ABCDEFGHIZ".indexOf(c[g])) 16 } 17 ;$(this).html(window.parseInt(f.join("")) >> 0x3) 18 } catch (e) {} 19 }) 20 })

  • 這段代碼的邏輯,獲取port標籤的class屬性值,取出屬性中後面的幾個大寫字母,遍歷該字元串,找出每次字元在"ABCDEFGHIZ"這個字元串中的索引,然後parseInt轉換為整數,然後進行右移3位的操作。
  • 完整代碼實現

    1 package com.cnblogs.wycm; 2 3 import org.jsoup.Jsoup; 4 import org.jsoup.nodes.Document; 5 import org.jsoup.nodes.Element; 6 import org.jsoup.select.Elements; 7 8 import java.io.IOException; 9 import java.net.URL; 10 11 public class Chapter2 { 12 public static void main(String[] args) throws IOException { 13 Document document= Jsoup.parse(new URL("http://www.goubanjia.com/"), 10000); 14 setPort(document); 15 //獲取class="table"的table的所有子節點tr 16 Elements elements = document.select("table[class=table] tr"); 17 for (int i = 1; i < elements.size; i++){ 18 //獲取td節點 19 Element td = elements.get(i).select("td").first; 20 /** 21 * 查找所有style屬性包含none字元串的標籤(頁面上未顯示的標籤),並移除 22 * 包括以下兩種 23 * stylex=display: none; 24 * stylex=display:none; 25 */ 26 for(Element none : td.select("[style*=none;]")){ 27 none.remove; 28 } 29 //移除空格 30 String ipPort = td.text.replaceAll(" ", ""); 31 //列印 32 System.out.println(ipPort); 33 } 34 } 35 36 /** 37 * js代碼port還原 38 * @param doc 39 */ 40 private static void setPort(Document doc){ 41 for (Element e : doc.select(".port")){//$(".port").each(function { 42 String a = e.text;//var a = $(this).html; 43 if(a.indexOf("*") != -0x1){//if (a.indexOf("*") != -0x1) { 44 return; 45 } 46 String b = e.attr("class");//var b = $(this).attr("class"); 47 b = b.split(" ")[0x1];//b = (b.split(" "))[0x1]; 48 String c = b.split("");//var c = b.split(""); 49 int d = b.length;//var d = c.length; 50 StringBuilder f = new StringBuilder;//var f = ; 51 for(int g = 0x0; g < d; g++){//for (var g = 0x0; g < d; g++) { 52 f.append("ABCDEFGHIZ".indexOf(c[g]));//f.push("ABCDEFGHIZ".indexOf(c[g])) 53 } 54 e.text(String.valueOf(Integer.valueOf(f.toString) >> 0x3));//$(this).html(window.parseInt(f.join("")) >> 0x3) 55 } 56 } 57 }

  • maven依賴

    1 2 org.jsoup 3 jsoup 4 1.10.2 5

總結

  • 該篇文章簡單分項了下如何應對前端混淆的反爬蟲。關於這種反爬蟲,還有其它的一些應對方式。如採用無頭瀏覽器的方式,比如phantomjs框架。這種無頭瀏覽器原本是用來做自動化測試的。它是基於webkit內核的,所以它可以較容易的爬取這種前端混淆的這種網站。一般來說瀏覽器能夠正常訪問到的數據,這種方式也可以比較容易爬取這些數據。當然這種方式的最大問題就是效率比較低。因為這種方式它每載入一個頁面,都需要下載它的附加資源,如js腳本,腳本下載完成後,還要去執行js腳本。
  • 我這裡採用的方式是閱讀js代碼,得出前端混淆的邏輯,然後再通過目標語言來實現對應邏輯。這種方式如果針對一些簡單的加密混淆還是很有用的。但是當遇到一些大型複雜的網站,如百度、微博等,需要抓取登錄後的數據。這時候需要來手動模擬登錄,相對來說,這種網站的模擬登錄會更複雜,找各種登錄參數來源。都會耗費大量精力。分析請求的成本會比較高。這種方式的優點就是爬取速度快,只獲取目標數據。不需要額外網路請求成本。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

javaScript 設計模式系列之一:觀察者模式
Swift 中 String 取下標及性能問題
.Net Core中使用ref和Span提高程序性能

TAG:科技優家 |

您可能感興趣

爬蟲進階:反反爬蟲技巧
反爬蟲一直是偽需求
網路爬蟲——抓取時的幾個小細節
網路江湖裡爬蟲玩的是一場「無間道」
每秒幾十萬的大規模網路爬蟲是如何煉成的?
爬蟲類,不一樣的個性
商業爬蟲的級別才能應對反爬策略
走進成熟的爬蟲框架
快速提升爬蟲性能的幾種方法
網路爬蟲恣意橫行,數據黑產必須打掉
新手爬蟲第一彈
一隻來越冬的爬蟲
數說爬蟲和反爬蟲大戰,誰是最後贏家?
【爬行天下】智能一體式爬蟲箱
這個地方一個爬蟲竟然能賣到十萬美元,一個蟲子竟然比你住的房子還要貴
這可能是全世界最恐怖爬蟲,瞬間摧毀鐵甲
【收藏】一文讀懂網路爬蟲!
通俗易懂的分析如何用Python實現一隻小爬蟲,爬取拉勾網的職位信息
互聯網上的腳印,竟然是爬蟲留下的?
洛克王國:酷愛吃屎的噁心爬蟲,覺醒之後形象霸氣卻不堪一擊