zoukankan      html  css  js  c++  java
  • 【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="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="33.997677256%;"></div>
        </td>
        <td>
            <div style="height: 10px">56.96%</div>
            <div class="segment segment-gold" style="56.9584024346%;"></div>
        </td>
        <td>
            <div style="height: 10px">292445</div>
            <div class="segment segment-green" style="%;"></div>
        </td>
    </tr>

    页面中有大段的注释干扰(不知道是不是特意设置 don't care),反正注意跳过去,别抓错

    <!--
                        <td><div style="height: 10px">%</div><div class="segment segment-green" style="%;"></div></td><td><div style="height: 10px">%</div><div class="segment segment-green" style="%;"></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

  • 相关阅读:
    leetcode------Search in Rotated Sorted ArrayII
    leetcode------Search in Rotated Sorted Array
    leetcode------Multiply Strings
    leetcode------Integer to Roman
    IIS7.5 自定义Html/shtml/htm...后缀映射
    [错误]试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)
    FolderBrowserDialog 成员
    [转载]DirectoryEntry配置IIS7出现ADSI Error:未知错误(0x80005000)
    C# textbox 滚动条 随文本输入 滚动
    C#文件对话框,一次多选文件设置
  • 原文地址:https://www.cnblogs.com/KC-Mei/p/4346140.html
Copyright © 2011-2022 走看看