【问题标题】:How to get domain name from URL如何从 URL 中获取域名
【发布时间】:2010-10-08 19:43:27
【问题描述】:

如何从 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        |
+----------------------+------------+

相关:

【问题讨论】:

  • www.abc.def.ghi.au.uk 怎么样?
  • “foo.bar.com”怎么样?还有“foo.com”?
  • 嗯,几分钟后第二篇关于一个非常相似的主题的帖子——家庭作业? (stackoverflow.com/questions/568864/…)
  • 我可以问什么?如果没有二级域名后缀(如 .co.uk),很难发明您需要什么域名
  • @Chinmay:你的术语在这里有各种各样的错误。您列出的所有输入都是域名,而不是 URL。这是一个 URL:http://en.wikipedia.org/wiki/URL,该 URL 中的域名是 en.wikipedia.org

标签: regex url


【解决方案1】:

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

  • 获取每个可用的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 更改或添加,则必须手动更新的手写正则表达式。乏味的工作!
  • 非常大的正则表达式,因此不太可读。

【讨论】:

  • RE:更新乏味 - 编写一个小代码生成器程序,根据输入数据文件生成正则表达式。
  • 是的。有了一个好的测试工具,这应该是可能的。我们当然没有进行测试...
  • 来自 Mozilla 的列表实际上看起来相当不错——它有 *.uk 来匹配 .ac.uk 。您只需要弄清楚格式并正确解释规则即可。
  • 我在几个项目中需要这个,所以我用 Python 和opened it up on GitHub 实现了它。您还可以通过 App Engine 上的 HTTP 端点查询它。随意贡献!
  • Mozilla PSL 现在匹配*.uk,因此@pi. 担心它无法匹配ac.uk 不再适用。
【解决方案2】:

聚会有点晚了,但是:

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, '')))

【讨论】:

  • 这是我最喜欢的答案。谢谢。
  • 不起作用:对于输入www.mail.yahoo.co.in,所需的输出是mail.yahoo,但输出是mail
  • 这很好,接受的答案也没有,但这种方式可扩展且更具动态性。无论您需要专门匹配 10% 到 20% 的案例,在这种方法的不足之处,您都可以按照公认的答案进行硬编码。这是社区的答案,而不是 11 年前已经收到答案的 OP。
【解决方案3】:

准确提取域名可能非常棘手,主要是因为域扩展名可以包含 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,输出将如下所示:

如您所见,无论呈现给函数的 URL 是什么,域名和不带扩展名的域名都会被一致地提取。

我希望这会有所帮助。

【讨论】:

  • Clinton 说:“因此,我编写了一个简短的 php 函数,它使用 'parse_url()' 和一些关于域扩展的观察来准确提取 url 组件和域名。”有人有这个函数的 JavaScript 版本吗?
  • 好剧本。使用起来还安全吗?
  • 谢谢。我仍然在许多涉及 URL 和域检查的应用程序中使用它,而且它每次都对我有用。
  • 我没有 PHP 来测试你的代码,sub1.sub2.test.co.it 是否适用于你的情况?
  • 这是一个不错的小脚本,适用于 95% 的情况。谢谢!我只是想指出,如果域长度为 3 个或更少的字母(www.cnn.com),它将失败,所以如果你只是复制和粘贴,请小心。问题是不可能知道域是“www”,“cnn.com”作为 TLD,还是“cnn”,“com”作为 TLD。在这种情况下,这很明显,但您需要知道所有 TLD 才能确定。
【解决方案4】:
/^(?:www\.)?(.*?)\.(?:com|au\.uk|co\.in)$/

【讨论】:

  • 我认为这些示例只是为了说明一般规则。这仅适用于 OP 提供的输入。
【解决方案5】:

有两种方法

使用拆分

