【问题标题】:Get just the domain name from a URL?仅从 URL 获取域名?
【发布时间】:2011-01-10 09:11:00
【问题描述】:

我正在尝试仅从 URL 字符串中提取域名。我几乎拥有它...我正在使用 URI

我有一个字符串.. 我的第一个想法是使用正则表达式,但后来我决定使用 URI 类

http://www.google.com/url?sa=t&source=web&ct=res&cd=1&ved=0CAgQFjAA&url=http://www.test.com/&rct=j&q=test&ei=G2phS-HdJJWTjAfckvHJDA&usg=AFQjCNFSEAztaqtkaIvEzxmRm2uOARn1kQ

我需要将以上内容转换为没有 www 的 google.com 和 google

我做了以下

Uri test = new Uri(referrer);
log.Info("Domain part : " + test.Host);

基本上这会返回 www.google.com ...。如果可能的话,我想尝试返回 2 个表单...如前所述...

google.com 和谷歌

URI 可以吗?

【问题讨论】:

  • 'foo.bar.com' 的结果应该是什么? 'foo.co.uk' 呢? 'foo.bar.museum' 呢?
  • 嗨,马克......基本上我是在纯域名之后......所以如果它以 ww3.test.co.uk 开头,那么它应该返回 test.co.uk 因为这是纯域 .... 所以在你的例子中 foo.co.uk 应该返回 foo.co.uk 因为这是纯域 .... 并且 foo.bar.museum 会返回 bar.museum 但是。博物馆不是.com、co.uk、.us 等有效的顶级域名吗? ...
  • .museum、.mobi 和 .travel 是完全有效的顶级域名。您能否澄清一下,为什么 ww3 不是“纯”域名的一部分,而 foo 是? 您的对纯域名的定义是什么?
  • 马克,也许你应该解释一下你的目标是什么?
  • 这绝对是一个有效的请求。我正在尝试删除大约 40,000 个域名的列表并进入“纯”域部分。通常域的前缀部分会导致后端功能。我们试图提供一个公共域供用户导航,这通常是后一部分。我很惊讶这从来没有得到回答!

标签: c# uri


【解决方案1】:

我为自己找到了一个解决方案,但没有使用任何 TLD 或其他东西。

它使用了这样一个事实,即所谓的主机名位于 Uri 的主机部分中,始终位于倒数第二个位置。子域始终在名称前面,TLD 始终在其后面。

看这里:

private static string GetNameFromHost(string host)
{
    if (host.Count(f => f == '.') == 1)
    {
        return host.Split('.')[0];
    }
    else
    {
        var _list = host.Split('.').ToList();
        return _list.ElementAt(_list.Count - 2);
    }
}

