如何从URL获取域名

时间:2009-02-20 11:01:33

标签: regex url

如何从URL字符串中获取域名?

示例:

+----------------------+------------+
| input                | output     |
+----------------------+------------+
| www.google.com       | google     |
| www.mail.yahoo.com   | mail.yahoo |
| www.mail.yahoo.co.in | mail.yahoo |
| www.abc.au.uk        | abc        |
+----------------------+------------+

相关:

20 个答案:

答案 0 :(得分:39)

我曾经为我工作过的公司写过这样的正则表达式。解决方案是:

  • 获取可用的每个ccTLDgTLD的列表。你的第一站应该是IANA。 Mozilla的列表一见钟情,但缺少ac.uk,所以为此它并不真正可用。
  • 像下面的示例一样加入列表。 警告:订购很重要!如果 org.uk 出现在 uk 之后,那么 example.org.uk 将匹配 org 而不是示例即可。

示例正则表达式:

.*([^\.]+)(com|net|org|info|coop|int|co\.uk|org\.uk|ac\.uk|uk|__and so on__)$

这非常有效,并且还与 de.com 和朋友等奇怪的,非正式的顶层相匹配。

好处:

  • 如果正则表达式是最佳排序的话,速度非常快

这个解决方案的缺点当然是:

  • 手写正则表达式,如果ccTLD更改或添加,必须手动更新。繁琐的工作!
  • 非常大的正则表达式,所以不太可读。

答案 1 :(得分:12)

/^(?:www\.)?(.*?)\.(?:com|au\.uk|co\.in)$/

答案 2 :(得分:8)

准确提取域名可能非常棘手,主要是因为域扩展可以包含2个部分(如.com.au或.co.uk),子域(前缀)可能存在也可能不存在。列出所有域扩展名不是一个选项,因为有数百个。例如,EuroDNS.com列出了800多个域名扩展名。

因此,我写了一个简短的php函数,它使用'parse_url()'和一些关于域扩展的观察来准确地提取url组件和域名。功能如下:

function parse_url_all($url){
    $url = substr($url,0,4)=='http'? $url: 'http://'.$url;
    $d = parse_url($url);
    $tmp = explode('.',$d['host']);
    $n = count($tmp);
    if ($n>=2){
        if ($n==4 || ($n==3 && strlen($tmp[($n-2)])<=3)){
            $d['domain'] = $tmp[($n-3)].".".$tmp[($n-2)].".".$tmp[($n-1)];
            $d['domainX'] = $tmp[($n-3)];
        } else {
            $d['domain'] = $tmp[($n-2)].".".$tmp[($n-1)];
            $d['domainX'] = $tmp[($n-2)];
        }
    }
    return $d;
}

这个简单的功能几乎适用于所有情况。有一些例外,但这些非常罕见。

要演示/测试此功能,您可以使用以下内容:

$urls = array('www.test.com', 'test.com', 'cp.test.com' .....);
echo "<div style='overflow-x:auto;'>";
echo "<table>";
echo "<tr><th>URL</th><th>Host</th><th>Domain</th><th>Domain X</th></tr>";
foreach ($urls as $url) {
    $info = parse_url_all($url);
    echo "<tr><td>".$url."</td><td>".$info['host'].
    "</td><td>".$info['domain']."</td><td>".$info['domainX']."</td></tr>";
}
echo "</table></div>";

列出的URL的输出如下:

enter image description here

如您所见,无论提供给该功能的网址如何,都会一直提取没有扩展名的域名和域名。

我希望这会有所帮助。

答案 3 :(得分:6)

聚会晚了一点,但是:

const urls = [
  'www.abc.au.uk',
  'https://github.com',
  'http://github.ca',
  'https://www.google.ru',
  'http://www.google.co.uk',
  'www.yandex.com',
  'yandex.ru',
  'yandex'
]

urls.forEach(url => console.log(url.replace(/.+\/\/|www.|\..+/g, '')))

答案 4 :(得分:4)

我不知道任何库,但域名的字符串操作很容易。

困难的部分是知道名字是在第二级还是第三级。为此,您需要一个您维护的数据文件(例如,对于.uk并不总是第三级,某些组织(例如bl.uk,jet.uk)存在于第二级)。

Mozilla的source of Firefox有这样的数据文件,请检查Mozilla许可,看看是否可以重复使用。

答案 5 :(得分:4)

有两种方式

使用拆分

然后只解析该字符串

var domain;
//find & remove protocol (http, ftp, etc.) and get domain
if (url.indexOf('://') > -1) {
    domain = url.split('/')[2];
} if (url.indexOf('//') === 0) {
    domain = url.split('/')[2];
} else {
    domain = url.split('/')[0];
}

//find & remove port number
domain = domain.split(':')[0];

使用正则表达式

 var r = /:\/\/(.[^/]+)/;
 "http://stackoverflow.com/questions/5343288/get-url".match(r)[1] 
 => stackoverflow.com

希望这有帮助

答案 6 :(得分:3)

import urlparse

