首先,从URL获取子域听起来很容易。
http://www.domain.example
扫描第一个期间,然后返回“ http://”之后的内容...
那你就记得
http://super.duper.domain.example
哦。因此,您会认为,好吧,找到最后一个时期,再说一句话,然后才得到所有东西!
那你就记得
http://super.duper.domain.co.uk
然后您回到正题。除了存储所有TLD列表之外,还有其他好主意吗?
首先,从URL获取子域听起来很容易。
http://www.domain.example
扫描第一个期间,然后返回“ http://”之后的内容...
那你就记得
http://super.duper.domain.example
哦。因此,您会认为,好吧,找到最后一个时期,再说一句话,然后才得到所有东西!
那你就记得
http://super.duper.domain.co.uk
然后您回到正题。除了存储所有TLD列表之外,还有其他好主意吗?
Answers:
除了存储所有TLD列表之外,还有其他好主意吗?
否,因为每个顶级域名(TLD)的不同之处在于子域名,二级域名等。
请记住,存在顶级域,第二级域和子域。从技术上讲,除TLD之外的所有内容都是一个子域。
在domain.com.uk示例中,“ domain”是子域,“ com”是第二级域,“ uk”是TLD。
因此,这个问题仍然比刚开始时更为复杂,这取决于如何管理每个TLD。您将需要一个包含所有TLD的数据库,其中包括它们的特定分区,以及属于第二级域和子域的内容。但是,由于TLD数量不多,因此该列表可合理管理,但是收集所有这些信息并非易事。可能已经有这样一个列表。
看起来http://publicsuffix.org/就是这样的列表-适合搜索的列表中的所有常见后缀(.com,.co.uk等)。解析它仍然不容易,但是至少您不必维护列表。
“公共后缀”是Internet用户可以直接注册名称的后缀。公共后缀的一些示例是“ .com”,“。co.uk”和“ pvt.k12.wy.us”。公共后缀列表是所有已知公共后缀的列表。
公共后缀列表是Mozilla基金会的一项倡议。它可以在任何软件中使用,但最初是为了满足浏览器制造商的需求而创建的。它允许浏览器执行以下操作:
- 避免为高级域名后缀设置破坏隐私的“ supercookies”
- 在用户界面中突出显示域名中最重要的部分
- 按站点准确分类历史记录条目
浏览列表,您会发现这不是一个小问题。我认为列表是完成此操作的唯一正确方法。
正如亚当所说,这并不容易,目前唯一可行的方法是使用列表。
即便如此,也存在例外-例如,.uk
有少数不在该级别上立即生效的域,不在中.co.uk
,因此必须将其添加为例外。
当前,这是主流浏览器的操作方式-必须确保example.co.uk
无法设置Cookie,.co.uk
然后该Cookie 会被发送到下的任何其他网站.co.uk
。
好消息是,http://publicsuffix.org/上已经有一个列表。
IETF中也有一些工作来创建某种标准,以允许TLD声明其域结构。尽管由于的.uk.com
类似,这有些复杂,但操作起来好像是一个公共后缀,但没有被.com
注册表出售。
.uk
域注册表现在允许直接在第二级进行注册。相应地,这反映在PSL中。
Publicsuffix.org似乎是可行的方法。有很多实现可以轻松解析publicsuffix数据文件文件的内容:
正如亚当和约翰所说,publicsuffix.org是正确的方法。但是,如果由于某种原因您无法使用此方法,以下是一种启发式假设,该假设适用于所有域的99%:
有一个属性可以区分(不是全部,但几乎是全部)“真实”域与子域和TLD,这就是DNS的MX记录。您可以创建一种搜索算法:逐个删除主机名的各个部分,并查询DNS,直到找到MX记录。例:
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");
}
.ai
或.ax
只是仅举几例)。
如前所述,公共后缀列表只是正确解析域的一种方法。对于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'
刚刚根据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
它不能完全解决问题,但是您可以尝试通过逐段获取域并检查响应来获得有用的答案,即先获取“ http:// uk ”,然后获取“ http://co.uk ” ,然后是“ http://domain.co.uk ”。当您收到一个非错误的响应时,您就拥有了域,其余的是子域。
有时候,您只需要尝试一下 :)
编辑:
汤姆·莱伊斯(Tom Leys)在评论中指出,某些域仅在www子域上设置,这在上面的测试中给了我们错误的答案。好点子!也许最好的方法是用“ http:// www ”和“ http://” 来检查每个部分,并将命中点算为该域名的命中点?我们仍然会错过一些“替代”安排,例如“ web.domain.com”,但是我有一段时间没有碰到其中一种了:)
.DK
其他人工作,而是按原样http://dk/
工作。这种启发式方法不是走的路...
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('/^[a-z]+:\/\//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是棘手的。
如果您要从任意URL列表中提取子域和/或域,则此python脚本可能会有所帮助。但是要小心,这并不完美。通常,这是一个棘手的问题,如果您有一个期望的域名白名单,这将非常有帮助。
汇入要求 url ='https://publicsuffix.org/list/public_suffix_list.dat' 页面= requests.get(URL) 域= [] 用于page.text.splitlines()中的行: 如果line.startswith('//'): 继续 其他: 域= line.strip() 如果域: domains.append(domain) 域= [d [2:],如果d.startswith('*。'),否则d表示d在域中] print('found {} domains'.format(len(domains)))
汇入 _regex ='' 对于域中的域: _regex + = r'{} |'.format(domain.replace('。','\。')) subdomain_regex = r'/([[^/]*)\.[^/.]+\.({})/.*$'。format(_regex) domain_regex = r'([[^ /。] + \。({}))/.*$'。format(_regex)
FILE_NAME =''#将CSV文件名放在此处 URL_COLNAME =''#将URL列名称放在此处 将熊猫作为pd导入 df = pd.read_csv(FILE_NAME) urls = df [URL_COLNAME] .astype(str)+'/'#注意:添加/作为黑客来帮助正则表达式 df ['sub_domain_extracted'] = urls.str.extract(pat = subdomain_regex,expand = True)[0] df ['domain_extracted'] = urls.str.extract(pat = domain_regex,expand = True)[0] df.to_csv('extracted_domains.csv',index = False)
要与http://一起删除的常见后缀(.co.uk,.com等)列表,则只有“ sub.domain”可以使用,而不是“ http:// sub”。 domain.suffix ”,或者至少这就是我可能要做的。
最大的问题是可能的后缀列表。毕竟有很多。
快速浏览publicsuffix.org列表后,您似乎可以通过从最后一个段长为两个字符的域中删除最后三个段(这里的“段”表示两个点之间的部分)来做出合理的近似,假设它是国家/地区代码,并将进一步细分。如果最后一个段是“我们”,倒数第二个段也是两个字符,则删除最后四个段。在所有其他情况下,请删除最后两个部分。例如:
“示例”不是两个字符,因此删除“ domain.example”,保留“ www”
“ example”不是两个字符,因此删除“ domain.example”,保留“ super.duper”
“ uk”是两个字符(但不是“ us”),因此删除“ domain.co.uk”,保留“ super.duper”
“我们”是两个字符,并且是“我们”,加上“ wy”也是两个字符,因此删除“ pvt.k12.wy.us”,保留“ foo”。
请注意,尽管这适用于到目前为止我在响应中看到的所有示例,但它仅是一个合理的近似值。这并不完全正确,尽管我怀疑它与您可能不准备/未获得供参考的实际列表差不多。
.NAME
例如,在刚开始时只能购买firstname.lastname.name
域名的情况。而且在相反的方向上,现在.US
也变得平坦了,因此您x.y.z.whatever.us
只需whatever.us
在注册表中购买即可,然后您的算法将失败。