Obtenir le nom de domaine à partir de l'URL donnée

130

Étant donné une URL, je souhaite extraire le nom de domaine (il ne doit pas inclure la partie «www»). L'URL peut contenir http / https. Voici le code java que j'ai écrit. Bien que cela semble fonctionner correctement, existe-t-il une meilleure approche ou existe-t-il des cas extrêmes qui pourraient échouer.

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

Entrée: http://google.com/blah

Sortie: google.com

Question aléatoire
la source
3
Essayez de http://74.125.226.70me faire savoir comment cela fonctionne :)
Marvin Pinto
1
Il renvoie simplement l'adresse IP. 74.125.226.70
RandomQuestion
2
Et comment obtiendriez-vous le nom de domaine ? En supposant que c'est ce que vous recherchez ..
Marvin Pinto
5
Par exemple http://www.de/ou http://www.com/ne donnera pas les résultats souhaités.
Michael Konietzka

Réponses:

287

Si vous souhaitez analyser une URL, utilisez java.net.URI. java.net.URLa un tas de problèmes - sa equalsméthode effectue une recherche DNS, ce qui signifie que le code qui l'utilise peut être vulnérable aux attaques par déni de service lorsqu'il est utilisé avec des entrées non fiables.

"M. Gosling - pourquoi avez-vous fait que l'URL est nul?" explique un de ces problèmes. Prenez simplement l'habitude d'utiliser à la java.net.URIplace.

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

devrait faire ce que vous voulez.


Bien que cela semble fonctionner correctement, existe-t-il une meilleure approche ou existe-t-il des cas extrêmes qui pourraient échouer.

Votre code tel qu'il est écrit échoue pour les URL valides:

  • httpfoo/bar- URL relative avec un composant de chemin commençant par http.
  • HTTP://example.com/ - le protocole est insensible à la casse.
  • //example.com/ - URL relative du protocole avec un hôte
  • www/foo - une URL relative avec un composant de chemin commençant par www
  • wwwexample.com- nom de domaine qui ne commence pas par www.mais commence par www.

Les URL hiérarchiques ont une grammaire complexe. Si vous essayez de lancer votre propre analyseur sans lire attentivement la RFC 3986, vous vous tromperez probablement. Utilisez simplement celui qui est intégré aux bibliothèques principales.

Si vous avez vraiment besoin de gérer des entrées désordonnées qui java.net.URIrejettent, consultez RFC 3986, annexe B:

Annexe B.Analyse d'une référence URI avec une expression régulière

Comme l'algorithme "first-match-wins" est identique à la méthode de désambiguïsation "gourmande" utilisée par les expressions régulières POSIX, il est naturel et courant d'utiliser une expression régulière pour analyser les cinq composants potentiels d'une référence URI.

La ligne suivante est l'expression régulière pour décomposer une référence URI bien formée en ses composants.

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

Les chiffres de la deuxième ligne ci-dessus ne servent qu'à faciliter la lecture; ils indiquent les points de référence pour chaque sous-expression (c.-à-d. chaque parenthèse appariée).

Mike Samuel
la source
2
@Jitendra, je vous recommande de ne pas travailler pour les réparer. Les gens des bibliothèques Java ont déjà fait le travail pour vous.
Mike Samuel
9
Aussi pour l'URI netUrl = new URI ("www.google.com"); netUrl.getHost () renvoie NULL. Je pense que je dois encore vérifier http: // ou https: //
RandomQuestion
2
@Jitendra, www.google.comest une URL relative avec un composant de chemin qui est www.google.com. Par exemple, si résolu contre http://example.com/, vous obtiendrez http://example.com/www.google.com.
Mike Samuel
Merci Mike ,. Si j'ai bien compris, avec la bibliothèque, vous voulez dire, utilisez l'URI ou le regex ci-dessus?
RandomQuestion
2
L'hôte URI sera nul s'il contient des caractères spéciaux, par exemple: "ö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
  }
}

Lire la suite

Michael Tarimo
la source
15

Voici une ligne courte et simple utilisant InternetDomainName.topPrivateDomain()dans Guava:InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

Étant donné http://www.google.com/blah, cela vous donnera google.com. Ou, étant donné http://www.google.co.mx, cela vous donnera google.co.mx.

Comme Sa Qada l'a commenté dans une autre réponse sur ce post , cette question a été posée plus tôt: Extraire le nom de domaine principal d'une URL donnée . La meilleure réponse à cette question est de Satya , qui suggère InternetDomainName.topPrivateDomain () de Guava

