【C#】WinForm 之 DOTA2英雄搭配助手(網頁抓取+在線綠色版+源碼開放)


吐舌笑臉睡不着,無聊......再整理點好玩的出來。先上圖


效果

6HUXOZQ69{]6OFD92ZUT6YQUS`GAF3S666LRJ~OOL}MNFR3KRGLLMT8[0YPZXO_C32`~R


 

碎碎念忍者

自從13級后打出DOTA2的天梯積分以來簡直是逆水行舟不進則退啊,室友已經高呼着被游戲玩了!!結果怒刪游戲

其實我也發現這游戲不合適我玩…天梯里場場被各種選英雄針對,普通場又是劍聖、斧王橫行。加之本人比較懶,不愛看視頻,場均10死那是常有的事(打起來跟打WOW戰場一樣,反正死了有復活:P)

不瞎扯了,其實初衷就是不想被針對(想選個最臟陣容神馬的我會告訴你嘛)


 

核心功能

這里要從Dotamax(http://dotamax.com/)說起,因為程序的核心都是在於如何抓取該DOTA2數據門戶提供的英雄數據。

看了這個網站相信大家基本有數了,說好的大數據、可視化這網站就用上了。我這里用的就是“克制指數”與“配合指數”(高玩說這個還是比較靠譜的,然后我就信了)。

通過以下函數獲得目標地址的網頁內容(我基本用的是字符串處理,DOM分析也是沒問題的)

private string GetWebContent(string Url)
        {
            string strResult = "";
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
                //聲明一個HttpWebRequest請求 
                request.Timeout = 30000;
                //設置連接超時時間 
                request.Headers.Set("Pragma", "no-cache");
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream streamReceive = response.GetResponseStream();
                Encoding encoding = Encoding.GetEncoding("utf-8");
                StreamReader streamReader = new StreamReader(streamReceive, encoding);
                strResult = streamReader.ReadToEnd();
            }
            catch
            {
                MessageBox.Show("獲取信息失敗,請檢查網絡連接");
            }
            return strResult;
        }

 

以下是抓取的步驟,由於本人第一次做此類應用,小白之處請及時指出哈。

A.抓取英雄信息

首先是抓取英雄信息。

目標URL:  http://dotamax.com/hero/

頁面分析:

<div id="半人馬戰行者" class="hero-list-hero Unused-Hero" onclick="DoNav('/hero/detail/centaur/')">
    <img class="hero-hover opacity-img img-shadow" src="http://www.dota2.com.cn/images/heroes/centaur_hphover.png">
    <div class="hero-top-list-bar">
        <span style="position: absolute;left:5px;color:rgb(87,186,53);bottom:-4px;"><img src="/static/image/overviewicon_str.png" style="width:15px;"></span>
    </div>
    <div class="hero-list-bar">
        <span style="color:#ccc !important;text-align: center;">半人馬戰行者 </span>
    </div>
</div>

從這段標簽應該很容易找到

  • 中文英雄名稱
  • 英文英雄名稱
  • 英雄頭像

這幾個字段有了后就可以建立本地緩存或者添加一行記錄了,具體代碼:

private void getHeros()
        {
            heroDataTable = new DataTable("heros");
            heroDataTable.Columns.Add("英雄名", typeof(string));            

            //要抓取的URL地址 
            string Url = "http://www.dotamax.com/hero/";
            //得到指定Url的源碼 
            string html = GetWebContent(Url);

            string EnName, ChName;
            string key;
            int index = 0;
            //string output = "";
            int count = 0;

            do
            {
                key = "onclick=\"DoNav('/hero/detail/";
                int i = html.IndexOf(key, index);

                if (i == -1)
                    break;

                i += key.Length;
                int j = html.IndexOf("/", i);
                EnName = html.Substring(i, j - i);

                key = "<span style=\"color:#ccc !important;text-align: center;\">";
                i = html.IndexOf(key, j + 1);
                i += key.Length;
                j = html.IndexOf(" </span>", i);
                ChName = html.Substring(i, j - i);


                Ch2En.Add(ChName, EnName);
                heroList.Add(ChName);

                DataRow dr = heroDataTable.NewRow();
                dr["英雄名"] = ChName;
                heroDataTable.Rows.Add(dr);
                count++;

                index = j;

            } while (true);
        }

 

B.抓取克制指數

根據英雄名稱,到指定URL抓取克制該英雄的英雄列表。

目標URL:http://dotamax.com/hero/detail/match_up_anti/英文英雄名稱/

頁面分析:

<tr>
    <td>
        <a href="/hero/detail/phantom_assassin"><img class="hero-img-list" src="http://www.dota2.com.cn/images/heroes/phantom_assassin_hphover.png"></a>
        <span class="hero-name-list">幻影刺客</span>
    </td>
    <td>
        <div style="height: 10px">3.19%</div>
        <div class="segment segment-green" style="width:33.997677256%;"></div>
    </td>
    <td>
        <div style="height: 10px">56.96%</div>
        <div class="segment segment-gold" style="width:56.9584024346%;"></div>
    </td>
    <td>
        <div style="height: 10px">292445</div>
        <div class="segment segment-green" style="width:%;"></div>
    </td>
</tr>