GENERIC_TLDS = [
    'aero', 'asia', 'biz', 'com', 'coop', 'edu', 'gov', 'info', 'int', 'jobs', 
    'mil', 'mobi', 'museum', 'name', 'net', 'org', 'pro', 'tel', 'travel', 'cat'
    ]

def get_domain(url):
    hostname = urlparse.urlparse(url.lower()).netloc
    if hostname == '':
        # Force the recognition as a full URL
        hostname = urlparse.urlparse('http://' + uri).netloc

    # Remove the 'user:passw', 'www.' and ':port' parts
    hostname = hostname.split('@')[-1].split(':')[0].lstrip('www.').split('.')

    num_parts = len(hostname)
    if (num_parts < 3) or (len(hostname[-1]) > 2):
        return '.'.join(hostname[:-1])
    if len(hostname[-2]) > 2 and hostname[-2] not in GENERIC_TLDS:
        return '.'.join(hostname[:-1])
    if num_parts >= 3:
        return '.'.join(hostname[:-2])

此代码不保证可以与所有网址一起使用,也不会过滤那些语法正确但无效的例如“example.uk”。

然而,在大多数情况下它会完成这项任务。

答案 7 :(得分:2)

不使用TLD列表进行比较是不可能的,因为它们存在许多案例,例如http://www.db.de/http://bbc.co.uk/,将由正则表达式解释为域db.de(正确)和co.uk(错误的)。

但即便如此,如果您的列表也不包含SLD,您将无法取得成功。 http://big.uk.com/http://www.uk.com/等网址都会被解释为uk.com(第一个域名为big.uk.com)。

因为所有浏览器都使用Mozilla的公共后缀列表:

https://en.wikipedia.org/wiki/Public_Suffix_List

您可以通过以下网址导入代码来使用它:

http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1

欢迎扩展我的功能以仅提取域名。它不会使用正则表达式而且速度很快:

http://www.programmierer-forum.de/domainnamen-ermitteln-t244185.htm#3471878

答案 8 :(得分:2)

基本上,你想要的是:

google.com        -> google.com    -> google
www.google.com    -> google.com    -> google
google.co.uk      -> google.co.uk  -> google
www.google.co.uk  -> google.co.uk  -> google
www.google.org    -> google.org    -> google
www.google.org.uk -> google.org.uk -> google

可选:

www.google.com     -> google.com    -> www.google
images.google.com  -> google.com    -> images.google
mail.yahoo.co.uk   -> yahoo.co.uk   -> mail.yahoo
mail.yahoo.com     -> yahoo.com     -> mail.yahoo
www.mail.yahoo.com -> yahoo.com     -> mail.yahoo

如果您只是查看名称的倒数第二部分,则无需构建不断变化的正则表达式,因为99%的域将被正确匹配:

(co|com|gov|net|org)

如果是其中之一,那么你需要匹配3个点,否则2.简单。现在,我的正则表达式魔法与其他一些SO'ers的不相符,所以我发现实现这一点的最好方法是使用一些代码,假设你已经脱离了这条道路:

 my @d=split /\./,$domain;                # split the domain part into an array
 $c=@d;                                   # count how many parts
 $dest=$d[$c-2].'.'.$d[$c-1];             # use the last 2 parts
 if ($d[$c-2]=~m/(co|com|gov|net|org)/) { # is the second-last part one of these?
   $dest=$d[$c-3].'.'.$dest;              # if so, add a third part
 };
 print $dest;                             # show it

根据您的问题获取名称:

 my @d=split /\./,$domain;                # split the domain part into an array
 $c=@d;                                   # count how many parts
 if ($d[$c-2]=~m/(co|com|gov|net|org)/) { # is the second-last part one of these?
   $dest=$d[$c-3];                        # if so, give the third last
   $dest=$d[$c-4].'.'.$dest if ($c>3);    # optional bit
 } else {
   $dest=$d[$c-2];                        # else the second last
   $dest=$d[$c-3].'.'.$dest if ($c>2);    # optional bit 
 };
 print $dest;                             # show it

我喜欢这种方法,因为它免维护。除非您想验证它实际上是一个合法的域,但这有点毫无意义,因为您最有可能只使用它来处理日志文件,并且无效的域首先不会在那里找到它。

如果您想匹配“非官方”子域名,例如bozo.za.net或bozo.au.uk,bozo.msf.ru只需将(za | au | msf)添加到正则表达式。

我很乐意看到有人只使用正则表达式完成所有这些操作,我确信这是可能的。

答案 9 :(得分:1)