public booléen isTopPrivateDomain ()

Indique si ce nom de domaine est composé d'exactement un composant de sous-domaine suivi d'un suffixe public. Par exemple, renvoie true pour google.com et foo.co.uk, mais pas pour www.google.com ou co.uk.

Avertissement: un résultat vrai de cette méthode n'implique pas que le domaine est au niveau le plus élevé qui est adressable en tant qu'hôte, car de nombreux suffixes publics sont également des hôtes adressables. Par exemple, le domaine bar.uk.com a un suffixe public de uk.com, donc il renvoie true à partir de cette méthode. Mais uk.com est lui-même un hôte adressable.

Cette méthode peut être utilisée pour déterminer si un domaine est probablement le niveau le plus élevé pour lequel les cookies peuvent être définis, même si cela dépend de la mise en œuvre des contrôles de cookies par les navigateurs individuels. Voir RFC 2109 pour plus de détails.

Mettre cela avec URL.getHost(), que le message original contient déjà, vous donne:

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
la source
6

J'ai écrit une méthode (voir ci-dessous) qui extrait le nom de domaine d'une URL et qui utilise une simple correspondance String. Ce qu'il fait réellement est d'extraire le bit entre le premier "://"(ou index 0s'il n'y en a pas "://") et le premier suivant "/"(ou index String.length()s'il n'y a pas de suivant "/"). Le "www(_)*."bit précédent restant est coupé. Je suis sûr qu'il y aura des cas où cela ne sera pas assez bon mais cela devrait être assez bon dans la plupart des cas!

Le message de Mike Samuel ci-dessus dit que la java.net.URIclasse pouvait le faire (et était préférée à la java.net.URLclasse) mais j'ai rencontré des problèmes avec la URIclasse. Notamment, URI.getHost()donne une valeur nulle si l'url n'inclut pas le schéma, c'est-à-dire le "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
la source
Je pense que cela pourrait ne pas être correct pourhttp://bob.com:8080/service/read?name=robert
Lee Meador
Merci d'avoir signalé Lee. Notez que j'ai nuancé ma réponse par "Je suis sûr qu'il y aura des cas où cela ne suffira pas ...". Ma réponse devra être légèrement modifiée pour votre cas particulier.
Adil Hussain
3

J'ai fait un petit traitement après la création de l'objet 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
la source
2

Dans mon cas, je n'avais besoin que du domaine principal et non du sous-domaine (pas de "www" ou quel que soit le sous-domaine):

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

Avec cette méthode, l'url " https://rest.webtoapp.io/llSlider?lg=en&t=8 " aura pour domaine "webtoapp.io".

Laurent
la source
1

essayez celui-ci: java.net.URL;
JOptionPane.showMessageDialog (null, getDomainName (nouvelle 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
la source
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;
}

Explication: Le regex a 4 groupes. Les deux premiers sont des groupes non correspondants et les deux suivants sont des groupes correspondants.

Le premier groupe qui ne correspond pas est "http" ou "https" ou ""

Le deuxième groupe non correspondant est «www». ou ""

Le deuxième groupe correspondant est le domaine de premier niveau

Le premier groupe correspondant est tout ce qui suit les groupes non correspondants et tout ce qui se trouve avant le domaine de premier niveau

La concaténation des deux groupes correspondants nous donnera le nom de domaine / hôte.

PS: notez que vous pouvez ajouter n'importe quel nombre de domaines pris en charge à l'expression régulière.

cegprakash
la source
0

Si l'URL d'entrée est une entrée utilisateur. cette méthode donne le nom d'hôte le plus approprié. s'il n'est pas trouvé, renvoie l'url d'entrée.

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  "";
        }
    }
espaceMonkey
la source
0

Tout ce qui précède est bon. Celui-ci me semble vraiment simple et facile à comprendre. Excusez les citations. Je l'ai écrit pour Groovy dans une classe appelée 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
}

Et voici quelques tests 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
la source
0

Une des façons dont j'ai fait et travaillé pour tous les cas consiste à utiliser Guava Library et regex en combinaison.

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 () peut être n'importe quelle méthode courante avec regex.

Shivam Yadav
la source
0

Pour obtenir le nom de domaine réel, sans le sous-domaine, j'utilise:

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

Notez que cela ne fonctionnera pas avec les domaines de second niveau (comme .co.uk).

nickhoffmann7
la source