如何从URL中提取顶级域名(TLD)

70 投票
8 回答
93380 浏览
提问于 2025-04-15 12:36

你想从一个网址中提取出主域名,但不包括任何子域名,该怎么做呢?

我最开始的简单尝试是:

'.'.join(urlparse.urlparse(url).netloc.split('.')[-2:])

这个方法对 http://www.foo.com 有用,但对 http://www.foo.com.au 就不行了。

有没有什么好的方法可以做到这一点,而不需要特别了解有效的顶级域名(TLD)或国家代码(因为这些会变化)呢?

谢谢!

8 个回答

42

使用这个有效的顶级域名文件,这是其他人在Mozilla网站上找到的:

from __future__ import with_statement
from urlparse import urlparse

# load tlds, ignore comments and empty lines:
with open("effective_tld_names.dat.txt") as tld_file:
    tlds = [line.strip() for line in tld_file if line[0] not in "/\n"]

def get_domain(url, tlds):
    url_elements = urlparse(url)[1].split('.')
    # url_elements = ["abcde","co","uk"]

    for i in range(-len(url_elements), 0):
        last_i_elements = url_elements[i:]
        #    i=-3: ["abcde","co","uk"]
        #    i=-2: ["co","uk"]
        #    i=-1: ["uk"] etc

        candidate = ".".join(last_i_elements) # abcde.co.uk, co.uk, uk
        wildcard_candidate = ".".join(["*"] + last_i_elements[1:]) # *.co.uk, *.uk, *
        exception_candidate = "!" + candidate

        # match tlds: 
        if (exception_candidate in tlds):
            return ".".join(url_elements[i:]) 
        if (candidate in tlds or wildcard_candidate in tlds):
            return ".".join(url_elements[i-1:])
            # returns "abcde.co.uk"

    raise ValueError("Domain not in global list of TLDs")

print get_domain("http://abcde.co.uk", tlds)

结果是:

abcde.co.uk

如果有人能告诉我上面的哪些部分可以用更符合Python风格的方式重写,我会很感激。例如,遍历last_i_elements列表肯定有更好的方法,但我想不出来。我也不知道ValueError是否是最合适的错误类型。有什么意见吗?

67

这里有一个很棒的Python模块,是有人在看到这个问题后写出来的,用来解决这个问题:https://github.com/john-kurkowski/tldextract

这个模块会查找公共后缀列表中的顶级域名,这个列表是由Mozilla的志愿者维护的,大家可以在这里找到。

引用:

这个tldextract模块能够识别所有的通用顶级域名(gTLDs)和国家代码顶级域名(ccTLDs),它通过查找当前存在的域名来实现这一点,这些信息都在公共后缀列表中。因此,给定一个网址,它可以从域名中识别出子域名,从国家代码中识别出域名。

55

不,实际上没有一种“内置”的方法可以知道,比如说 zap.co.it 是一个子域名(因为意大利的注册商确实出售像 co.it 这样的域名),而 zap.co.uk 不是(因为英国的注册商不出售像 co.uk 这样的域名,只出售像 zap.co.uk 这样的域名)。

你只能使用一个辅助表格(或者在线资源)来告诉你哪些顶级域名(TLD)像英国和澳大利亚那样表现得比较特殊——光靠看字符串是无法知道这些的,因为你需要额外的语义知识(当然,这些情况可能会改变,但如果你能找到一个好的在线资源,那些信息也会相应更新,希望如此!)。

撰写回答