web-dev-qa-db-fra.com

Obtenir le sous-domaine à partir d'une URL

Obtenir le sous-domaine à partir d'une URL semble facile au début.

http://www.domain.example

Balayez pour la première période puis retournez ce qui est arrivé après le "http: //" ...

Alors tu te souviens

http://super.duper.domain.example

Oh. Alors, vous pensez, d'accord, trouvez la dernière période, retournez un mot et récupérez tout avant! 

Alors tu te souviens

http://super.duper.domain.co.uk

Et vous êtes de retour à la case départ. Quelqu'un a-t-il de bonnes idées en plus de stocker une liste de tous les TLD?

98
jb.

Quelqu'un a-t-il de bonnes idées en plus. stocker une liste de tous les TLD?

Non, car chaque TLD diffère par ce qui compte en tant que sous-domaine, domaine de second niveau, etc.

N'oubliez pas qu'il existe des domaines de premier niveau, des domaines de second niveau et des sous-domaines. Techniquement, tout sauf le TLD est un sous-domaine.

Dans l'exemple domain.com.uk, domain est un sous-domaine, com est un domaine de second niveau et uk est le tld.

La question reste donc plus complexe qu’au premier abord et dépend de la manière dont chaque TLD est géré. Vous aurez besoin d'une base de données de tous les TLD comprenant leur partitionnement particulier, ainsi que ce qui compte comme domaine de second niveau et sous-domaine. Il n'y a pas trop de TLD, cependant, la liste est relativement gérable, mais collecter toutes ces informations n'est pas anodin. Une telle liste est peut-être déjà disponible.

On dirait que http://publicsuffix.org/ est l'une de ces listes - tous les suffixes courants (.com, .co.uk, etc.) dans une liste adaptée à la recherche. Il ne sera toujours pas facile de l'analyser, mais au moins vous ne devez pas maintenir la liste. 

Un "suffixe public" est un suffixe sous lequel Les internautes peuvent s’inscrire directement des noms. Quelques exemples de public les suffixes sont ".com", ".co.uk" et "pvt.k12.wy.us". Le suffixe public La liste est une liste de tous les publics connus suffixes.

La liste des suffixes publics est un initiative de la fondation Mozilla . Il est disponible pour une utilisation dans n'importe quel logiciel, mais a été créé à l'origine pour répondre aux besoins du navigateur fabricants. Il permet aux navigateurs de, par exemple:

  • Évitez de définir des "super-biscuits" préjudiciables à la vie privée. suffixes de noms de domaine de haut niveau
  • Mettez en surbrillance la partie la plus importante d'un nom de domaine chez l'utilisateur interface
  • Triez avec précision les entrées d'historique par site

En regardant à travers la liste , vous pouvez voir que ce n'est pas un problème trivial. Je pense qu'une liste est le seul moyen correct d'y parvenir ...

-Adam

68
Adam Davis

Comme Adam le dit, ce n'est pas facile et actuellement, le seul moyen pratique consiste à utiliser une liste.

Même dans ce cas, il existe des exceptions - par exemple, dans .uk, quelques domaines valides immédiatement à ce niveau ne sont pas dans .co.uk; ils doivent donc être ajoutés en tant qu'exceptions.

C’est actuellement ce que font les principaux navigateurs - il est nécessaire de s’assurer que example.co.uk ne peut pas définir de cookie pour .co.uk qui serait ensuite envoyé à un autre site Web sous .co.uk.

La bonne nouvelle est qu’une liste est déjà disponible sur http://publicsuffix.org/ .

Il y a aussi du travail dans IETF pour créer une sorte de standard permettant aux TLD de déclarer la structure de leur domaine. Ceci est toutefois légèrement compliqué par le code suivant: .uk.com, qui fonctionne comme s'il s'agissait d'un suffixe public, mais qui n'est pas vendu par le registre .com.

25
Alnitak

Publicsuffix.org semble être la solution. Il existe de nombreuses implémentations pour analyser facilement le contenu du fichier de données publicuffix:

21
JohnTESlade

Comme déjà dit par Adam et John publicsuffix.org est la voie à suivre. Mais, si pour une raison quelconque vous ne pouvez pas utiliser cette approche, voici une heuristique basée sur une hypothèse qui marche pour 99% des domaines:

