从URL获取子域名

从url获取子域名首先听起来很简单。

http://www.domain.example 

扫描第一个时间段,然后返回“http://”后面的内容…

那你还记得

 http://super.duper.domain.example 

哦。 那么你认为,好吧,find最后一个时期,回去一句话,把所有东西都拿出来!

那你还记得

 http://super.duper.domain.co.uk 

而你又回到了原点。 除了存储所有顶级域名列表之外,任何人都有什么好的想法?

除了存储所有顶级域名列表之外,任何人都有什么好的想法?

不,因为每个顶级域名在子域,二级域名等方面都有所不同

请记住,有顶级域名,二级域名和子域名。 从技术上讲,除了TLD以外的所有东西都是一个子域。

在domain.com.uk的例子中,domain是一个子域,com是二级域,而uk是tld。

所以这个问题比起初看起来要复杂得多,这取决于每个TLD是如何pipe理的。 您需要一个包含其特定分区的所有顶级域名的数据库,以及作为二级域名和子域名的数据。 虽然没有太多的顶级域名,所以名单可以合理pipe理,但收集所有的信息并不是微不足道的。 可能已经有这样的列表可用。

看起来像http://publicsuffix.org/是一个这样的列表; – 所有常见的后缀(.com,.co.uk等)在一个列表适合search。 parsing它仍然不是一件容易的事情,但至less你不必维护这个列表。

“公共后缀”是网民可以直接注册的名字。 公共后缀的一些例子是“.com”,“.co.uk”和“pvt.k12.wy.us”。 公共后缀列表是所有已知公共后缀的列表。

公共后缀列表是Mozilla基金会的一项举措。 它可用于任何软件,但最初是为了满足浏览器制造商的需求而创build的。 它允许浏览器,例如:

  • 避免为高级别域名后缀设置隐私破坏性的“supercookies”
  • 在用户界面中突出显示域名中最重要的部分
  • 按网站准确排列历史logging

通过列表看 ,你可以看到这不是一个微不足道的问题。 我认为列表是唯一正确的方法来完成这个…

-亚当

正如亚当所说,这并不容易,而目前唯一可行的方法是使用一个列表。

即使这样,也有例外的情况 – 例如在.uk ,有一些在这个层次上立即生效的不在.co.uk的域名,所以这些域名必须被添加为例外。

这是目前主stream浏览器如何做到这一点 – 有必要确保example.co.uk不能为.co.uk设置Cookie,然后将其发送到.co.uk下的任何其他网站。

好消息是在http://publicsuffix.org/上已经有一个列表。;

IETF还有一些工作要制定某种标准,允许顶级域名声明他们的域名结构。 虽然像.uk.com这样的操作稍微复杂一些,但它是以公共后缀的forms运行的,但不是由.com注册机构出售的。

Publicsuffix.org似乎是要做的。 有很多实现可以轻松parsingpublicsuffix数据文件的内容:

  • Perl: Domain :: PublicSuffix
  • Java: http : //sourceforge.net/projects/publicsuffix/
  • PHP: php-domain-parser
  • C#/ .NET: https : //github.com/danesparza/domainname-parser
  • Python: http : //pypi.python.org/pypi/publicsuffix
  • Ruby: domainatrix , public_suffix

正如亚当和约翰所说的publicsuffix.org是正确的路要走。 但是,如果出于任何原因,你不能使用这种方法,这里的启发式基于一个假设,适用于99%的所有领域:

有一个属性可以区分(不是全部,但几乎全部)“子域名”和“顶级域名”的“真实”域名,也就是DNS的MXlogging。 您可以创build一个search此algorithm的algorithm:逐个删除主机名的部分,然后查询DNS,直到findMXlogging。 例:

 super.duper.domain.co.uk => no MX record, proceed duper.domain.co.uk => no MX record, proceed domain.co.uk => MX record found! assume that's the domain 

