C#中获取URL的顶级域名

16

我正在使用C#和ASP.NET。

我们的IIS 6.0服务器收到很多“奇怪”的请求,我想按域名记录并分类这些请求。

例如,我们会得到以下一些奇怪的请求:

后三个比较明显,但我想将它们全部归为“example.com”,因为其托管在我们的服务器上。其他的不是,抱歉:-)

所以我正在寻找一些好主意来从上面检索出“example.com”。其次,我想将m.、wap.、iphone等匹配成一组,但那可能只是在移动设备快捷方式列表中进行快速查找。我可以手动编写这个列表。

但是,这里是正则表达式的答案,还是纯字符串操作最容易?我想“拆分”URL字符串并查找item[0]和item[1]...

有什么想法吗?


我还需要一个适用于.co.uk类型域名的解决方案... - Kurru
我认为你应该先检测它是否是.co.uk,然后针对这种情况进行特殊处理。并不是每个国家都有类似的“顶级/次级”域名。因此,我首先选择“顶级”域名,然后再进行排序。 - BerggreenDK
7个回答

23

您可以使用以下NuGetNager.PublicSuffix包。它使用与浏览器供应商相同的数据源。

NuGet

PM> Install-Package Nager.PublicSuffix

例子

var domainParser = new DomainParser(new WebTldRuleProvider());

var domainInfo = domainParser.Parse("sub.test.co.uk");
//domainInfo.Domain = "test";
//domainInfo.Hostname = "sub.test.co.uk";
//domainInfo.RegistrableDomain = "test.co.uk";
//domainInfo.SubDomain = "sub";
//domainInfo.TLD = "co.uk";

谢谢,这正是我正在寻找的。 - Ege Aydın
6
这是唯一正确的方法;该程序包下载并缓存由https://publicsuffix.org/维护和策划的后缀列表,这也是浏览器供应商使用的相同列表。 - Martijn Pieters

12
以下代码使用 Uri 类来获取主机名,然后通过在句点上拆分主机名从 Uri.Host 中获取第二级主机(examplecompany.com)。
var uri = new Uri("http://www.poker.winner4ever.examplecompany.com/");
var splitHostName = uri.Host.Split('.');
if (splitHostName.Length >= 2)
{
    var secondLevelHostName = splitHostName[splitHostName.Length - 2] + "." +
                              splitHostName[splitHostName.Length - 1];
}

16
这可能适合于楼主的需求,但并不适用于所有领域。例如,http://www.google.co.uk/或http://www.bbc.co.uk/的主机名应为“co.uk”。 - LukeH
2
@LukeH:非常好的观点。我只是考虑到了楼主的需求,国家代码顶级域名甚至没有在我的脑海中浮现出来 :-/ - Phil Hunt
@LukeH - OP已经明确说明了他感兴趣的域名,因此似乎他并不是在寻找适用于任何TLD的通用解决方案 - 他说“'examplecompany.com'托管在我们的服务器上”。在一般情况下使用正则表达式匹配TLD实际上非常困难且充满陷阱。 - Mike Chamberlain
我得到了一个很长的奇怪URL的日志文件 - 我事先不知道传入的URL。因此,我不能在字符串上使用一些“indexOf”,因为我们还收到了针对不存在、从未存在过、已经存在的域名的查询。有时候我觉得人们只是为了好玩而错误地将他们的IP指向我们的服务器...但我又怎么知道呢。 - BerggreenDK
@LukeH:我知道这个“问题”,但如果我可以解决域名的问题,我会在特殊情况下处理co.uk。因此,如果我将其拆分,我会得到“domain.tld”- 我可以制作一个“麻烦列表”,列出“co.uk”等,如果匹配,则添加一个额外的级别。我想这可能是唯一的处理方法。 - BerggreenDK

9

可能有一些例子返回的结果与期望不同,但国家代码是唯一的仅有2个字符的代码,它们可能具有短的第二级(通常使用2或3个字符)。因此,在大多数情况下,这将给您想要的结果:

string GetRootDomain(string host)
{
    string[] domains = host.Split('.');

    if (domains.Length >= 3)
    {
        int c = domains.Length;
        // handle international country code TLDs 
        // www.amazon.co.uk => amazon.co.uk
        if (domains[c - 1].Length < 3 && domains[c - 2].Length <= 3)
            return string.Join(".", domains, c - 3, 3);
        else
            return string.Join(".", domains, c - 2, 2);
    }
    else
        return host;
}

