Ottieni il nome di dominio da un determinato URL


130

Dato un URL, voglio estrarre il nome di dominio (non dovrebbe includere la parte 'www'). L'URL può contenere http / https. Ecco il codice java che ho scritto. Anche se sembra funzionare bene, c'è qualche approccio migliore o ci sono alcuni casi limite, che potrebbero fallire.

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

Input: http://google.com/blah

Uscita: google.com


3
Prova http://74.125.226.70e fammi sapere come funziona :)
Marvin Pinto

1
Restituisce solo l'indirizzo IP. 74.125.226.70
Domanda casuale

2
E come otterresti il nome di dominio da quello? Supponendo che sia quello che stai cercando ..
Marvin Pinto

5
Ad esempio http://www.de/o http://www.com/non darà i risultati desiderati.
Michael Konietzka,

Risposte:


287

Se vuoi analizzare un URL, usa java.net.URI. java.net.URLha un sacco di problemi - èequals metodo esegue una ricerca DNS, il che significa che il codice che lo utilizza può essere vulnerabile agli attacchi denial of service se utilizzato con input non attendibili.

"Mr. Gosling - perché hai fatto schifo url uguale?" spiega uno di questi problemi. Prendi l'abitudine di usare java.net.URIinvece.

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

dovrebbe fare quello che vuoi.


Anche se sembra funzionare bene, c'è qualche approccio migliore o ci sono alcuni casi limite, che potrebbero fallire.

Il tuo codice scritto non riesce per gli URL validi:

  • httpfoo/bar - URL relativo con un componente percorso che inizia con http .
  • HTTP://example.com/ - il protocollo non fa distinzione tra maiuscole e minuscole.
  • //example.com/ - URL relativo del protocollo con un host
  • www/foo - un URL relativo con un componente percorso che inizia con www
  • wwwexample.com- nome di dominio che non inizia con www.ma inizia con www.

Gli URL gerarchici hanno una grammatica complessa. Se provi a rotolare il tuo parser senza leggere attentamente RFC 3986, probabilmente sbaglierai. Usa solo quello integrato nelle librerie principali.

Se hai davvero bisogno di gestire gli input disordinati che java.net.URIrifiutano, vedi RFC 3986 Appendice B:

Appendice B. Analisi di un riferimento URI con un'espressione regolare

Poiché l'algoritmo "first-match-wins" è identico al metodo di disambiguazione "avido" utilizzato dalle espressioni regolari POSIX, è naturale e banale utilizzare un'espressione regolare per analizzare i potenziali cinque componenti di un riferimento URI.

La seguente riga è l'espressione regolare per suddividere un riferimento URI ben formato nei suoi componenti.

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

I numeri nella seconda riga sopra sono solo per aiutare la leggibilità; indicano i punti di riferimento per ciascuna sottoespressione (cioè ogni parentesi accoppiata).


2
@Jitendra, ti consiglio di non lavorare per risolverli. Le biblioteche Java hanno già fatto il lavoro per te.
Mike Samuel,

9
Anche per URI netUrl = nuovo URI ("www.google.com"); netUrl.getHost () restituisce NULL. Penso di aver ancora bisogno di controllare http: // o https: //
RandomQuestion

2
@Jitendra, www.google.comè un URL relativo con un componente path che lo è www.google.com. Ad esempio, se risolto contro http://example.com/, otterresti http://example.com/www.google.com.
Mike Samuel,

Grazie Mike. Se ho capito bene, con libreria, vuoi dire, utilizzare URI o regex sopra?
Domanda casuale

2
L'host URI sarà nullo se contiene caratteri speciali, ad esempio: "ö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
  }
}

Leggi di più


15

Ecco una linea breve e semplice che usa InternetDomainName.topPrivateDomain()in Guava:InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

Dato http://www.google.com/blah, questo ti darà google.com. O, dato http://www.google.co.mx, ti darà google.co.mx.

Come ha commentato Sa Qada in un'altra risposta su questo post , questa domanda è stata posta in precedenza: Estrai il nome di dominio principale da un determinato URL . La migliore risposta a questa domanda è di Satya , che suggerisce InternetDomainName.topPrivateDomain () di Guava