頁面中有大段的注釋干擾(不知道是不是特意設置 don't care),反正注意跳過去,別抓錯

<!--
                    <td><div style="height: 10px">%</div><div class="segment segment-green" style="width:%;"></div></td><td><div style="height: 10px">%</div><div class="segment segment-green" style="width:%;"></div></td>
                    -->

從這段標簽找到

  • 克制英雄名稱
  • 克制指數

這樣子如果自己這方選了該克制英雄就加上對應克制指數。然后按這個數值排好序,給出推薦。具體代碼:

private void addAntiIndex(string hero,int no)
        {
            no++;

            string CurEnName = Ch2En[hero];
            string CurChName = hero;
            string Url = "http://www.dotamax.com/hero/detail/match_up_anti/" + CurEnName + "/";
            //得到指定Url的源碼 
            html = GetWebContent(Url);


            string AntiName, AntiValue, WinRate, UsedTime;
            string key;            
            int index = 0;;

            do
            {
                key = "<span class=\"hero-name-list\">";
                int i = html.IndexOf(key, index);

                if (i == -1)
                {
                    autoSorting();
                    return;
                }

                i += key.Length;
                int j = html.IndexOf("</span>", i);
                AntiName = html.Substring(i, j - i);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 1);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                AntiValue = html.Substring(i, j - i);

                //去除反抓取
                j = html.IndexOf("-->", j);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 3);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                WinRate = html.Substring(i, j - i);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 1);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                UsedTime = html.Substring(i, j - i);

                index = j;


                AntiValue = AntiValue.Substring(0, AntiValue.Length - 1);
                double value = Convert.ToDouble(AntiValue);
                int t_no = findHero(AntiName);
                heroDataTable.Rows[t_no][no] = -value;

                double sum = 0;
                for (int h = 2; h < 12; h++)
                {
                    sum += (double)heroDataTable.Rows[t_no][h];
                }
                heroDataTable.Rows[t_no][1] = sum;               
            } while (true);            
        }

 

C.抓取配合指數

根據英雄名稱,到指定URL抓取配合該英雄的英雄列表。

目標URL:http://dotamax.com/hero/detail/match_up_comb/英文英雄名稱/

頁面跟之前那步基本沒什么區別,這里就不重復說了。

目的是找到

  • 配合英雄名稱
  • 配合指數

這樣在克制對面的基礎上,繼續結合隊友選擇的英雄,選出最XXX陣容。具體代碼:

private void addCombIndex(string hero, int no)
        {
            no++;

            string CurEnName = Ch2En[hero];
            string CurChName = hero;
            string Url = "http://www.dotamax.com/hero/detail/match_up_comb/" + CurEnName + "/";
            //得到指定Url的源碼 
            html = GetWebContent(Url);


            string CombName, CombValue, WinRate, UsedTime;
            string key;
            int index = 0; ;

            do
            {
                key = "<span class=\"hero-name-list\">";
                int i = html.IndexOf(key, index);

                if (i == -1)
                {
                    autoSorting();
                    return;
                }

                i += key.Length;
                int j = html.IndexOf("</span>", i);
                CombName = html.Substring(i, j - i);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 1);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                CombValue = html.Substring(i, j - i);

                //去除反抓取
                j = html.IndexOf("-->", j);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 3);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                WinRate = html.Substring(i, j - i);

                key = "<div style=\"height: 10px\">";
                i = html.IndexOf(key, j + 1);
                i += key.Length;
                j = html.IndexOf("</div>", i);
                UsedTime = html.Substring(i, j - i);

                index = j;


                CombValue = CombValue.Substring(0, CombValue.Length - 1);
                double value = Convert.ToDouble(CombValue);
                int t_no = findHero(CombName);
                heroDataTable.Rows[t_no][no] = value;

                double sum = 0;
                for (int h = 2; h < 12; h++)
                {
                    sum += (double)heroDataTable.Rows[t_no][h];
                }
                heroDataTable.Rows[t_no][1] = sum;
            } while (true); 
        }

 

D.簡單的查找、排序

這個貌似沒啥好說的.

 

寫在最后

本人先后使用txt文件、MS-SQL(VS比較方便)緩存網頁數據,但為了簡化安裝方便基友測試還是再寫了一個在線綠色版本,即:邊分析邊顯示,所有數據僅用變量存儲,只占用部分內存而不生成任何緩存文件,整個程序僅一個exe文件。

當然,C#的程序還是需要預先有 .net framework,然而身為CS專業的小伙伴竟然還真有沒裝.NET的,我已無力吐槽亞當

不過這樣子也有個問題就是響應速度變慢了,因為除了啟動程序的時候將所有英雄信息導入內存以外,每添加一個英雄還要抓取一次克制/配合信息。反正我自己肯定是用離線版的拉,不然哪有時間邊選英雄邊統計數據,不過大家真要改改也快的哈,而且看着爬過來的數據填滿數據庫,感覺良好:P

其實最最大的問題在於手動添加英雄太麻煩了,但是DOTA2貌似只有RPG版才能做Lua插件…反正我真心不知道多玩盒子這些DOTA插件是怎么跟游戲交互的。so 只能做成"DOTA2英雄搭配助手"而不是啥"最臟DOTA2插件"了…有誰知道的話求告訴哈~那啥,我還是很想做成XXXX插件的哈。(說模式識別的基友你好,再見!)

 

Dota2Aid在線綠色版:

http://files.cnblogs.com/files/KC-Mei/Dota2Aid.zip (已過期)

http://files.cnblogs.com/files/KC-Mei/Dota2Aid-Latest.rar(不知道那個幫助寫明白沒,應該是能用的吧)

恩,說好的開源,VS2012的項目文件: https://github.com/Blz-Galaxy/Dota2Aid_OnlineVersion 

由於自己都用的是本地數據庫版本,在線版的可能還有一些BUG沒修復,原諒我懶得改了…反正感覺這個響應速度打死我也不會真正用這個。

繼續跪求多玩盒子的交互原理… 

最后附贈個MS-SQL服務監視器,做本地數據庫的話搭配用妥妥的~吐舌笑臉

【C#】WinForm 之 SQL Server 服務監控器(避免開機啟動服務)http://www.cnblogs.com/KC-Mei/p/4334179.html

 


免責聲明!

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



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