然后只解析那个字符串

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】:

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

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

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

    【讨论】:

      【解决方案7】:
      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])
      

      此代码不保证适用于所有 URL,并且不会过滤那些语法正确但无效的 URL,例如“example.uk”。

      但是在大​​多数情况下它会完成这项工作。

      【讨论】:

        【解决方案8】:

        基本上,你想要的是:

        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】:

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

          但即便如此,如果您的列表也不包含 SLD,您也不会成功。像 http://big.uk.com/http://www.uk.com/ 这样的 URL 都将被解释为 uk.com(第一个域是 big.uk.com)。

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

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

          您可以通过以下 URL 将其导入代码中:

          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

          【讨论】:

            【解决方案10】:

            /[^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

            【讨论】:

              【解决方案11】:

              所以如果你只有一个字符串而不是 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');
              

              【讨论】:

                【解决方案12】:

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

                输出如下所示:

                http://www.google.co.uk => google.co.uk
                http://24.media.tumblr.com/tumblr_m04s34rqh567ij78k_250.gif => 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 ''  
                

                似乎工作得很好。
                但是,必须对其进行修改以根据需要删除输出中的域扩展。

                【讨论】:

                  【解决方案13】:
                  1. 这是怎么回事

                    =((?:(?:(?:http)s?:)?\/\/)?(?:(?:[a-zA-Z0-9]+)\.?)*(?:(?:[a-zA-Z0-9]+))\.[a-zA-Z0-9]{2,3}) (您可能需要在模式末尾添加“\/”

                  2. 如果您的目标是消除作为参数传入的 url,您可以将等号添加为第一个字符,例如:

                    =((?:(?:(?:http)s?:)?//)?(?:(?:[a-zA-Z0-9]+).?)*(?:( ?:[a-zA-Z0-9]+)).[a-zA-Z0-9]{2,3}/)

                    并替换为“/”

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

                  【讨论】:

                    【解决方案14】:

                    您能否只查找 .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]
                    

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

                    此示例适用于以下情况:

                    【讨论】:

                      【解决方案15】:

                      这里的所有答案都很好,但有时都会失败。 所以我知道链接其他东西并不常见,已经在别处回答过,但你会发现你不必把时间浪费在不可能的事情上。 这是因为像 mydomain.co.uk 这样的域没有办法知道提取的域是否正确。 如果你说要通过 URL 提取,前面有 http 或 https 或什么都没有的东西(但如果前面可能什么都没有,你必须删除

                      filter_var($url, filter_var($url, FILTER_VALIDATE_URL))
                      

                      在下面,因为 FILTER_VALIDATE_URL 不能将不以 http 开头的字符串识别为 url,因此可以将其删除,并且您也可以用这样的愚蠢的东西来实现,永远不会失败:

                      $url = strtolower('hTTps://www.example.com/w3/forum/index.php');
                      
                      if( filter_var($url, FILTER_VALIDATE_URL) && substr($url, 0, 4) == 'http' )
                      {
                      // array order is !important
                      $domain = str_replace(array("http://www.","https://www.","http://","https://"), array("","","",""), $url);
                      $spos = strpos($domain,'/');
                      if($spos !== false)
                      {
                       $domain = substr($domain, 0, $spos);
                      } } else { $domain = "can't extract a domain"; }
                      
                      echo $domain;
                      

                      Check FILTER_VALIDATE_URL default behavior here

                      但是,如果您想检查一个域的有效性,并且始终确保提取的值是正确的,那么您必须检查一组有效的顶级域,如下所述: https://stackoverflow.com/a/70566657/6399448 否则您将永远无法确定提取的字符串是正确的域。不幸的是,这里的所有答案有时都会失败。

                      P.s 在这里有意义的独特答案在我看来是这样的(对不起,我之前没有读过它。它提供了相同的解决方案,即使没有提供我上面提到或链接的示例): https://stackoverflow.com/a/569219/6399448

                      【讨论】:

                        【解决方案16】:

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

                        前缀:

                        • www.

                        后缀:

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

                        【讨论】:

                        • 仅适用于样本,维护此类列表无法扩展
                        【解决方案17】:
                        #!/usr/bin/perl -w
                        use strict;
                        
                        my $url = $ARGV[0];
                        if($url =~ /([^:]*:\/\/)?([^\/]*\.)*([^\/\.]+)\.[^\/]+/g) {
                          print $3;
                        }
                        

                        【讨论】:

                        • 如果你使用了除正斜杠之外的其他字符作为匹配操作符,那么你就不需要有这么多的转义字符并且可以使正则表达式更具可读性,例如$url =~ m{([^:]*://)?([^/]*\.)*([^/\.]+)\.[^/]+} 也不确定是否需要循环运算符 (/g)?
                        • 是的,虽然我的回答最大的问题是它不适用于外国域,因为它们不遵循标准的美国格式“xxx.(com|edu|org|etc)” . Sot telegraph.co.uk 不匹配。让我觉得您确实需要明确列出所有不同的国家/地区代码才能匹配类似的内容。
                        • 或者既然其他人已经弄清楚了这些东西,只需使用一个模块来完成它,例如 URI::Find - search.cpan.org/perldoc?URI::Find 或者如果你只想要一个正则表达式然后 search.cpan.org/perldoc?Regexp::Common::URI跨度>
                        • 当然,但是当有人要求使用正则表达式时,解决它总是很有趣:)
                        【解决方案18】:
                        /^(?:https?:\/\/)?(?:www\.)?([^\/]+)/i
                        

                        【讨论】:

                        • 一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。正则表达式尤其如此,正则表达式因对大多数人来说是不透明的线噪声而臭名昭著。在这里,也不是特别清楚它是否解决了整个问题,因为有答案,而且做得很好,并且有很好的解释……。
                        【解决方案19】:

                        使用这个 (.)(.*?)(.) 然后只需提取前导和结束点。 简单吧?

                        【讨论】:

                          【解决方案20】:

                          只是为了知识:

                          '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 
                          

                          【讨论】:

                            【解决方案21】:

                            我知道问题是寻求正则表达式解决方案,但每次尝试都无法涵盖所有​​内容

                            我决定用 Python 编写这个方法,它只适用于具有子域(即 www.mydomain.co.uk)的 URL,而不适用于像 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:])}
                            

                            【讨论】:

                              【解决方案22】:

                              假设我们有这个:http://google.com

                              而你只想要域名

                              let url = http://google.com;
                              let domainName = url.split("://")[1];
                              console.log(domainName);
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 1970-01-01
                                • 2011-01-10
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                相关资源
                                最近更新 更多