網絡爬蟲之投票


目錄

  1. 前言
  2. 起因
  3. 主要技術點
  4. 總結
  5. 后記

一、前言

       在你心中什么是網絡爬蟲?在網線里鑽來鑽去的小蟲?先看一下百度百科的解釋:

網絡爬蟲(又被稱為網頁蜘蛛,網絡機器人,在FOAF社區中間,更經常的稱為網頁追逐者),是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本。另外一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。

       看完之后有何感想,其實百度、Bing、Google等都是大網絡爬蟲。當然我們不可能去做一個像百度一樣的搜索引擎,那么爬蟲對我們普通人有什么用?用處很大,小到刷你的博客流量、大到獲取商業機密(何為商業機密?進入大數據時代,一個公司的數據就是其最大商業機密,所以要想獲取途牛、淘寶、京東的商業機密很簡單————爬吧)。本文不介紹這么高大上的(其實實現方法都一樣),介紹一個所有人都深受其害的(是否有被人邀請投票的經歷?)————投票。

二、起因

       這幾天百忙中用網絡爬蟲做了一個網絡自動投票器,結果很簡單,過程較艱難。又想到很多同胞跟我一樣深受“拉票之害”,簡單記錄之,用於總結網絡爬蟲的功能,希望每個人看完都能自己寫個投票器自己刷票(投票不求人),哈哈。

三、主要技術點

  1. 網絡抓包
  2. dom樹分析
  3. winform網絡請求
  4. 模擬登錄
  5. 字符串處理

3.1 網絡抓包

       寫網絡爬蟲最重要的就是抓包,抓包在百度百科中的解釋如下:

抓包(packet capture)就是將網絡傳輸發送與接收的數據包進行截獲、重發、編輯、轉存等操作,也用來檢查網絡安全。抓包也經常被用來進行數據截取等。

       理論上凡是通過網卡的數據都能通過抓包的方式進行分析,在網絡爬蟲中主要抓的是HTTP/HTTPS協議的數據,這兩種數據也就是通過瀏覽器能夠正常訪問的數據。HTTP/HTTPS協議抓包工具有很多,個人覺得比較好的是Fiddler,關於其下載和用法網上很多,不做這里贅述。

       比如我們要寫一個投票工具,那么主要考慮抓這么幾個數據:

  1. 最重要的是投票地址。點擊你要投票的對象的投票按鈕,這時候瀏覽器會自動向投票地址發請求,這當然逃不過Fiddler的火眼金睛。我們就可以把這個網址記錄下來用於寫投票器。當然如果你的投票沒有登錄、沒有其他環節,就是點一下投票二字即可,那么你走運了,到這一步你的工作已經結束了。
  2. 如果投票有登錄也不要慌,在登錄頁面輸入用戶名密碼,點擊登錄,同樣會在Fiddler中留下登錄的鏈接地址。
  3. 其他具體情況具體分析。

       這里需要說明的是HTTP請求分為POST、GET等方式(具體可以百度之),凡是通過瀏覽器直接輸入地址顯示出來的頁面肯定都是GET請求,像投票請求兩種方式均有可能,登錄請求基本上可以肯定是POST。POST和GET的不同就在於POST能夠提交表單數據,所以需要我們根據自己的用戶名密碼等拼接表單數據。

3.2 dom樹分析

       簡單投票器一般不需要進行DOM樹分析,只有極個別的情況需要(恰好此次被我碰到),其他網絡爬蟲如數據獲取等是肯定需要進行此項分析的。我在這里將其寬泛化,把JS腳本解析等都歸入此類中,這需要我們掌握一些HTML的基礎知識,包括HTML標簽,像<input>、<a>、<span>、<div>等以及javascript語法、CSS語法等。

