Obtener el nombre de dominio de la URL dada

130

Dada una URL, quiero extraer el nombre de dominio (no debe incluir la parte 'www'). La URL puede contener http / https. Aquí está el código de Java que escribí. Aunque parece funcionar bien, ¿hay algún enfoque mejor o hay algunos casos límite que podrían fallar?

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;
}

Entrada: http://google.com/blah

Salida: google.com

Pregunta aleatoria
fuente
3
Trata de http://74.125.226.70decirme cómo funciona :)
Marvin Pinto
1
Simplemente devuelve la dirección IP. 74.125.226.70
RandomQuestion
2
¿Y cómo obtendrías el nombre de dominio de eso? Asumiendo que eso es lo que buscas ..
Marvin Pinto
55
Por ejemplo http://www.de/o http://www.com/no dará los resultados deseados.
Michael Konietzka

Respuestas:

287

Si desea analizar una URL, use java.net.URI. java.net.URLtiene un montón de problemas: su equalsmétodo realiza una búsqueda de DNS, lo que significa que el código que lo usa puede ser vulnerable a ataques de denegación de servicio cuando se usa con entradas no confiables.

"Señor Gosling, ¿por qué hizo que url sea igual de malo?" explica uno de esos problemas. Solo tiene la costumbre de usar en su java.net.URIlugar.

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;
}

Debes hacer lo que quieras.


Aunque parece funcionar bien, ¿hay algún enfoque mejor o hay algunos casos límite que podrían fallar?

Su código como escrito falla para las URL válidas:

  • httpfoo/bar- URL relativa con un componente de ruta que comienza con http.
  • HTTP://example.com/ - el protocolo no distingue entre mayúsculas y minúsculas.
  • //example.com/ - URL relativa del protocolo con un host
  • www/foo - una URL relativa con un componente de ruta que comienza con www
  • wwwexample.com- nombre de dominio que no comienza con www.pero comienza con www.

Las URL jerárquicas tienen una gramática compleja. Si intentas rodar tu propio analizador sin leer cuidadosamente RFC 3986, probablemente te equivoques. Simplemente use el que está integrado en las bibliotecas principales.

Si realmente necesita lidiar con entradas desordenadas que java.net.URIrechaza, consulte RFC 3986 Apéndice B:

Apéndice B. Análisis de una referencia de URI con una expresión regular

Como el algoritmo "first-match-wins" es idéntico al método de desambiguación "codicioso" utilizado por las expresiones regulares POSIX, es natural y común usar una expresión regular para analizar los cinco componentes potenciales de una referencia URI.

La siguiente línea es la expresión regular para descomponer una referencia de URI bien formada en sus componentes.

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

Los números en la segunda línea anterior son solo para ayudar a la legibilidad; indican los puntos de referencia para cada subexpresión (es decir, cada paréntesis emparejado).

Mike Samuel
fuente
2
@Jitendra, te recomiendo que no trabajes en arreglarlos. La gente de las bibliotecas de Java ya ha hecho el trabajo por usted.
Mike Samuel
9
También para URI netUrl = nuevo URI ("www.google.com"); netUrl.getHost () devuelve NULL. Creo que todavía necesito verificar http: // o https: //
RandomQuestion
2
@Jitendra, www.google.comes una URL relativa con un componente de ruta que es www.google.com. Por ejemplo, si se resuelve en contra http://example.com/, obtendrá http://example.com/www.google.com.
Mike Samuel
Gracias Mike. Si entendí correcto, con la biblioteca, quieres decir, ¿usar URI o regex arriba?
RandomQuestion
2
El host URI será nulo si contiene caracteres especiales, por ejemplo: "ö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
  }
}

Lee mas

Michael Tarimo
fuente
15

Aquí hay una línea corta y simple usando InternetDomainName.topPrivateDomain()en guayaba:InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

Dado http://www.google.com/blah, eso te dará google.com. O, dado http://www.google.co.mx, te dará google.co.mx.

Como Sa Qada comentó en otra respuesta en esta publicación , esta pregunta se ha hecho anteriormente: extraer el nombre de dominio principal de una URL dada . La mejor respuesta a esa pregunta es de Satya , quien sugiere InternetDomainName.topPrivateDomain () de Guava

