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

130

Учитывая 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

Случайный вопрос
источник
3
Попробуй http://74.125.226.70и дай мне знать, как это работает :)
Марвин Пинто,
1
Он просто возвращает IP-адрес. 74.125.226.70
RandomQuestion 07
2
И как бы вы получили от этого доменное имя ? Предполагая, что это то, что вам нужно ...
Марвин Пинто,
5
Например http://www.de/или http://www.com/не даст желаемых результатов.
Майкл Конецка,

Ответы:

287

Если вы хотите проанализировать 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:

Приложение Б. Анализ ссылки URI с помощью регулярного выражения

Поскольку алгоритм «первое совпадение-победа» идентичен «жадному» методу устранения неоднозначности, используемому в регулярных выражениях POSIX, естественно и часто использовать регулярное выражение для анализа пяти потенциальных компонентов ссылки URI.

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

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

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

Майк Сэмюэл
источник
2
@Jitendra, я рекомендую вам не работать над их исправлением. Люди, занимающиеся библиотеками Java, уже сделали всю работу за вас.
Майк Сэмюэл,
9
Также для URI netUrl = новый URI ("www.google.com"); netUrl.getHost () возвращает NULL. Думаю, мне все еще нужно проверить http: // или https: //
RandomQuestion
2
@Jitendra www.google.com- это относительный URL-адрес с компонентом пути www.google.com. Например, если http://example.com/принять решение против , вы получите http://example.com/www.google.com.
Майк Сэмюэл
Спасибо, Майк. Если я правильно понял, с библиотекой, вы имеете в виду, использовать URI или регулярное выражение выше?
RandomQuestion 07
2
URI-хост будет пустым, если он содержит специальные символы, например: «öob.se»
inc
80
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
  }
}

Читать далее

Майкл Таримо
источник
15

Вот короткая и простая строка, используемая 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-адреса . Лучший ответ на этот вопрос от Satya , который наводит на мысль гуавы в InternetDomainName.topPrivateDomain ()

публичное логическое значение isTopPrivateDomain ()

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

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

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

Собирая это вместе с тем 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);
  }
}
Kirby
источник
6

Я написал метод (см. Ниже), который извлекает имя домена 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;
}
Адиль Хуссейн
источник
Я думаю , что это может не быть правильным дляhttp://bob.com:8080/service/read?name=robert
Ли Meador
Спасибо, что указали на Ли. Обратите внимание, что я уточнил свой ответ словами «Я уверен, что будут случаи, когда этого будет недостаточно ...». Мой ответ потребует небольших изменений в вашем конкретном случае.
Адиль Хуссейн
3

Я сделал небольшую обработку после создания объекта 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;
migueloop
источник
2

В моем случае мне нужен был только основной домен, а не субдомен (без 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];
    }
    return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
}

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

Laurent
источник
1

попробуйте это: 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;}
Эко Дидик
источник
1
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);
    }
    return null;
}

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

Первая неподходящая группа - это «http», «https» или «»

Вторая неподходящая группа - «www». или ""

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

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

Объединение двух совпадающих групп даст нам имя домена / хоста.

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

cegprakash
источник
0

Если входной 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  "";
        }
    }
spaceMonkey
источник
0

Все вышеперечисленное хорошо. Мне это кажется очень простым и легким для понимания. Извините за цитаты. Я написал его для Groovy внутри класса DataCenter.

static String extractDomainName(String url) {
    int start = url.indexOf('://')
    if (start < 0) {
        start = 0
    } else {
        start += 3
    }
    int end = url.indexOf('/', start)
    if (end < 0) {
        end = url.length()
    }
    String domainName = url.substring(start, end)

    int port = domainName.indexOf(':')
    if (port >= 0) {
        domainName = domainName.substring(0, port)
    }
    domainName
}

А вот несколько тестов junit4:

@Test
void shouldFindDomainName() {
    assert DataCenter.extractDomainName('http://example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('http://subpart.example.com/path/') == 'subpart.example.com'
    assert DataCenter.extractDomainName('http://example.com') == 'example.com'
    assert DataCenter.extractDomainName('http://example.com:18445/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com') == 'example.com'
}
Ли Мидор
источник
0

Один из способов, которыми я работал и работал для всех случаев, - это использование библиотеки Guava и регулярного выражения в сочетании.

public static String getDomainNameWithGuava(String url) throws MalformedURLException, 
  URISyntaxException {
    String host =new URL(url).getHost();
    String domainName="";
    try{
        domainName = InternetDomainName.from(host).topPrivateDomain().toString();
    }catch (IllegalStateException | IllegalArgumentException e){
        domainName= getDomain(url,true);
    }
    return domainName;
}

getDomain () может быть любым обычным методом с регулярным выражением.

Шивам Ядав
источник
0

Чтобы получить фактическое доменное имя без поддомена, я использую:

private String getDomainName(String url) throws URISyntaxException {
    String hostName = new URI(url).getHost();
    if (!hostName.contains(".")) {
        return hostName;
    }
    String[] host = hostName.split("\\.");
    return host[host.length - 2];
}

Обратите внимание, что это не будет работать с доменами второго уровня (например, .co.uk).

nickhoffmann7
источник