3.3 winform網絡請求

       進入到今天的關鍵階段,通過上述步驟我們獲取到了投票地址,比如(http://www.****.cn/vote.php?id=100)。那么我們如何通過程序發送請求呢?總不能讓我們在瀏覽器輸入鏈接然后狂按回車吧?這樣就起不到投票器的作用了。

       其實也很簡單,很多語言中都已經內置了網絡請求模塊,我們以C#為例,可以采用下述方法進行請求。

public string GetContent(string method, string url, string postData = "", CookieContainer cookie = null)
{
    HttpWebResponse response = null;
    HttpWebRequest request = null;
    if (cookie == null)
        cookie = new CookieContainer();
    // 准備請求...
    try
    {
        // 設置參數
        request = WebRequest.Create(url) as HttpWebRequest;
        request.CookieContainer = cookie;
        request.AllowAutoRedirect = true;
        request.Method = method.ToUpper();
        request.ContentType = "application/x-www-form-urlencoded";
        string userAgent = string.Format("Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.8670)");
        request.UserAgent = userAgent;
        request.ContentLength = postData.Length;
        if (method.ToUpper() == "POST")
        {
            if (!string.IsNullOrEmpty(postData))
            {
                byte[] data = Encoding.Default.GetBytes(postData);
                request.ContentLength = data.Length;
                using (Stream outstream = request.GetRequestStream())
                {
                    outstream.Write(data, 0, data.Length);
                }
            }
        }
        //發送請求並獲取相應回應數據
        response = request.GetResponse() as HttpWebResponse;
        //直到request.GetResponse()程序才開始向目標網頁發送Post請求
        using (Stream instream = response.GetResponseStream())
        {
            using (StreamReader sr = new StreamReader(instream, encoding))
            {
                //返回結果網頁(html)代碼
                string content = sr.ReadToEnd();
                return content;
            }
        }
    }
    catch (Exception ex)
    {
        string err = ex.Message;
        return err;
    }
    finally
    {
        if (response != null)
            response.Close();
    }
}

上述代碼實現了GET和POST兩種請求方式,其中method即為上述兩種方法,url就是你找到的請求。postData是你拼接的表單數據。該方法返回的是頁面的HTML代碼。

       所以是不是很容易,如果你的投票就是點一下就能投的類型,恭喜你,通過上面的代碼加一個循環你就可以開啟瘋狂刷票模式。但是事與願違,很多投票都不是那么簡單,最大的障礙就是有些投票要先登錄。

3.4 模擬登錄

       其實WEB端的登錄就是向服務器獲取一個標識,這個標識學名Cookie,當我們點擊登錄的時候向服務器發送一個通知,通知服務器我來了,服務器收到后給你一個腰牌(Cookie)說:我知道了,你拿着這個腰牌以后見牌如見君。這樣我們后面再點投票的時候服務器就知道是你投的票,不是其他冒牌貨。所以關鍵問題就在如何獲取Cookie。

       其實上面的代碼已經包含了這個功能,你只需要在使用GetContent函數發送登錄請求的時候接受其中的Cookie即可。所以登錄請求和投票請求都可以使用上述代碼,上述代碼也就是Winform程序發送網絡請求的核心代碼。

3.5 字符串處理

       在這講述偉大的爬蟲的時候我為什么要再講字符串處理呢,其實這次爬蟲投票器差點就在字符串處理這個問題上前功盡棄,幾乎已經開始構思更牛逼的方法。這次抓包發現發送投票請求的時候向服務器多發送了一個參數,名稱為hc,我一看小意思這應該是一個時間標識一樣的東西,將其置之不理,可是始終得不到正確的投票結果,一直說投票無效,猜想難道這個投票網站這么先進?沒有道理啊,不存在比人腦還先進的電腦(除非你是阿法狗)。然后將程序的JS代碼以及DOM樹認認真真的分析了一遍,發現其值取於一個類型為"hidden"的input域,每次請求該值都會發生變化,所以我一直投票不成功,然后想這就簡單了,每次請求一下這個網頁,取出該值就好,代碼如下:

string GetHc(CookieContainer cookie)
{
    var url = "http://......";
    var res= GetContent("GET", url, cookie: cookie);
    var index = res.IndexOf("<input type=\"hidden\" id=\"hc\" value=\"");
    if (index >= 0)
        return res.Substring(index, 8);
    return "";
}

       代碼很容易,因為取的值簡單也沒有用正則表達式,只是使用了Substring。滿心歡喜以為大功告成,誰知依然是悲劇,百思不得其解,無論怎樣都不行。就在我正准備放棄,使用更牛逼的武器的時候。詳情請見(使用selenium+phantomJS實現網頁爬取)。突然發現得到的hc根本就不是正確的hc,不知道各位看官是否瞧出?因為IndexOf獲取的是匹配字符的開頭的序號,所以此處根本沒有獲取到hc。正確的方法應該是res.Substring(index + "<input type=\"hidden\" id=\"hc\" value=\"".Length, 8)。改完之后立馬投票成功。

四、總結

       本文簡單介紹了爬蟲所涉及到的相關知識,以及如何解析出一個投票器的請求鏈接。冰凍三尺非一日之寒,任何學問都涉及到方方面面的知識,唯有沉淀下來融入進去方能收獲最好的自己。尤其還需要注意細節,以及堅持,如果不是多實驗了一次發現Substring的這個問題,恐怕也就沒有這篇文章了。

五、后記

       各位看官寫個投票器是不是很容易?其實這里面牽扯到的問題很多,比如如果有驗證碼,投票器寫不了,比如手機登錄、微信里面投票什么的寫不了。再者說網絡刷票沒有逃避監管的方式,凡是想追蹤都能通過后台數據分析出來。所以各位看官,刷票有風險,操作需謹慎,各種利弊自己權衡。


免責聲明!

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



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