Получить доменное имя из заданного URL-адреса

Учитывая URL-адрес, я хочу извлечь доменное имя (оно не должно включать часть "www" ). Url может содержать http/https. Вот код Java, который я написал. Хотя кажется, что он работает нормально, есть ли какой-нибудь лучший подход или есть некоторые краевые случаи, которые могут потерпеть неудачу.

public static String getDomainName(String url) throws MalformedURLException{
    if(!url.startsWith("http") && !url.startsWith("https")){
         url = "http://" + url;
    }        
    URL netUrl = new URL(url);
    String host = netUrl.getHost();
    if(host.startsWith("www")){
        host = host.substring("www".length()+1);
    }
    return host;
}

Вход: http://google.com/blah

Вывод: google.com

Ответ 1

Если вы хотите проанализировать URL-адрес, используйте java.net.URI. java.net.URL имеет множество проблем - его метод equals выполняет поиск DNS, что означает, что его использование может быть уязвимым для атак типа "отказ в обслуживании" при использовании с ненадежными входами.

"Г-н Гослинг - почему вы сделали URL-адрес равным сосать?" объясняет одну из таких проблем. Просто привыкните использовать java.net.URI вместо этого.

public static String getDomainName(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;
}

должен делать то, что вы хотите.


Хотя, похоже, он работает нормально, есть ли какой-нибудь лучший подход или есть некоторые случаи кросс, которые могут потерпеть неудачу.

Ваш код, как написано, не подходит для действительных URL-адресов:

  • httpfoo/bar - относительный URL-адрес с компонентом пути, начинающимся с http.
  • HTTP://example.com/ - протокол нечувствителен к регистру.
  • //example.com/ - относительный URL-адрес протокола с хостом
  • www/foo - относительный URL-адрес с компонентом пути, который начинается с www
  • wwwexample.com - имя домена, которое не начинается с www., но начинается с www.

Иерархические URL-адреса имеют сложную грамматику. Если вы попытаетесь опрокинуть свой собственный парсер без тщательного чтения RFC 3986, вы, вероятно, ошибетесь. Просто используйте тот, который встроен в основные библиотеки.

Если вам действительно нужно иметь дело с беспорядочными входами, которые отклоняются java.net.URI, см. RFC 3986 Приложение B:

Приложение B. Разбор URI-ссылки с регулярным выражением

Поскольку алгоритм "first-match-wins" идентичен "жадному",    метод неоднозначности, используемый регулярными выражениями POSIX,    естественным и обычным для использования регулярного выражения для синтаксического анализа    потенциальные пять компонентов ссылки URI.

Следующая строка - это регулярное выражение для разложения a    правильно сформированный URI-ссылка на его компоненты.

  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
   12            3  4          5       6  7        8 9

Цифры во второй строке выше предназначены только для удобства чтения;    они указывают контрольные точки для каждого подвыражения (то есть каждый    спаренная скобка).

Ответ 2

import java.net.*;
import java.io.*;

public class ParseURL {
  public static void main(String[] args) throws Exception {

    URL aURL = new URL("http://example.com:80/docs/books/tutorial"
                       + "/index.html?name=networking#DOWNLOADING");

    System.out.println("protocol = " + aURL.getProtocol()); //http
    System.out.println("authority = " + aURL.getAuthority()); //example.com:80
    System.out.println("host = " + aURL.getHost()); //example.com
    System.out.println("port = " + aURL.getPort()); //80
    System.out.println("path = " + aURL.getPath()); //  /docs/books/tutorial/index.html
    System.out.println("query = " + aURL.getQuery()); //name=networking
    System.out.println("filename = " + aURL.getFile()); ///docs/books/tutorial/index.html?name=networking
    System.out.println("ref = " + aURL.getRef()); //DOWNLOADING
  }
}

Подробнее

Ответ 3

Вот короткая и простая строка, использующая InternetDomainName.topPrivateDomain() в Guava: InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

Учитывая http://www.google.com/blah, это даст вам google.com. Или, учитывая http://www.google.co.mx, он предоставит вам google.co.mx.

Как сказал Са-Када в другом ответе на этот пост, этот вопрос был задан раньше: Извлеките основное доменное имя из заданного URL-адреса. Лучший ответ на этот вопрос - Сатья, который предлагает Guava InternetDomainName.topPrivateDomain()

public boolean isTopPrivateDomain()

Указывает, состоит ли это имя домена только из одного компонента субдомена, за которым следует открытый суффикс. Например, возвращает true для google.com и foo.co.uk, но не для www.google.com или co.uk.

Предупреждение. Истинный результат этого метода не означает, что домен находится на самом высоком уровне, который адресуется как хост, так как многие общедоступные суффиксы также являются адресными хостами. Например, домен bar.uk.com имеет открытый суффикс uk.com, поэтому он вернет true из этого метода. Но uk.com сам по себе является адресным хостом.

Этот метод может быть использован для определения того, является ли домен, вероятно, самым высоким уровнем, для которого могут быть установлены файлы cookie, хотя это зависит только от реализации браузерами отдельных файлов в браузере. Подробнее см. RFC 2109.

URL.getHost() это вместе с URL.getHost(), который уже содержит исходное сообщение, дает вам:

import com.google.common.net.InternetDomainName;

import java.net.URL;