Il existe une propriété qui distingue (pas tous, mais presque tous) les "vrais" domaines des sous-domaines et des TLD: il s'agit de l'enregistrement MX du DNS. Vous pouvez créer un algorithme qui recherche ceci: Supprimez une à une les parties du nom d'hôte et interrogez le DNS jusqu'à ce que vous trouviez un enregistrement MX. Exemple:

super.duper.domain.co.uk => no MX record, proceed
duper.domain.co.uk       => no MX record, proceed
domain.co.uk             => MX record found! assume that's the domain

Voici un exemple en php:

function getDomainWithMX($url) {
    //parse hostname from URL 
    //http://www.example.co.uk/index.php => www.example.co.uk
    $urlParts = parse_url($url);
    if ($urlParts === false || empty($urlParts["Host"])) 
        throw new InvalidArgumentException("Malformed URL");

    //find first partial name with MX record
    $hostnameParts = explode(".", $urlParts["Host"]);
    do {
        $hostname = implode(".", $hostnameParts);
        if (checkdnsrr($hostname, "MX")) return $hostname;
    } while (array_shift($hostnameParts) !== null);

    throw new DomainException("No MX record found");
}
9
Francois Bourgeois

Je viens juste d’écrire un programme pour cela en utilisant les informations de publicsuffix.org:

https://github.com/isaksky/url_dom

Par exemple:

(parse "sub1.sub2.domain.co.uk") 
;=> {:public-suffix "co.uk", :domain "domain.co.uk", :rule-used "*.uk"}
1
Isak

Pour une bibliothèque C (avec génération de table de données en Python), j’ai écrit http://code.google.com/p/domain-registry-provider/ , qui est à la fois rapide et économe en espace.

La bibliothèque utilise environ 30 Ko pour les tables de données et environ 10 Ko pour le code C. Il n'y a pas de surcharge de démarrage puisque les tables sont construites au moment de la compilation. Voir http://code.google.com/p/domain-registry-provider/wiki/DesignDoc pour plus de détails.

Pour mieux comprendre le code de génération de table (Python), commencez ici: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Pour mieux comprendre l'API C, voir: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h

1
Bryan McQuade

Comme déjà dit Liste des suffixes publics n’est qu’un moyen d’analyser correctement le domaine. Pour PHP, vous pouvez essayer TLDExtract . Voici un exemple de code:

$extract = new LayerShifter\TLDExtract\Extract();

$result = $extract->parse('super.duper.domain.co.uk');
$result->getSubdomain(); // will return (string) 'super.duper'
$result->getSubdomains(); // will return (array) ['super', 'duper']
$result->getHostname(); // will return (string) 'domain'
$result->getSuffix(); // will return (string) 'co.uk'
1

Vous pouvez utiliser cette API lib tld.js: JavaScript pour travailler avec des noms de domaine, des sous-domaines et des URI complexes.

tldjs.getDomain('mail.google.co.uk');
// -> 'google.co.uk'

Si vous obtenez le domaine racine dans le navigateur. Vous pouvez utiliser cette lib AngusFu/browser-root-domain

var KEY = '__rT_dM__' + (+new Date());
var R = new RegExp('(^|;)\\s*' + KEY + '=1');
var Y1970 = (new Date(0)).toUTCString();

module.exports = function getRootDomain() {
  var domain = document.domain || location.hostname;
  var list = domain.split('.');
  var len = list.length;
  var temp = '';
  var temp2 = '';

  while (len--) {
    temp = list.slice(len).join('.');
    temp2 = KEY + '=1;domain=.' + temp;

    // try to set cookie
    document.cookie = temp2;

    if (R.test(document.cookie)) {
      // clear
      document.cookie = temp2 + ';expires=' + Y1970;
      return temp;
    }
  }
};

L'utilisation d'un cookie est délicate.

0
xiaoyu2er

Cela ne fonctionne pas exactement, mais vous pourriez peut-être obtenir une réponse utile en essayant de récupérer le domaine, morceau par morceau, et en vérifiant la réponse, par exemple, fetch ' http: // uk ', puis ' http: //co.uk ', puis' http://domain.co.uk '. Lorsque vous obtenez une réponse sans erreur, vous obtenez le domaine et le reste est un sous-domaine.

Parfois tu dois juste l'essayer :)

