python domain name split name and extension
How would you split a domain name that will return name and extension
Wow, there are a lot of bad answers here. You can only do this if you know what's on the public suffix list. If you are using split
or a regex or something else, you're doing this wrong.
Luckily, this is python, and there's a library for this: https://pypi.python.org/pypi/tldextract
From their readme:
>>> import tldextract
>>> tldextract.extract('http://forums.news.cnn.com/')
ExtractResult(subdomain='forums.news', domain='cnn', suffix='com')
ExtractResult
is a namedtuple. Makes it pretty easy.
The advantage of using a library like this is that they will keep up with the additions to the public suffix list so you don't have to.
In general, it's not easy to work out where the user-registered bit ends and the registry bit begins. For example: a.com, b.co.uk, c.us, d.ca.us, e.uk.com, f.pvt.k12.wy.us...
The nice people at Mozilla have a project dedicated to listing domain suffixes under which the public can register domains: http://publicsuffix.org/
Depending on your application, be a little wary of simply taking the part following the last '.'. That works fine for .com, .net, .org, etc but will likely fall over for many County Code TLDs. E.g. bit.ly or google.co.uk.
(By which I mean 'bit.ly' probably prefer to be identified including the .ly TLD whereas google probably don't want to be identified with a spurious .co remainder. Whether that's important will obviously depend on what you're doing).
In those complicated cases ... well, you've got your work cut out I suspect!
A robust answer will probably depend on how you're gathering / storing your domains and what you really want back as the 'name'.
For example, if you've got a set of domain names, with no subdomain information, then you could do the opposite of what's suggested above and simply take the first part off:
>>> "stackoverflow.com".split('.')[0]
'stackoverflow'
You mean internet domain name, like www.stackoverflow.com? If so, then just use:
>>> 'www.stackoverflow.com'.rsplit('.', 1)
['www.stackoverflow', 'com']
As other commenters have pointed out, there's no surefire way of doing this, short of having a dynamically updated list of TLDs and gTLDs. What works for google.com
might not work for google.co.uk
, or something.co.xx
, or something.com.xx
. Pretty much anything can be in a TLD or a gTLD and who knows what the future holds?
So there are two very different approaches:
- Use a library that has a regularly-updated list of TLDs and gTLDs, like tldextract.
- Use an algorithm that you know will fail on some edge-cases, but aim for as few as possible.
In my experience, the following satisfies #2 well, assuming you've already stripped off protocol and path:
def domain_from_hostname( hostname ):
# Assume any TLD business will be dealt with in the last 7 bytes
# This won't work for:
# - Subdomains on supershort domains with short TLDs
# - Domains with TLDs over 7 bytes long (".diamonds" anyone?)
if len(host) < 8:
return host.strip( 'www.' )
host_left = host[:-7].split('.')[-1]
return u'%s%s' % ( host_left, host[-7:] )
Try it with some weirdness: a .com.au
, .media
, .in
, .中信
etc.
domain = 'subdomain.domain.ext'
name, ext = domain.split('.')[-2:]
If you always want to get the last part of a domain name, you can:
subdomain, _, domain= fqdn.rpartition('.')
I guess you will find urlparse
module interesting: http://docs.python.org/library/urlparse.html
This is what I have come up with. Nothing fancy. It works for me. Although I do believe it gives weird feedback sometimes when there is characters like ?, +, so on. Still don't understand why.
scheme = 'https://www.msn.com/d/1234.php?=https://www.msn.com?+'
notfound = -1
https = scheme.rfind('http://')
com = scheme.rfind('.com')
if https != notfound:
if com != notfound:
domain = scheme[https:com+len('.com')]
return scheme[https:com+len('.com')]
#Here we can grab the double suffix. This one has not been fully tested.
def getdoublesuffix(domain):
'''
:description: returns double dot TLD suffix endings or returns -1
:function:
'''
# ['www.domain.co.com'] to
# ['www.domain', 'co', 'com']
dots = domain.rsplit(sep='.', maxsplit=2)
# count dots by enumeration not string count! Only interested in enumeration count and
# not total dot count since it is split by '.' as a separator.
for number, value in enumerate(dots, 0):
value = value
number = number
if number is 2:
# co.com
result = '{0}.{1}'.format(dots[1], dots[2])
return result
else:
#return that we do not have a domain ending in two dot notation.
return -1
精彩评论