我的最初简单的尝试是:
'.'.join(urlparse.urlparse(url).netloc.split('.')[-2:])
这对于http://www.foo.com有效,但对于http://www.foo.com.au无效。有没有一种正确的方法来做到这一点而不使用关于有效顶级域名(TLD)或国家代码的特殊知识(因为它们会改变)。
谢谢
'.'.join(urlparse.urlparse(url).netloc.split('.')[-2:])
这对于http://www.foo.com有效,但对于http://www.foo.com.au无效。有没有一种正确的方法来做到这一点而不使用关于有效顶级域名(TLD)或国家代码的特殊知识(因为它们会改变)。
谢谢
这里有一个很棒的Python模块,是有人在看到这个问题后编写的,用来解决这个问题: https://github.com/john-kurkowski/tldextract
该模块在由Mozilla志愿者维护的Public Suffix List中查找TLD(顶级域名)。
引用:
tldextract
则另一方面知道所有gTLD(通用顶级域名)和ccTLD(国家代码顶级域名)的形式,通过查找Public Suffix List上当前正在使用的域名。因此,给定一个URL,它可以从其域名中识别出其子域名和其国家代码。
tld
失败了(它将一个有效的URL标记为无效)。 - szeitlin没有一种固有的方法可以知道(例如)zap.co.it
是子域名(因为意大利的注册机构确实出售像co.it
这样的域名),而zap.co.uk
则不是(因为英国的注册机构并不出售像co.uk
这样的域名,只出售像zap.co.uk
这样的域名)。
您只需要使用辅助表格(或在线资源)来告诉您哪些顶级域名(TLD)像英国和澳大利亚那样行事异常——除非拥有这种额外的语义知识,否则没有办法仅通过查看字符串来推断(当然可能会变化,但如果您能找到一个好的在线资源,那么该资源也会相应地更改,希望如此!)。
使用这个有效顶级域名文件(由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
如果有人能告诉我如何以更Pythonic的方式重写上面的内容,我将不胜感激。例如,迭代last_i_elements
列表可能有更好的方法,但我想不出来。我也不确定ValueError
是否是最合适的异常。有什么建议吗?
effective_tld_names.dat
文件是否也会更新以适应新的域名,例如.amsterdam
、.vodka
和.wtf
? - kramer65public_suffix_list.dat
,如果您不指定Python应该将文件读取为UTF8,则Python会发出警告。请明确指定编码方式:with open("public_suffix_list.dat", encoding="utf8") as tld_file
。 - Andrei使用 Python tld
https://pypi.python.org/pypi/tld
pip install tld
从给定的URL中获取顶级域名并以字符串形式返回from tld import get_tld
print get_tld("http://www.google.co.uk")
英国商业
或不带协议
from tld import get_tld
get_tld("www.google.co.uk", fix_protocol=True)
co.uk
from tld import get_tld
res = get_tld("http://some.subdomain.google.co.uk", as_object=True)
res
# 'co.uk'
res.subdomain
# 'some.subdomain'
res.domain
# 'google'
res.tld
# 'co.uk'
res.fld
# 'google.co.uk'
res.parsed_url
# SplitResult(
# scheme='http',
# netloc='some.subdomain.google.co.uk',
# path='',
# query='',
# fragment=''
# )
从给定的 URL 获取第一级域名字符串from tld import get_fld
get_fld("http://www.google.co.uk")
# 'google.co.uk'
tld.get_tld()
实际上返回的是完全合格的域名,而不是顶级域名? - Marianget_tld("http://www.google.co.uk", as_object=True).extension
会打印出 "co.uk"。 - Artur Barseghyanhttp://data.iana.org/TLD/tlds-alpha-by-domain.txt
这是另一个列表。http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
这是另一个列表。在 get_tld 更新所有新的顶级域名之前,我从错误中获取 tld。虽然这是糟糕的代码,但它能够工作。
def get_tld():
try:
return get_tld(self.content_url)
except Exception, e:
re_domain = re.compile("Domain ([^ ]+) didn't match any existing TLD name!");
matchObj = re_domain.findall(str(e))
if matchObj:
for m in matchObj:
return m
raise e
这是我处理它的方式:
if not url.startswith('http'):
url = 'http://'+url
website = urlparse.urlparse(url)[1]
domain = ('.').join(website.split('.')[-2:])
match = re.search(r'((www\.)?([A-Z0-9.-]+\.[A-Z]{2,4}))', domain, re.I)
if not match:
sys.exit(2)
elif not match.group(0):
sys.exit(2)
www.mybrand.sa.com
的URL为subdomain='order.mybrand',domain='sa',suffix='com'
!!
因此,最终我决定编写这个方法
重要说明:此方法仅适用于具有子域的URL。这并不意味着要取代更高级的库,如tldextract
def urlextract(url):
url_split=url.split(".")
if len(url_split) <= 2:
raise Exception("Full url required with subdomain:",url)
return {'subdomain': url_split[0], 'domain': url_split[1], 'suffix': ".".join(url_split[2:])}