Modifier:

Tom Leys souligne dans les commentaires que certains domaines sont configurés uniquement sur le sous-domaine www, ce qui nous donnerait une réponse incorrecte dans le test ci-dessus. Bon point! La meilleure approche serait peut-être de vérifier chaque partie avec ' http: // www ' ainsi qu'avec 'http: //', et de compter le nombre de résultats correspondant à l'un des succès de cette section du nom de domaine? Il nous manque encore des arrangements «alternatifs» tels que «web.domain.com», mais je ne les ai pas rencontrés depuis un moment :)

0
jTresidder

Je viens d'écrire une bibliothèque objc: https://github.com/kejinlu/KKDomain

0
Luke
echo tld('http://www.example.co.uk/test?123'); // co.uk

/**
 * http://publicsuffix.org/
 * http://www.alandix.com/blog/code/public-suffix/
 * http://tobyinkster.co.uk/blog/2007/07/19/php-domain-class/
 */
function tld($url_or_domain = null)
{
    $domain = $url_or_domain ?: $_SERVER['HTTP_Host'];
    preg_match('/^[a-z]+:\/\//i', $domain) and 
        $domain = parse_url($domain, PHP_URL_Host);
    $domain = mb_strtolower($domain, 'UTF-8');
    if (strpos($domain, '.') === false) return null;

    $url = 'http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1';

    if (($rules = file($url)) !== false)
    {
        $rules = array_filter(array_map('trim', $rules));
        array_walk($rules, function($v, $k) use(&$rules) { 
            if (strpos($v, '//') !== false) unset($rules[$k]);
        });

        $segments = '';
        foreach (array_reverse(explode('.', $domain)) as $s)
        {
            $wildcard = rtrim('*.'.$segments, '.');
            $segments = rtrim($s.'.'.$segments, '.');

            if (in_array('!'.$segments, $rules))
            {
                $tld = substr($wildcard, 2);
                break;
            }
            elseif (in_array($wildcard, $rules) or 
                    in_array($segments, $rules))
            {
                $tld = $segments;
            }
        }

        if (isset($tld)) return $tld;
    }

    return false;
}
0
Mike

Utilisez URIBuilder Puis obtenez l'attribut URIBUilder.Host Divisez-le en un tableau sur "." Vous avez maintenant un tableau avec le domaine séparé.

0
jrr

Si vous souhaitez extraire des sous-domaines et/ou des domaines à partir d'une liste arbitraire d'URL, ce script python peut être utile. Attention cependant, ce n'est pas parfait. C’est un problème délicat à résoudre en général et il est très utile si vous avez une liste blanche des domaines que vous attendez.

  1. Obtenez les domaines de premier niveau de publicsuffix.org
 demandes d'importation 

 url = 'https://publicsuffix.org/list/public_suffix_list.dat'
page = requests.get (url) 

 domains = []
 pour ligne dans page.text.splitlines (): 
 si line.startswith ('//'):
 continuer
 autre:
 domaine = line.strip () 
 si domaine: 
 domains.append (domain) 

 domains = [d [2:] si d.startswith ('*.') sinon d pour d dans les domaines] 
 print ('found {} domains'.format (len (domaines))) 
  1. Construire une regex
 import re 

_ regex = '' 
 pour le domaine dans les domaines: 
 _regex + = r '{} |' .format (domain.replace ('.', '\.')) 

 subdomain_regex = r '/([^/]*)\.[^/. ] + \. ({}) /.*$ '. format (_regex) 
 domain_regex = r' ([^ /.] + \. ({})) /.** '. format (_regex)
  1. Utilisez regex sur la liste des URL
 FILE_NAME = '' # insère le nom du fichier CSV ici 
 URL_COLNAME = '' # insère son nom de colonne ici 

 Importer des pandas en tant que pd 

 Df = pd.read_csv (FILE_NAME) 
 urls = df [URL_COLNAME] .astype (str) + '/' # remarque: ajouter/comme un hack pour aider l'expression rationnelle 

 df ['sous_domaine_extracté'] = urls.str.extract (pat = subdomain_regex, expand = True) [0] 
 df ['domain_extreated'] = urls.str.extract (pat = domaine_regex, expand = True) [0] 

 df.to_csv ('extract_domains.csv ', index = False) 
0
AlexG