public class DomainNameMain {

  public static void main(final String... args) throws Exception {
    final String urlString = "http://www.google.com/blah";
    final URL url = new URL(urlString);
    final String host = url.getHost();
    final InternetDomainName name = InternetDomainName.from(host).topPrivateDomain();
    System.out.println(urlString);
    System.out.println(host);
    System.out.println(name);
  }
}

Ответ 4

Я написал метод (см. ниже), который извлекает имя домена url и которое использует простое сопоставление строк. Фактически это извлекает бит между первым "://" (или индексом 0, если там нет "://"), и первым последующим "/" (или индексом String.length(), если нет последующих "/"). Оставшийся, предшествующий бит "www(_)*." прерывается. Я уверен, что будут случаи, когда это будет недостаточно, но в большинстве случаев это должно быть достаточно хорошо!

Сообщение Майка Самуэля выше говорит, что класс java.net.URI мог бы сделать это (и был предпочтительнее класса java.net.URL), но я столкнулся с проблемами с классом URI. Примечательно, что URI.getHost() дает нулевое значение, если url не включает схему, то есть бит "http(s)".

/**
 * Extracts the domain name from {@code url}
 * by means of String manipulation
 * rather than using the {@link URI} or {@link URL} class.
 *
 * @param url is non-null.
 * @return the domain name within {@code url}.
 */
public String getUrlDomainName(String url) {
  String domainName = new String(url);

  int index = domainName.indexOf("://");

  if (index != -1) {
    // keep everything after the "://"
    domainName = domainName.substring(index + 3);
  }

  index = domainName.indexOf('/');

  if (index != -1) {
    // keep everything before the '/'
    domainName = domainName.substring(0, index);
  }

  // check for and remove a preceding 'www'
  // followed by any sequence of characters (non-greedy)
  // followed by a '.'
  // from the beginning of the string
  domainName = domainName.replaceFirst("^www.*?\\.", "");

  return domainName;
}

Ответ 5

Я сделал небольшое лечение после создания объекта URI

 if (url.startsWith("http:/")) {
        if (!url.contains("http://")) {
            url = url.replaceAll("http:/", "http://");
        }
    } else {
        url = "http://" + url;
    }
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;

Ответ 6

попробуйте следующее: java.net.URL;
JOptionPane.showMessageDialog(null, getDomainName (новый URL ( " https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains" )));

public String getDomainName(URL url){
String strDomain;
String[] strhost = url.getHost().split(Pattern.quote("."));
String[] strTLD = {"com","org","net","int","edu","gov","mil","arpa"};

if(Arrays.asList(strTLD).indexOf(strhost[strhost.length-1])>=0)
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else if(strhost.length>2)
    strDomain = strhost[strhost.length-3]+"."+strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
return strDomain;}

Ответ 8

private static final String hostExtractorRegexString = "(?:https?://)?(?:www\\.)?(.+\\.)(com|au\\.uk|co\\.in|be|in|uk|org\\.in|org|net|edu|gov|mil)";
private static final Pattern hostExtractorRegexPattern = Pattern.compile(hostExtractorRegexString);

public static String getDomainName(String url){
    if (url == null) return null;
    url = url.trim();
    Matcher m = hostExtractorRegexPattern.matcher(url);
    if(m.find() && m.groupCount() == 2) {
        return m.group(1) + m.group(2);
    }
    else {
        return null;
    }
}

Объяснение: Регулярное выражение имеет 4 группы. Первые два являются несогласованными группами, а следующие два являются сопоставимыми группами.

Первая несогласованная группа - это "http" или "https" или "

Вторая несогласованная группа - "www". или ""

Вторая соответствующая группа - домен верхнего уровня

Первая соответствующая группа - это что-то после групп, не соответствующих друг другу, и ничего перед доменом верхнего уровня

Конкатенация двух сопоставимых групп даст нам имя домена/хоста.

PS: Обратите внимание, что вы можете добавить любое количество поддерживаемых доменов в регулярное выражение.

Ответ 9

Если входной URL-адрес введен пользователем. этот метод дает наиболее подходящее имя хоста. если не найден, возвращает возвращаемый url.

private String getHostName(String urlInput) {
        urlInput = urlInput.toLowerCase();
        String hostName=urlInput;
        if(!urlInput.equals("")){
            if(urlInput.startsWith("http") || urlInput.startsWith("https")){
                try{
                    URL netUrl = new URL(urlInput);
                    String host= netUrl.getHost();
                    if(host.startsWith("www")){
                        hostName = host.substring("www".length()+1);
                    }else{
                        hostName=host;
                    }
                }catch (MalformedURLException e){
                    hostName=urlInput;
                }
            }else if(urlInput.startsWith("www")){
                hostName=urlInput.substring("www".length()+1);
            }
            return  hostName;
        }else{
            return  "";
        }
    }

Ответ 10

В моем случае мне нужен только основной домен, а не субдомен (нет "www" или что-то вроде субдомена):

public static String getUrlDomain(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    String[] domainArray = domain.split("\\.");
    if (domainArray.length == 1) {
        return domainArray[0];
    }
    else {
        return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
    }
}

С помощью этого метода для домена "webtoapp.io" будет указан URL-адрес " https://rest.webtoapp.io/llSlider?lg=ru&t=8 ".