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