/// <summary>
        /// 处理UrlDictionary,筛选+做的是减法
        /// </summary>
        /// <param name="args"></param>
        /// <param name="patternStr"></param>
        private static void CustomParseLink_MainList(CustomParseLinkEvent3Args args, string patternStr)
        {
            Dictionary<string, string> temp = new Dictionary<string, string>();
            foreach (var item in args.UrlDictionary)
            {
                string href = item.Key;
                string text = item.Value;

                if (!string.IsNullOrEmpty(href))
                {
                    Regex regex = new Regex(patternStr, RegexOptions.IgnoreCase);//忽略大小写
                    Match mat = regex.Match(href);
                    if (mat.Success)
                    {
                        temp.Add(href, text);
                    }
                }
            }
            args.UrlDictionary = temp;
        }
        /// <summary>
        /// 处理Html,重新过滤+做的是加法
        /// </summary>
        /// <param name="args"></param>
        /// <param name="patternStr"></param>
        /// <param name="groupIndex"></param>
        private static void CustomParseLink_NextPageSdau(CustomParseLinkEvent3Args args, string patternStr, int groupIndex)
        {
            string url = "";
            if (args != null && !string.IsNullOrEmpty(args.Html))
            {

                Regex regex = new Regex(patternStr, RegexOptions.IgnoreCase);//忽略大小写
                Match mat = regex.Match(args.Html);
                if (mat.Success)
                {
                    url = mat.Groups[groupIndex].Value;
                    var baseUri = new Uri(args.UrlInfo.UrlString);
                    Uri currentUri = url.StartsWith("http", StringComparison.OrdinalIgnoreCase)
                                         ? new Uri(url)
                                         : new Uri(baseUri, url);//根据指定的基 URI 和相对 URI 字符串,初始化 System.Uri 类的新实例。
                    //如果不包含http,则认为超链接是相对路径,根据baseUrl建立绝对路径
                    url = currentUri.AbsoluteUri;
                    //Console.WriteLine("######" + url + "######");
                    args.UrlDictionary.Add(url, Guid.NewGuid().ToString());
                }
            }
            //return args.UrlDictionary;
        }
 private static void CustomParseLink_MainListMode2(CustomParseLinkEvent3Args args, string kDetailPattern, int groupIndex)
 {
     string url = "";
     if (args != null && !string.IsNullOrEmpty(args.Html))
     {
         MatchCollection mat_k = Regex.Matches(args.Html, kDetailPattern, RegexOptions.IgnoreCase);
         foreach (Match item in mat_k)
         {
             if (item.Success)
             {
                 url = item.Groups[groupIndex].Value;
                 var baseUri = new Uri(args.UrlInfo.UrlString);
                 Uri currentUri = url.StartsWith("http", StringComparison.OrdinalIgnoreCase)
                                      ? new Uri(url)
                                      : new Uri(baseUri, url);//根据指定的基 URI 和相对 URI 字符串,初始化 System.Uri 类的新实例。
                                                              //如果不包含http,则认为超链接是相对路径,根据baseUrl建立绝对路径
                 url = currentUri.AbsoluteUri;
                 //Console.WriteLine("######" + url + "######");
                 args.UrlDictionary.Add(url, Guid.NewGuid().ToString());
             }
         }
     }
 }
        private static void Master_CustomParseLinkEvent3(CustomParseLinkEvent3Args args)
        {



            #region 
            //
            #region 可以进一步修改
            //if (isDetailMode2 == true)
            //{
            //    CustomParseLink_MainList(args, "今天天气好晴朗,又是刮风又是下雨。");//什么都不匹配
            //    CustomParseLink_MainListMode2(args, configModel.kDetailPattern, 0);
            //}
            //else
            //{
            //    CustomParseLink_MainList(args, configModel.kDetailPattern);//什么都不匹配
            //} 
            #endregion
            //
            CustomParseLink_MainList(args, "什么都不匹配什么都不匹配什么都不匹配什么都不匹配");//什么都不匹配
            CustomParseLink_MainListMode2(args, configModel.kDetailPattern, 0);
            CustomParseLink_NextPageSdau(args, configModel.kNextPagePattern, 1);//下一页                     
            #endregion

            #region  SDAU
            //CustomParseLink_MainList(args, "(view).+?([0-9]{5})");//去除,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_NextPageSdau(args, "<a .+ href='(.+)'>下一页</a>", 1);//添加,下一步,拼写一个大的正则表达式就好 
            #endregion
            #region 北京市地震局
            //CustomParseLink_MainList(args, "今天天气好晴朗,又是刮风又是下雨");//什么都不匹配
            //CustomParseLink_NextPageSdau(args, "•<A href=\"(/manage/html/[\\d\\w]{32}/_content/\\d{2}_\\d{2}/\\d{2}/\\d+\\.html)\"", 1);//详细页
            //CustomParseLink_NextPageSdau(args, "<a href=\"(index_\\d+.html)\">下一页</a>", 1);//下一页 
            #endregion
            #region 上海民政
            ////去除(保留符合正则的),下一步,拼写一个大的正则表达式就好
            //CustomParseLink_MainList(args, @"/gb/shmzj/node4/node\d+/n\d{4}/u1ai\d{5}.html");
            ////添加,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_NextPageSdau(args, "<a HREF=\"(/gb\\shmzj/node4/node\\d+/n\\d{4}/index\\d+\\.html)\" class=next>下一页</a>", 1); //<a href="(List.action\?[\w\d&=]+)">下一页</a>  
            #endregion
            #region 陕西

            ////去除,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_MainList(args, @"xg-xxgk-gk-[\d|-]+");//xg-xxgk-gk-[\d|-]+
            ////添加,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_NextPageSdau(args, "<a href=\"(List.action\\?[\\w\\d&=]+)\">下一页</a>", 1); //<a href="(List.action\?[\w\d&=]+)">下一页</a> 
            #endregion
            #region 上海
            ////去除,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_MainList(args, @"detail1.jsp.*id=\d*");
            ////添加,下一步,拼写一个大的正则表达式就好
            //CustomParseLink_NextPageSdau(args, @"<A .*HREF=(.+) class.*>\s*下一页</A>", 1); 
            #endregion
            #region 安居客
            //CustomParseLink_MainList(args, "http://beijing.anjuke.com/prop/view/.*commsearch_p");
            //CustomParseLink_NextPageSdau(args, "<a href='(.+)' class='aNxt'>下一页 &gt;</a>", 1);
            //CustomParseLink_NextPageSdau(args, "http://beijing.anjuke.com/prop/view/.*commsearch_p", 0); 
            #endregion
        }
        /// <summary>
        /// The parse links.
        /// 超链接解析
        /// 通用的超链接解析;没有针对特定的超链接解析暴露接口
        /// </summary>
        /// <param name="urlInfo">
        /// The url info.
        /// </param>
        /// <param name="html">
        /// The html.
        /// </param>
        private void ParseLinks(UrlInfo urlInfo, string html)
        {
            //设置参数大于0,并且 url深度 大于等于 设置深度==》同时满足==》退出
            //设置参数小于等于0,或者url深度 小于 设置深度(2)==》执行下面处理
            if (this.Settings.Depth > 0 && urlInfo.Depth >= this.Settings.Depth)
            {
                return;
            }

            var urlDictionary = new Dictionary<string, string>();//<href,text>
            //http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
            Match match = Regex.Match(html, "(?i)<a .*?href=\"([^\"]+)\"[^>]*>(.*?)</a>");//原来的正则表达式"(?i)<a .*?href=\"([^\"]+)\"[^>]*>(.*?)</a>"超链接正则表达式
            while (match.Success)
            {
                // 以 href 作为 key
                string urlKey = match.Groups[1].Value;

                // 以 text 作为 value
                string urlValue = Regex.Replace(match.Groups[2].Value, "(?i)<.*?>", string.Empty);

                urlDictionary[urlKey] = urlValue;
                match = match.NextMatch();//从上一个匹配结束的位置(即在上一个匹配字符之后的字符)开始返回一个包含下一个匹配结果的新
            }
            //至此会得到一个urlDictionary[urlKey] = urlValue;
            //Kiwi:在这里添加自定义处理也不错,url+html==>url
            //至此出现两个问题:1、有些URL不是我们需要的,它们添加进来了
            //                 2、有由JS自动生成的url,这里没有获得,比如page.js,页面接受完数据后,浏览器执行js代码,生成页码条,嵌入到页面上
            //自定义操作,我挖掘html,获得新URL加入到urlDictionary;
            //           urlDictionary删除不必要的URL
            if (CustomParseLinkEvent3 != null)
            {
                CustomParseLinkEvent3Args linkArgs = new CustomParseLinkEvent3Args
                {
                    UrlInfo = urlInfo,
                    UrlDictionary = urlDictionary,
                    Html = html
                };//1、urlInfo原始信息;2、初步解析后的html信息;3、初步解析得到的url集合

                #region 被升级的代码

                //CustomParseLinkEvent2的代码
                //urlDictionary = CustomParseLinkEvent2(new CustomParseLinkEvent2Args
                //{
                //    UrlInfo = urlInfo,
                //    UrlDictionary = urlDictionary,
                //    Html = html
                //});

                #endregion 被升级的代码

                CustomParseLinkEvent3(linkArgs);
                urlDictionary = linkArgs.UrlDictionary;
            }

            foreach (var item in urlDictionary)
            {
                string href = item.Key;
                string text = item.Value;

                if (!string.IsNullOrEmpty(href))
                {
                    bool canBeAdd = true;

                    if (this.Settings.EscapeLinks != null && this.Settings.EscapeLinks.Count > 0)//有忽略链接
                    {                                                             //(suffix:后缀;StringComparison.OrdinalIgnoreCase:忽略大小写,进行比较)
                        if (this.Settings.EscapeLinks.Any(suffix => href.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)))// 确定序列中的任何元素是否都满足条件。
                                                                                                                               //满足条件,不添加;即有满足忽略后缀的超链接,不添加
                        {
                            canBeAdd = false;
                        }
                    }

                    if (this.Settings.HrefKeywords != null && this.Settings.HrefKeywords.Count > 0)//有连接关键词
                    {
                        if (!this.Settings.HrefKeywords.Any(href.Contains))//不包含关键字,不添加。原来关键字这么重要。
                        {
                            canBeAdd = false;
                        }
                    }

                    if (canBeAdd)
                    {
                        string url = href.Replace("%3f", "?")
                            .Replace("%3d", "=")
                            .Replace("%2f", "/")
                            .Replace("&amp;", "&");

                        if (string.IsNullOrEmpty(url) || url.StartsWith("#")
                            || url.StartsWith("mailto:", StringComparison.OrdinalIgnoreCase)
                            || url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        var baseUri = new Uri(urlInfo.UrlString);
                        Uri currentUri = url.StartsWith("http", StringComparison.OrdinalIgnoreCase)
                                             ? new Uri(url)
                                             : new Uri(baseUri, url);//根据指定的基 URI 和相对 URI 字符串,初始化 System.Uri 类的新实例。
                                                                     //如果不包含http,则认为超链接是相对路径,根据baseUrl建立绝对路径

                        url = currentUri.AbsoluteUri;

                        if (this.Settings.LockHost)
                        {
                            // 去除二级域名后,判断域名是否相等,相等则认为是同一个站点
                            // 例如:mail.pzcast.com 和 www.pzcast.com
                            if (baseUri.Host.Split('.').Skip(1).Aggregate((a, b) => a + "." + b)
                                != currentUri.Host.Split('.').Skip(1).Aggregate((a, b) => a + "." + b))
                            {
                                continue;
                            }
                        }

                        if (!this.IsMatchRegular(url))//如果不匹配
                        {
                            continue;
                        }

                        #region addUrlEventArgs

                        var addUrlEventArgs = new AddUrlEventArgs { Title = text, Depth = urlInfo.Depth + 1, Url = url };
                        if (this.AddUrlEvent != null && !this.AddUrlEvent(addUrlEventArgs))
                        {
                            continue;
                        }

                        #endregion addUrlEventArgs

                        //Kiwi:在这里添加一个事件处理自定义的url处理方法最好了

                        //经过上面的一系列处理,决定将url加入队列
                        UrlQueue.Instance.EnQueue(new UrlInfo(url) { Depth = urlInfo.Depth + 1 });
                    }
                }
            }
        }
        /// <summary>
        /// The parse links.
        /// 超链接解析
        /// 通用的超链接解析;没有针对特定的超链接解析暴露接口
        /// </summary>
        /// <param name="urlInfo">
        /// The url info.
        /// </param>
        /// <param name="html">
        /// The html.
        /// </param>
        private void ParseLinks(UrlInfo urlInfo, string html)
        {
            //设置参数大于0,并且 url深度 大于等于 设置深度==》同时满足==》退出
            //设置参数小于等于0,或者url深度 小于 设置深度(2)==》执行下面处理
            if (this.Settings.Depth > 0 && urlInfo.Depth >= this.Settings.Depth)
            {
                return;
            }

            var urlDictionary = new Dictionary <string, string>();                         //<href,text>
            //http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
            Match match = Regex.Match(html, "(?i)<a .*?href=\"([^\"]+)\"[^>]*>(.*?)</a>"); //原来的正则表达式"(?i)<a .*?href=\"([^\"]+)\"[^>]*>(.*?)</a>"超链接正则表达式

            while (match.Success)
            {
                // 以 href 作为 key
                string urlKey = match.Groups[1].Value;

                // 以 text 作为 value
                string urlValue = Regex.Replace(match.Groups[2].Value, "(?i)<.*?>", string.Empty);

                urlDictionary[urlKey] = urlValue;
                match = match.NextMatch();//从上一个匹配结束的位置(即在上一个匹配字符之后的字符)开始返回一个包含下一个匹配结果的新
            }
            //至此会得到一个urlDictionary[urlKey] = urlValue;
            //Kiwi:在这里添加自定义处理也不错,url+html==>url
            //至此出现两个问题:1、有些URL不是我们需要的,它们添加进来了
            //                 2、有由JS自动生成的url,这里没有获得,比如page.js,页面接受完数据后,浏览器执行js代码,生成页码条,嵌入到页面上
            //自定义操作,我挖掘html,获得新URL加入到urlDictionary;
            //           urlDictionary删除不必要的URL
            if (CustomParseLinkEvent3 != null)
            {
                CustomParseLinkEvent3Args linkArgs = new CustomParseLinkEvent3Args
                {
                    UrlInfo       = urlInfo,
                    UrlDictionary = urlDictionary,
                    Html          = html
                };//1、urlInfo原始信息;2、初步解析后的html信息;3、初步解析得到的url集合

                #region 被升级的代码

                //CustomParseLinkEvent2的代码
                //urlDictionary = CustomParseLinkEvent2(new CustomParseLinkEvent2Args
                //{
                //    UrlInfo = urlInfo,
                //    UrlDictionary = urlDictionary,
                //    Html = html
                //});

                #endregion 被升级的代码

                CustomParseLinkEvent3(linkArgs);
                urlDictionary = linkArgs.UrlDictionary;
            }

            foreach (var item in urlDictionary)
            {
                string href = item.Key;
                string text = item.Value;

                if (!string.IsNullOrEmpty(href))
                {
                    bool canBeAdd = true;

                    if (this.Settings.EscapeLinks != null && this.Settings.EscapeLinks.Count > 0)                               //有忽略链接
                    {                                                                                                           //(suffix:后缀;StringComparison.OrdinalIgnoreCase:忽略大小写,进行比较)
                        if (this.Settings.EscapeLinks.Any(suffix => href.EndsWith(suffix, StringComparison.OrdinalIgnoreCase))) // 确定序列中的任何元素是否都满足条件。
                                                                                                                                //满足条件,不添加;即有满足忽略后缀的超链接,不添加
                        {
                            canBeAdd = false;
                        }
                    }

                    if (this.Settings.HrefKeywords != null && this.Settings.HrefKeywords.Count > 0) //有连接关键词
                    {
                        if (!this.Settings.HrefKeywords.Any(href.Contains))                         //不包含关键字,不添加。原来关键字这么重要。
                        {
                            canBeAdd = false;
                        }
                    }

                    if (canBeAdd)
                    {
                        string url = href.Replace("%3f", "?")
                                     .Replace("%3d", "=")
                                     .Replace("%2f", "/")
                                     .Replace("&amp;", "&");

                        if (string.IsNullOrEmpty(url) || url.StartsWith("#") ||
                            url.StartsWith("mailto:", StringComparison.OrdinalIgnoreCase) ||
                            url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        var baseUri    = new Uri(urlInfo.UrlString);
                        Uri currentUri = url.StartsWith("http", StringComparison.OrdinalIgnoreCase)
                                             ? new Uri(url)
                                             : new Uri(baseUri, url); //根据指定的基 URI 和相对 URI 字符串,初始化 System.Uri 类的新实例。
                                                                      //如果不包含http,则认为超链接是相对路径,根据baseUrl建立绝对路径

                        url = currentUri.AbsoluteUri;

                        if (this.Settings.LockHost)
                        {
                            // 去除二级域名后,判断域名是否相等,相等则认为是同一个站点
                            // 例如:mail.pzcast.com 和 www.pzcast.com
                            if (baseUri.Host.Split('.').Skip(1).Aggregate((a, b) => a + "." + b)
                                != currentUri.Host.Split('.').Skip(1).Aggregate((a, b) => a + "." + b))
                            {
                                continue;
                            }
                        }

                        if (!this.IsMatchRegular(url))//如果不匹配
                        {
                            continue;
                        }

                        #region addUrlEventArgs

                        var addUrlEventArgs = new AddUrlEventArgs {
                            Title = text, Depth = urlInfo.Depth + 1, Url = url
                        };
                        if (this.AddUrlEvent != null && !this.AddUrlEvent(addUrlEventArgs))
                        {
                            continue;
                        }

                        #endregion addUrlEventArgs

                        //Kiwi:在这里添加一个事件处理自定义的url处理方法最好了

                        //经过上面的一系列处理,决定将url加入队列
                        UrlQueue.Instance.EnQueue(new UrlInfo(url)
                        {
                            Depth = urlInfo.Depth + 1
                        });
                    }
                }
            }
        }