这里是一个例子在PHP中:

 function getDomainWithMX($url) { //parse hostname from URL //http://www.example.co.uk/index.php => www.example.co.uk $urlParts = parse_url($url); if ($urlParts === false || empty($urlParts["host"])) throw new InvalidArgumentException("Malformed URL"); //find first partial name with MX record $hostnameParts = explode(".", $urlParts["host"]); do { $hostname = implode(".", $hostnameParts); if (checkdnsrr($hostname, "MX")) return $hostname; } while (array_shift($hostnameParts) !== null); throw new DomainException("No MX record found"); } 

刚刚根据publicsuffix.org的信息为clojure写了一个程序:

https://github.com/isaksky/url_dom

例如:

 (parse "sub1.sub2.domain.co.uk") ;=> {:public-suffix "co.uk", :domain "domain.co.uk", :rule-used "*.uk"} 

对于C库(使用Python生成数据表),我写了http://code.google.com/p/domain-registry-provider/ ,它既快速又节省空间。

该库使用约30kB的数据表和约10kB的C代码。 由于在编译时构造表,所以没有启动开销。 有关更多详细信息,请参阅http://code.google.com/p/domain-registry-provider/wiki/DesignDoc

为了更好地理解表生成代码(Python),请从这里开始: http : //code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

要更好地理解C API,请参阅: http : //code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h

正如前面所说的公共后缀列表只是正确parsing域的一种方法。 对于PHP,您可以尝试TLDExtract 。 这里是示例代码:

 $extract = new LayerShifter\TLDExtract\Extract(); $result = $extract->parse('super.duper.domain.co.uk'); $result->getSubdomain(); // will return (string) 'super.duper' $result->getSubdomains(); // will return (array) ['super', 'duper'] $result->getHostname(); // will return (string) 'domain' $result->getSuffix(); // will return (string) 'co.uk' 

这不是完全正确的,但你也许可以得到一个有用的答案,试图一块一块地取出域,并检查响应,即获取“ http:// uk ”,然后“ http://co.uk ” ,然后是“ http://domain.co.uk ”。 当你得到一个非错误的答复,你有域名,其余的是子域名。

有时你只能尝试一下 🙂

编辑:

Tom Leys在评论中指出,某些域名只能在www子域名上设置,这会在上面的testing中给我们一个不正确的答案。 好点子! 也许最好的办法是用' http:// www '和'http://'来检查每个部分,并计算一个命中作为该域名的该部分的命中? 我们仍然会错过一些'替代'的安排,如“web.domain.com”,但我没有遇到过一段时间:)

使用URIBuilder,然后获取URIBUilder.host属性,将其分成“。”数组。 你现在有一个数组与域拆分。

 echo tld('http://www.example.co.uk/test?123'); // co.uk /** * http://publicsuffix.org/ * http://www.alandix.com/blog/code/public-suffix/ * http://tobyinkster.co.uk/blog/2007/07/19/php-domain-class/ */ function tld($url_or_domain = null) { $domain = $url_or_domain ?: $_SERVER['HTTP_HOST']; preg_match('/^[az]+:\/\//i', $domain) and $domain = parse_url($domain, PHP_URL_HOST); $domain = mb_strtolower($domain, 'UTF-8'); if (strpos($domain, '.') === false) return null; $url = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1'; if (($rules = file($url)) !== false) { $rules = array_filter(array_map('trim', $rules)); array_walk($rules, function($v, $k) use(&$rules) { if (strpos($v, '//') !== false) unset($rules[$k]); }); $segments = ''; foreach (array_reverse(explode('.', $domain)) as $s) { $wildcard = rtrim('*.'.$segments, '.'); $segments = rtrim($s.'.'.$segments, '.'); if (in_array('!'.$segments, $rules)) { $tld = substr($wildcard, 2); break; } elseif (in_array($wildcard, $rules) or in_array($segments, $rules)) { $tld = $segments; } } if (isset($tld)) return $tld; } return false; } 

我刚刚写了一个objc库: https : //github.com/kejinlu/KKDomain

您可以使用这个lib tld.js:JavaScript API来处理复杂的域名,子域和URI。

 tldjs.getDomain('mail.google.co.uk'); // -> 'google.co.uk' 

如果您在浏览器中获取根域。 你可以使用这个lib AngusFu / browser-root-domain 。

 var KEY = '__rT_dM__' + (+new Date()); var R = new RegExp('(^|;)\\s*' + KEY + '=1'); var Y1970 = (new Date(0)).toUTCString(); module.exports = function getRootDomain() { var domain = document.domain || location.hostname; var list = domain.split('.'); var len = list.length; var temp = ''; var temp2 = ''; while (len--) { temp = list.slice(len).join('.'); temp2 = KEY + '=1;domain=.' + temp; // try to set cookie document.cookie = temp2; if (R.test(document.cookie)) { // clear document.cookie = temp2 + ';expires=' + Y1970; return temp; } } }; 

使用cookie是棘手的。

常见后缀列表(.co.uk,.com,等等)与http://一起去掉,然后你将只有“sub.domain”来处理而不是“ http:// sub”。域名.suffix “,或者至less这是我可能做的。

最大的问题是可能的后缀列表。 毕竟有很多东西。

仔细看一下publicsuffix.org列表,看起来你可以通过从最后一个段是两个字符的域去掉最后三个段(这里的“段”,这意味着两个点之间的段)来做出合理的近似,假设它是一个国家代码,并将进一步细分。 如果最后一段是“我们”,倒数第二段也是两个字符,则删除最后四段。 在所有其他情况下,删除最后两个部分。 例如:

  • HTTP://www.domain.example

“example”不是两个字符,所以删除“domain.example”,留下“www”

  • HTTP://super.duper.domain.example

“example”不是两个字符,所以删除“domain.example”,留下“super.duper”

“英国”是两个字符(但不是“我们”),所以删除“domain.co.uk”,留下“super.duper”

“我们”是两个字符,是“我们”,再加上“wy”也是两个字符,所以删除“pvt.k12.wy.us”,留下“foo”。

请注意,虽然这对我迄今为止在响应中看到的所有示例都有效,但它仍然只是一个合理的近似值。 这是不完全正确的,虽然我怀疑它是关于你可能得到的,而没有得到一个实际列表供参考。