public boolean isTopPrivateDomain ()

Indica si este nombre de dominio se compone de exactamente un componente de subdominio seguido de un sufijo público. Por ejemplo, devuelve verdadero para google.com y foo.co.uk, pero no para www.google.com o co.uk.

Advertencia: Un resultado verdadero de este método no implica que el dominio esté en el nivel más alto que sea direccionable como host, ya que muchos sufijos públicos también son hosts direccionables. Por ejemplo, el dominio bar.uk.com tiene un sufijo público de uk.com, por lo que volvería verdadero a partir de este método. Pero uk.com es en sí mismo un host direccionable.

Este método se puede usar para determinar si un dominio es probablemente el nivel más alto para el que se pueden establecer cookies, aunque incluso eso depende de las implementaciones de controles de cookies de los navegadores individuales. Ver RFC 2109 para más detalles.

Poner eso junto con URL.getHost(), que la publicación original ya contiene, te da:

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
fuente
6

Escribí un método (ver más abajo) que extrae el nombre de dominio de una url y que usa una simple coincidencia de cadenas. Lo que realmente hace es extraer el bit entre el primero "://"(o el índice 0si no está "://"contenido) y el primero subsiguiente "/"(o el índice String.length()si no hay contenido posterior "/"). El "www(_)*."bit precedente restante se corta. Estoy seguro de que habrá casos en los que esto no será lo suficientemente bueno, ¡pero debería ser lo suficientemente bueno en la mayoría de los casos!

La publicación anterior de Mike Samuel dice que la java.net.URIclase podría hacer esto (y era preferible a la java.net.URLclase) pero encontré problemas con la URIclase. Notablemente, URI.getHost()da un valor nulo si la url no incluye el esquema, es decir, el "http(s)"bit.

/**
 * 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;
}
Adil Hussain
fuente
Creo que esto podría no ser correcta parahttp://bob.com:8080/service/read?name=robert
Lee Meador
Gracias por señalar a Lee. Tenga en cuenta que califiqué mi respuesta con "Estoy seguro de que habrá casos en los que esto no será lo suficientemente bueno ...". Mi respuesta necesitará algunas modificaciones para su caso particular.
Adil Hussain
3

Hice un pequeño tratamiento después de la creación del objeto 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
fuente
2

En mi caso, solo necesitaba el dominio principal y no el subdominio (no "www" o lo que sea el subdominio):

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];
}

Con este método, la url " https://rest.webtoapp.io/llSlider?lg=en&t=8 " tendrá para el dominio "webtoapp.io".

Laurent
fuente
1

pruebe este: java.net.URL;
JOptionPane.showMessageDialog (null, getDomainName (nueva 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;}
Eko Didik
fuente
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;
}

Explicación: La expresión regular tiene 4 grupos. Los dos primeros son grupos no coincidentes y los dos siguientes son grupos coincidentes.

El primer grupo no coincidente es "http" o "https" o ""

El segundo grupo no coincidente es "www". o ""

El segundo grupo coincidente es el dominio de nivel superior.

El primer grupo coincidente es cualquier cosa después de los grupos no coincidentes y cualquier cosa antes del dominio de nivel superior

La concatenación de los dos grupos coincidentes nos dará el nombre de dominio / host.

PD: tenga en cuenta que puede agregar cualquier cantidad de dominios compatibles a la expresión regular.

cegprakash
fuente
0

Si la url de entrada es entrada del usuario. Este método proporciona el nombre de host más apropiado. si no se encuentra, devuelve la url de entrada.

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  "";
        }
    }
mono espacial
fuente
0

Todo lo anterior es bueno. Este me parece muy simple y fácil de entender. Disculpe las citas. Lo escribí para Groovy dentro de una clase llamada 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
}

Y aquí hay algunas pruebas 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'
}
Lee Meador
fuente
0

Una de las formas en que lo hice y trabajé para todos los casos es usar la Biblioteca de guayaba y la expresión regular en combinación.

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 () puede ser cualquier método común con regex.

Shivam Yadav
fuente
0

Para obtener el nombre de dominio real, sin el subdominio, uso:

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];
}

Tenga en cuenta que esto no funcionará con dominios de segundo nivel (como .co.uk).

nickhoffmann7
fuente