【讨论】:

    【解决方案2】:

    我想出了以下解决方案(使用 Linq):

        public string MainDomainFromHost(string host)
        {
            string[] parts = host.Split('.');
            if (parts.Length <= 2)
                return host; // host is probably already a main domain
            if (parts[parts.Length - 1].All(char.IsNumber))
                return host; // host is probably an IPV4 address
            if (parts[parts.Length - 1].Length == 2 && parts[parts.Length - 2].Length == 2)
                return string.Join(".", parts.TakeLast(3)); // this is the case for co.uk, co.in, etc...
            return string.Join(".", parts.TakeLast(2)); // all others, take only the last 2
        }
    

    【讨论】:

      【解决方案3】:

      使用 Nager.PublicSuffix

      安装包 Nager.PublicSuffix

      var domainParser = new DomainParser(new WebTldRuleProvider());
      
      var domainName = domainParser.Get("sub.test.co.uk");
      //domainName.Domain = "test";
      //domainName.Hostname = "sub.test.co.uk";
      //domainName.RegistrableDomain = "test.co.uk";
      //domainName.SubDomain = "sub";
      //domainName.TLD = "co.uk";
      

      【讨论】:

        【解决方案4】:

        我几乎尝试了所有方法,但都没有达到预期的效果。 所以这是我从 servermanfail 调整的方法。

        tld 文件在https://publicsuffix.org/list/ 上可用 我已从https://publicsuffix.org/list/effective_tld_names.dat 获取文件并对其进行解析并搜索 tld。如果发布了新的 tld,只需下载最新文件即可。

        玩得开心。

        using System;
        using System.Collections.Generic;
        using System.IO;
        
        namespace SearchWebsite
        {
        internal class NetDomain
        {
            static public string GetDomainFromUrl(string Url)
            {
                return GetDomainFromUrl(new Uri(Url));
            }
        
            static public string GetDomainFromUrl(string Url, bool Strict)
            {
                return GetDomainFromUrl(new Uri(Url), Strict);
            }
        
            static public string GetDomainFromUrl(Uri Url)
            {
                return GetDomainFromUrl(Url, false);
            }
        
            static public string GetDomainFromUrl(Uri Url, bool Strict)
            {
                initializeTLD();
                if (Url == null) return null;
                var dotBits = Url.Host.Split('.');
                if (dotBits.Length == 1) return Url.Host; //eg http://localhost/blah.php = "localhost"
                if (dotBits.Length == 2) return Url.Host; //eg http://blah.co/blah.php = "localhost"
                string bestMatch = "";
                foreach (var tld in DOMAINS)
                {
                    if (Url.Host.EndsWith(tld, StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (tld.Length > bestMatch.Length) bestMatch = tld;
                    }
                }
                if (string.IsNullOrEmpty(bestMatch))
                    return Url.Host; //eg http://domain.com/blah = "domain.com"
        
                //add the domain name onto tld
                string[] bestBits = bestMatch.Split('.');
                string[] inputBits = Url.Host.Split('.');
                int getLastBits = bestBits.Length + 1;
                bestMatch = "";
                for (int c = inputBits.Length - getLastBits; c < inputBits.Length; c++)
                {
                    if (bestMatch.Length > 0) bestMatch += ".";
                    bestMatch += inputBits[c];
                }
                return bestMatch;
            }
        
        
            static private void initializeTLD()
            {
                if (DOMAINS.Count > 0) return;
        
                string line;
                StreamReader reader = File.OpenText("effective_tld_names.dat");
                while ((line = reader.ReadLine()) != null)
                {
                    if (!string.IsNullOrEmpty(line) && !line.StartsWith("//"))
                    {
                        DOMAINS.Add(line);
                    }
                }
                reader.Close();
            }
        
        
            // This file was taken from https://publicsuffix.org/list/effective_tld_names.dat
        
            static public List<String> DOMAINS = new List<String>();
        }
        

        }

        【讨论】:

        • 我已经使用了您的解决方案,它运行良好,直到我发现了一些错误。例如www.navistar.com 不会剥离www 部分。这是修复if (!url.Host.EndsWith("." + tld, StringComparison.InvariantCultureIgnoreCase)) continue;
        【解决方案5】:

        Uri 的主机始终返回域 (www.google.com),包括标签 (www) 和顶级域 (com)。但通常你会想要提取中间位。我就是这么做的

        Uri uri;
        bool result = Uri.TryCreate(returnUri, UriKind.Absolute, out uri);
        if (result == false)
            return false;
        
        //if you are sure it's not "localhost"
        string domainParts = uri.Host.Split('.');
        string topLevel = domainParts[domainParts.Length - 1]
        string hostBody = domainParts[domainParts.Length - 2]
        string label = domainParts[domainParts.Length - 3]
        

        但您确实需要检查 domainParts.length,因为给定的 uri 通常类似于“google.com”。

        【讨论】:

          【解决方案6】:
          string domain = new Uri(HttpContext.Current.Request.Url.AbsoluteUri).GetLeftPart(UriPartial.Authority);
          

          【讨论】:

            【解决方案7】:

            下面是一些仅提供 SLD 加 gTLD 或 ccTLD 扩展名的代码(请注意下面的例外情况)。我不关心 DNS。

            理论如下:

            • 3 个令牌以下的任何内容都保持原样,例如“localhost”、“domain.com”,否则:最后一个令牌必须是 gTLD 或 ccTLD 扩展名。
            • 如果倒数第二个标记的长度
            • 最后,那个之前的令牌被认为是 SLD。在此之前的任何内容都被视为子域或主机限定符,例如万维网。

            至于代码,短小精悍:

            private static string GetDomainName(string url)
            {
                string domain = new Uri(url).DnsSafeHost.ToLower();
                var tokens = domain.Split('.');
                if (tokens.Length > 2)
                {
                    //Add only second level exceptions to the < 3 rule here
                    string[] exceptions = { "info", "firm", "name", "com", "biz", "gen", "ltd", "web", "net", "pro", "org" }; 
                    var validTokens = 2 + ((tokens[tokens.Length - 2].Length < 3 || exceptions.Contains(tokens[tokens.Length - 2])) ? 1 : 0);
                    domain = string.Join(".", tokens, tokens.Length - validTokens, validTokens);
                }
                return domain;
            }
            

            明显的例外是这不会处理 2 个字母的域名。因此,如果您有幸拥有 ab.com,则需要稍微修改代码。对于我们这些普通人来说,这段代码将涵盖几乎所有 gTLD 和 ccTLD,减去一些非常奇特的代码。

            【讨论】:

              【解决方案8】:

              是的,我在这里发布了解决方案:http://pastebin.com/raw.php?i=raxNQkCF

              如果你想删除扩展,只需添加

              if (url.indexof(".")&gt;-1) {url = url.substring(0, url.indexof("."))}

              【讨论】:

                【解决方案9】:

                @Dewfy:缺陷是您的方法为“www.test.co.uk”返回“uk”,但这里的域显然是“test.co.uk”。

                @naivists:缺陷是您的方法为“www.beta.microsoft.com”返回“beta.microsoft.com”,但这里的域显然是“microsoft.com”

                我也需要,所以我编写了一个类,您可以将其复制并粘贴到您的解决方案中。它使用 tld 的硬编码字符串数组。 http://pastebin.com/raw.php?i=VY3DCNhp

                Console.WriteLine(GetDomain.GetDomainFromUrl("http://www.beta.microsoft.com/path/page.htm"));
                

                输出microsoft.com

                Console.WriteLine(GetDomain.GetDomainFromUrl("http://www.beta.microsoft.co.uk/path/page.htm"));
                

                输出microsoft.co.uk

                【讨论】:

                • 请注意,pastebin 类实际上并未将 .org.uk、.co.uk 或 .ac.uk 添加到 TLD 列表中。所以巧合的是,上面的例子在你添加它们之前实际上并不能工作。
                • @servermanfail,感谢您提供的出色代码。正是我需要的!
                • 当今年晚些时候和明年有数百个新 gTLD 可用时,这将不再有效......除非有人手动添加它们。
                • 糟糕的解决方案,完全避免它。
                【解决方案10】:

                由于域名的众多变化以及不存在任何构成您所描述的“纯域名”的真正权威列表,我过去只是求助于使用 Uri.Host。为了避免 www.google.com 和 google.com 显示为两个不同的域的情况,我经常求助于剥离 www。来自包含它的所有域,因为几乎可以保证(几乎)指向同一个站点。这确实是唯一一种不冒丢失数据风险的简单方法。

                【讨论】:

                  【解决方案11】:

                  我认为您对“域名”的构成存在误解 - 没有常用的“纯域名”之类的东西 - 如果您想要一致的结果,您需要定义它。 你只是想去掉“www”部分吗? 然后有另一个版本剥离顶级域(例如剥离“.com”或“.co.uk”等部分?) 另一个答案提到 split(".") - 如果您想手动排除主机名的特定部分,您将需要使用类似的东西,.NET 框架中没有任何内容可以完全满足您的要求 - 您需要实现这些自己做事。

                  【讨论】:

                    【解决方案12】:

                    google.com 不保证与 www.google.com 相同(好吧,对于本示例,它在技术上是相同的,但可能并非如此)。

                    也许您实际上需要的是删除“顶级”域和“www”子域?然后只需split('.') 并在最后一部分之前参加!

                    【讨论】:

                    • “google.com 不保证与 www.google.com 相同”——事实上它并不相同 :)
                    • 天哪,真的。 www.google.com=209.85.129.104, google.com=209.85.129.147 :-)
                    • naivists : 域相同,服务器根据请求保留负载平衡 IP
                    【解决方案13】:

                    是的,可以使用:

                    Uri.GetLeftPart( UriPartial.Authority )
                    

                    【讨论】:

                    • 感谢 Dewfy,但这实际上返回 google.com .. 因此 http:// 和 www 这是我不需要的
                    • 我实际上让它在没有 http:// 的情况下返回相同的结果,但它有 www... 使用 Uri.Host
                    • 你读过这个问题吗?这将返回 httр://www.google.com
                    • Answer 不返回 OP 请求的内容。不知道为什么它有这么多的赞成票。
                    • @T.S 因为如果谷歌把我带到这里,它回答了我的问题,我赞成。我不在乎(甚至经常不阅读)原始问题。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-04-08
                    • 2014-11-14
                    • 2010-10-08
                    • 2012-03-25
                    相关资源
                    最近更新 更多