pubblico booleano isTopPrivateDomain ()

Indica se questo nome di dominio è composto esattamente da un componente del sottodominio seguito da un suffisso pubblico. Ad esempio, restituisce true per google.com e foo.co.uk, ma non per www.google.com o co.uk.

Avviso: un vero risultato di questo metodo non implica che il dominio sia al livello più alto che è indirizzabile come host, poiché molti suffissi pubblici sono anche host indirizzabili. Ad esempio, il dominio bar.uk.com ha un suffisso pubblico di uk.com, quindi restituire true da questo metodo. Ma uk.com è di per sé un host indirizzabile.

Questo metodo può essere utilizzato per determinare se un dominio è probabilmente il livello più alto per il quale è possibile impostare i cookie, anche se ciò dipende dalle implementazioni dei controlli dei cookie da parte dei singoli browser. Vedere RFC 2109 per i dettagli.

Metterlo insieme a URL.getHost(), che già contiene il post originale, ti dà:

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

6

Ho scritto un metodo (vedi sotto) che estrae il nome di dominio di un URL e che utilizza una semplice corrispondenza String. Ciò che effettivamente fa è estrarre il bit tra il primo "://"(o l'indice 0se non è "://"contenuto) e il primo successivo "/"(o l'indice String.length()se non c'è successivo "/"). Il "www(_)*."bit precedente rimanente viene eliminato. Sono sicuro che ci saranno casi in cui questo non sarà abbastanza buono, ma dovrebbe essere abbastanza buono nella maggior parte dei casi!

Il post sopra di Mike Samuel dice che la java.net.URIclasse poteva farlo (ed era preferita alla java.net.URLclasse) ma ho riscontrato problemi con la URIclasse. In particolare, URI.getHost()fornisce un valore nullo se l'URL non include lo schema, ovvero il "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;
}

Penso che questo potrebbe non essere corretto perhttp://bob.com:8080/service/read?name=robert
Lee Meador,

Grazie per aver sottolineato Lee. Nota che ho qualificato la mia risposta con "Sono sicuro che ci saranno casi in cui questo non sarà abbastanza buono ...". La mia risposta avrà bisogno di qualche leggera modifica per il tuo caso particolare.
Adil Hussain,

3

Ho fatto un piccolo trattamento dopo la creazione dell'oggetto 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;

2

Nel mio caso avevo solo bisogno del dominio principale e non del sottodominio (nessun "www" o qualunque sia il sottodominio):

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 questo metodo l'URL " https://rest.webtoapp.io/llSlider?lg=en&t=8 " avrà per il dominio "webtoapp.io".


1

prova questo: java.net.URL;
JOptionPane.showMessageDialog (null, getDomainName (nuovo 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;
}

Spiegazione: regex ha 4 gruppi. I primi due sono gruppi non corrispondenti e i due successivi sono gruppi corrispondenti.

Il primo gruppo non corrispondente è "http" o "https" o ""

Il secondo gruppo non corrispondente è "www". o ""

Il secondo gruppo corrispondente è il dominio di primo livello

Il primo gruppo corrispondente è qualsiasi cosa dopo i gruppi non corrispondenti e qualsiasi cosa prima del dominio di primo livello

La concatenazione dei due gruppi corrispondenti ci darà il nome dominio / host.

PS: Nota che puoi aggiungere un numero qualsiasi di domini supportati a regex.


0

Se l'URL di input è input dell'utente. questo metodo fornisce il nome host più appropriato. se non trovato restituisce l'URL di input.

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

0

Tutto quanto sopra è buono. Questo mi sembra davvero semplice e facile da capire. Scusa le virgolette. L'ho scritto per Groovy all'interno di una classe chiamata 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
}

E qui ci sono alcuni test di 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

Uno dei modi in cui ho lavorato e lavorato per tutti i casi è usare Guava Library e regex in combinazione.

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 () può essere qualsiasi metodo comune con regex.


0

Per ottenere il nome di dominio effettivo, senza il sottodominio, utilizzo:

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

Nota che questo non funzionerà con domini di secondo livello (come .co.uk).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.