实际上应该为 gmp.police.uk 提供 "police.uk",因为 "police" 长度超过 3 个字符。 - Garr Godfrey
啊,那错了。域名是'police.uk',主机是'gmp'。另一个例子是:devon-cornwall.police.uk。 - meh-uk
非常好的中间解决方案 - Dirk Boer

4

如果没有最新的不同域级别数据库,这是不可能完成的。

请考虑:

s1.moh.gov.cn
moh.gov.cn
s1.google.com
google.com

那么您想要获得哪个级别的域名?这完全取决于顶级域名(TLD)、二级域名(SLD)、国家代码顶级域名(ccTLD)等,因为ccTLD受国家控制,他们可能定义了对您来说不知道的非常特殊的SLD


我同意,但我仍然希望能够对我们的传入流量进行排序。 - BerggreenDK
那时我建议使用普通的 TLD 格式并牺牲罕见的 ccTLD 域名。那样其他答案会更有帮助。 - Xaqron
gov.cn是s1.moh.gov.cn中的顶级域名,你认为呢? - Toolkit

2
我写了一个用于.NET 2+的,以帮助提取URL的域组件。
更多细节可以在Github上找到,但与以前的选项相比,其中一个好处是它可以自动从http://publicsuffix.org下载最新数据(每月一次),因此该库的输出应该与Web浏览器用于建立域安全边界的输出大致相同(即相当不错)。
它还不完美,但适合我的需求,并且应该不需要太多工作就能适应其他用例,请分叉并发送拉取请求。

你在库中考虑过新的顶级域名吗? - BerggreenDK
1
是的。由于该库是基于publicsuffix.org的数据构建的,因此在像Firefox和Chrome这样的浏览器的夜间版本中添加支持后,将在一个月内支持新的顶级域名。您可以通过在一个月内公共后缀数据库过期之前删除缓存副本来加快此过程,但这仅在开发先于新后缀的主流支持的软件时才有用。 - Luckyrat

1
使用正则表达式:
^https?://([\w./]+[^.])?\.?(\w+\.(com)|(co.uk)|(com.au))$

这将匹配任何以你感兴趣的顶级域名结尾的URL。可以根据需要扩展列表。此外,捕获组将分别包含子域、主机名和顶级域名。


1
嗯,这不需要我先知道这两个域是什么吗? - BerggreenDK
对于一般情况,您需要完整的规则列表,了解每个国家如何组织其域名。有些国家我们很熟悉(例如,我们知道在.com或.co.uk之前的任何内容都是网站名称),但罗马尼亚是如何做的呢?例如,在URL something.com.ro中,网站称为“com”,子域名称为“something”吗?还是罗马尼亚使用"com.ro"作为商业网站的顶级域名?我不知道,但我相信如果您想正确地完成这项工作,您将需要这种信息。 - Mike Chamberlain
4
Mozilla基金会已经列出了这些顶级域名(TLD)的(可能不完全)清单:http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1。 - Mike Chamberlain
谢谢你提供的链接,我能看懂你的观点。但是目前这仅是我们自己服务器上的一个脚本,我们知道我们托管的顶级域名类型并不多。问题更多的是当我们收到大量“奇怪的URL映射”到我们的域名时 - 我们希望能够检索并对其进行分类以便轻松查看。但还是非常感谢你提供的TLD链接。我也会去查一下它。也许可以从那个页面构建某种导入功能。 - BerggreenDK
@Mikey Cee,好链接。之前在Google Guava库中找到了一个用于确定TLD的模式列表,并将其翻译成了XML格式。这是它的链接:https://docs.google.com/file/d/0B8ALaar6dLM7ZUc2MUtidVE4RXM/edit?usp=sharing - Unicorn

0
uri.Host.ToLower().Replace("www.","").Substring(uri.Host.ToLower().Replace("www.","").IndexOf('.'))
  • 对于 Uri uri = new Uri("https://dev59.com/a2445IYBdhLWcg3w6eNo"); 返回 ".com"

  • 对于 Uri uri = new Uri("http://stackoverflow.co.jp"); 返回 ".co.jp"

  • 对于 Uri uri = new Uri("http://stackoverflow.s1.moh.gov.cn"); 返回 ".s1.moh.gov.cn"

等等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接