/[^w{3}\.]([a-zA-Z0-9]([a-zA-Z0-9\-]{0,65}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}/gim

使用此javascript正则表达式忽略www和跟随点,同时保持域完整。也适当地匹配没有www和cc tld

答案 10 :(得分:0)

您能否只查找 .com(或其他)之前的单词(其他列表的顺序与频率相反,请参阅 here

并取第一个匹配组 即

window.location.host.match(/(\w|-)+(?=(\.(com|net|org|info|coop|int|co|ac|ie|co|ai|eu|ca|icu|top|xyz|tk|cn|ga|cf|nl|us|eu|de|hk|am|tv|bingo|blackfriday|gov|edu|mil|arpa|au|ru)(\.|\/|$)))/g)[0]

您可以通过将此行复制到任何选项卡上的开发人员控制台来测试它

此示例适用于以下情况:

enter image description here

答案 11 :(得分:0)

我知道这个问题正在寻找正则表达式解决方案,但是在所有尝试中它都无法涵盖所有​​问题

我决定用Python编写此方法,该方法仅适用于具有子域(即www.mydomain.co.uk)的网址,而不适用于像www.mail.yahoo.com这样的多层子域

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:])}

答案 12 :(得分:0)

  1. 这是怎么回事?

    =((?:(?:(?:http)s?:)?\/\/)?(?:(?:[a-zA-Z0-9]+)\.?)*(?:(?:[a-zA-Z0-9]+))\.[a-zA-Z0-9]{2,3}) (您可能希望添加&#34; \ /&#34;到模式结束

  2. 如果你的目标是摆脱作为参数传递的网址,你可以添加等号作为第一个字符,例如:

    =(?(:( :( ?: HTTP)S:?)//)?(?:(?:[A-ZA-Z0-9] +)。?)*(:( ?:[A-ZA-Z0-9] +))[A-ZA-Z0-9] {2,3} /)

    并替换为&#34; /&#34;

  3. 此示例的目标是删除任何域名,无论其出现何种形式。 (即确保url参数不包含域名以避免xss攻击)

答案 13 :(得分:0)

使用它 (。)(。*?)(。) 然后只提取前导点和终点。 容易,对吧?

答案 14 :(得分:0)

出于某种目的,我昨天做了这个快速的Python函数。它从URL返回域。它很快,不需要任何输入文件列表的东西。但是,我并不假装它在所有情况下都能正常工作,但它确实完成了我为简单的文本挖掘脚本所需的工作。

输出如下:

http://www.google.co.uk =&gt; google.co.uk
http://24.media.tumblr.com/tumblr_m04s34rqh567ij78k_250.gif =&gt; tumblr.com

def getDomain(url):    
        parts = re.split("\/", url)
        match = re.match("([\w\-]+\.)*([\w\-]+\.\w{2,6}$)", parts[2]) 
        if match != None:
            if re.search("\.uk", parts[2]): 
                match = re.match("([\w\-]+\.)*([\w\-]+\.[\w\-]+\.\w{2,6}$)", parts[2])
            return match.group(2)
        else: return ''  

似乎工作得很好。
但是,必须修改它以根据需要删除输出上的域扩展名。

答案 15 :(得分:0)

因此,如果你只有一个字符串而不是window.location,你可以使用...

String.prototype.toUrl = function(){

if(!this && 0 < this.length)
{
    return undefined;
}
var original = this.toString();
var s = original;
if(!original.toLowerCase().startsWith('http'))
{
    s = 'http://' + original;
}

s = this.split('/');

var protocol = s[0];
var host = s[2];
var relativePath = '';

if(s.length > 3){
    for(var i=3;i< s.length;i++)
    {
        relativePath += '/' + s[i];
    }
}

s = host.split('.');
var domain = s[s.length-2] + '.' + s[s.length-1];    

return {
    original: original,
    protocol: protocol,
    domain: domain,
    host: host,
    relativePath: relativePath,
    getParameter: function(param)
    {
        return this.getParameters()[param];
    },
    getParameters: function(){
        var vars = [], hash;
        var hashes = this.original.slice(this.original.indexOf('?') + 1).split('&');
        for (var i = 0; i < hashes.length; i++) {
            hash = hashes[i].split('=');
            vars.push(hash[0]);
            vars[hash[0]] = hash[1];
        }
        return vars;
    }
};};

如何使用。

var str = "http://en.wikipedia.org/wiki/Knopf?q=1&t=2";
var url = str.toUrl;

var host = url.host;
var domain = url.domain;
var original = url.original;
var relativePath = url.relativePath;
var paramQ = url.getParameter('q');
var paramT = url.getParamter('t');

答案 16 :(得分:0)

您需要一个可以删除哪些域名前缀和后缀的列表。例如:

前缀:

  • www.

后缀:

  • .com
  • .co.in
  • .au.uk

答案 17 :(得分:-1)

只是为了知识:

'http://api.livreto.co/books'.replace(/^(https?:\/\/)([a-z]{3}[0-9]?\.)?(\w+)(\.[a-zA-Z]{2,3})(\.[a-zA-Z]{2,3})?.*$/, '$3$4$5');

# returns livreto.co 

答案 18 :(得分:-1)

/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/i

答案 19 :(得分:-1)

#!/usr/bin/perl -w
use strict;

my $url = $ARGV[0];
if($url =~ /([^:]*:\/\/)?([^\/]*\.)*([^\/\.]+)\.[^\/]+/g) {
  print $3;
}