Ottieni il sottodominio da un URL


100

All'inizio ottenere il sottodominio da un URL sembra facile.

http://www.domain.example

Esegui la scansione del primo punto, quindi restituisci tutto ciò che è venuto dopo "http: //" ...

Allora ti ricordi

http://super.duper.domain.example

Oh. Quindi pensi, okay, trova l'ultimo punto, torna indietro di una parola e prendi tutto prima!

Allora ti ricordi

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

E sei tornato al punto di partenza. Qualcuno ha grandi idee oltre a memorizzare un elenco di tutti i TLD?


Questa domanda è già stata posta qui: Ottenere parti di un URL Modifica: una domanda simile è stata posta qui
:)

Cam chiarisci cosa vuoi? Sembra che tu stia cercando la parte di dominio "ufficiale" dell'URL (ad esempio dominio.co.uk), indipendentemente da quante etichette DNS compaiono prima?
Alnitak

Non penso che sia la stessa domanda - questo sembra riguardare più i tagli amministrativi nel nome di dominio che non possono essere risolti semplicemente guardando la stringa
Alnitak

Sono d'accordo. Espandi di più su qual è il tuo obiettivo finale.
BuddyJoe

Risposte:


73

Qualcuno ha grandi idee oltre a memorizzare un elenco di tutti i TLD?

No, perché ogni TLD differisce per ciò che conta come sottodominio, dominio di secondo livello, ecc.

Tieni presente che esistono domini di primo livello, domini di secondo livello e sottodomini. Tecnicamente parlando, tutto tranne il TLD è un sottodominio.

Nell'esempio domain.com.uk, "domain" è un sottodominio, "com" è un dominio di secondo livello e "uk" è il TLD.

Quindi la domanda rimane più complessa che a prima vista e dipende da come viene gestito ogni TLD. Avrai bisogno di un database di tutti i TLD che includono il loro particolare partizionamento e ciò che conta come dominio di secondo livello e sottodominio. Non ci sono troppi TLD, tuttavia, quindi l'elenco è ragionevolmente gestibile, ma raccogliere tutte queste informazioni non è banale. Potrebbe già essere disponibile un elenco di questo tipo.

Sembra che http://publicsuffix.org/ sia uno di questi elenchi: tutti i suffissi comuni (.com, .co.uk, ecc.) In un elenco adatto per la ricerca. Non sarà ancora facile analizzarlo, ma almeno non devi mantenere l'elenco.

Un "suffisso pubblico" è quello in cui gli utenti di Internet possono registrare direttamente i nomi. Alcuni esempi di suffissi pubblici sono ".com", ".co.uk" e "pvt.k12.wy.us". L'elenco dei suffissi pubblici è un elenco di tutti i suffissi pubblici noti.

L'elenco dei suffissi pubblici è un'iniziativa della Mozilla Foundation. È disponibile per l'uso in qualsiasi software, ma è stato originariamente creato per soddisfare le esigenze dei produttori di browser. Consente ai browser, ad esempio:

  • Evita di impostare "supercookie" dannosi per la privacy per suffissi di nomi di dominio di alto livello
  • Evidenzia la parte più importante di un nome di dominio nell'interfaccia utente
  • Ordina accuratamente le voci della cronologia per sito

Guardando l'elenco , puoi vedere che non è un problema banale. Penso che un elenco sia l'unico modo corretto per ottenere questo risultato ...


Mozilla ha un codice che utilizza questo servizio. Il progetto è stato scorporato perché le specifiche dei cookie originali avevano collegato i TLD alla fiducia nei cookie, ma non hanno mai funzionato. Il bug "Cookie Monster" è stato il primo problema e l'architettura non è mai stata riparata o sostituita.
benc

La lingua preferita per risolvere questo problema non è elencata, ma esiste un progetto opensource che utilizza questo elenco nel codice C # qui: code.google.com/p/domainname-parser
Dan Esparza

Che un dominio sia o meno un "suffisso pubblico" dovrebbe essere reso disponibile tramite il protocollo DNS stesso, magari tramite un flag EDNS. In tal caso il proprietario può impostarlo e non è necessario mantenere un elenco separato.
Pieter Ennes,

@PieterEnnes EDNS è per i flag "relativi al trasporto" e non può essere utilizzato per i metadati relativi al contenuto. Sono d'accordo che questa informazione sarebbe collocata al meglio nel DNS stesso. ISTR ha in programma una "sessione BoF" al prossimo IETF di Vancouver per discuterne.
Alnitak

26

Come dice Adam, non è facile e attualmente l'unico modo pratico è utilizzare un elenco.

Anche in questo caso ci sono delle eccezioni, ad esempio in .ukci sono una manciata di domini che sono validi immediatamente a quel livello che non sono presenti .co.uk, quindi quelli devono essere aggiunti come eccezioni.

Questo è attualmente il modo in cui lo fanno i browser tradizionali: è necessario assicurarsi che example.co.uknon sia possibile impostare un cookie per il .co.ukquale verrebbe inviato a qualsiasi altro sito Web sotto.co.uk .

La buona notizia è che c'è già un elenco disponibile su http://publicsuffix.org/ .

C'è anche del lavoro nell'IETF per creare una sorta di standard per consentire ai TLD di dichiarare l'aspetto della loro struttura di dominio. Questo è un po 'complicato anche se da artisti del calibro di .uk.com, che viene gestito come se fosse un suffisso pubblico, ma non viene venduto dal .comregistro.


1
Basta, l'IETF dovrebbe sapere meglio che lasciare che i propri URL muoiano. La bozza (ultimo aggiornamento nel settembre 2012) può ora essere raggiunta qui: tools.ietf.org/html/draft-pettersen-subtld-structure
IMSoP

Il gruppo di lavoro IETF sull'argomento (DBOUND) è stato chiuso.
Patrick Mevzek

Nota che da quando ho scritto questo, il .ukregistro dei domini ora consente le registrazioni direttamente al secondo livello. Ciò si riflette di conseguenza nel PSL.
Alnitak

22

Publicsuffix.org sembra il modo per farlo. Ci sono molte implementazioni là fuori per analizzare facilmente il contenuto del file di dati publicsuffix:


2
Ma ricorda che non è solo questione di analisi! Questo elenco su Publicsuffix.org è un progetto non ufficiale, che è incompleto (manca eu.org, per esempio), NON riflette automaticamente le politiche di TLD e potrebbe non essere più mantenuto in qualsiasi momento.
bortzmeyer


7
L'elenco su publicsuffix.org non è "non ufficiale" più di qualsiasi altra cosa faccia Mozilla. Dato che Mozilla, Opera e Chrome lo utilizzano, è improbabile che non venga più mantenuto. Per quanto riguarda l'incompletezza, qualsiasi operatore di un dominio come eu.org può richiedere l'inclusione, se lo desidera, e comprende le conseguenze di ciò. Se desideri aggiungere un dominio, chiedi al proprietario di farlo. Sì, non riflette automaticamente la politica TLD, ma in tal caso non lo fa nulla: non esiste una fonte programmatica di tali informazioni.
Gervase Markham

dagger / android: okhttp ti darà il topPrivateDomain
bladerunner

9

Come già detto da Adam e John publicsuffix.org è la strada giusta da percorrere. Ma, se per qualsiasi motivo non è possibile utilizzare questo approccio, ecco un'euristica basata su un presupposto che funziona per il 99% di tutti i domini:

Esiste una proprietà che distingue (non tutti, ma quasi tutti) i domini "reali" dai sottodomini e dai TLD ed è il record MX del DNS. Potresti creare un algoritmo che cerchi questo: Rimuovi le parti del nome host una per una e interroga il DNS finché non trovi un record MX. Esempio:

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

Ecco un esempio in 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");
}

È questo che IETF suggerisce anche qui ?
Ellie Kesselman

1
Anche publicsuffix.org dice (vedi sesto paragrafo) che il modo corretto per farlo è attraverso il DNS, proprio come hai detto nella tua risposta!
Ellie Kesselman,

1
Tranne che puoi avere completamente un dominio senza un record MX. E che l'algoritmo verrà ingannato dai record con caratteri jolly. E sul lato opposto ci sono TLD che hanno record MX (come .aio .axsolo per citarne alcuni).
Patrick Mevzek

@patrick: sono totalmente d'accordo; come ho detto nell'introduzione, questo algoritmo non è a prova di proiettile, è solo un'euristica che funziona sorprendentemente bene.
Francois Bourgeois

2

Come già detto, l'elenco dei suffissi pubblici è solo un modo per analizzare correttamente il dominio. Per PHP puoi provare TLDExtract . Ecco il codice di esempio:

$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

Ho appena scritto un programma per questo in clojure basato sulle informazioni da publicsuffix.org:

https://github.com/isaksky/url_dom

Per esempio:

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

1

Per una libreria C (con generazione di tabelle dati in Python), ho scritto http://code.google.com/p/domain-registry-provider/ che è sia veloce che efficiente in termini di spazio.

La libreria utilizza ~ 30 kB per le tabelle dati e ~ 10 kB per il codice C. Non vi è alcun sovraccarico di avvio poiché le tabelle vengono costruite in fase di compilazione. Vedi http://code.google.com/p/domain-registry-provider/wiki/DesignDoc per maggiori dettagli.

Per comprendere meglio il codice di generazione della tabella (Python), inizia qui: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Per comprendere meglio l'API C, vedere: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h


1
Ho anche una libreria C / C ++ che ha il proprio elenco sebbene sia confrontato anche con l'elenco publicsuffix.org. Si chiama libtld e funziona sotto Unix e MS-Windows snapwebsites.org/project/libtld
Alexis Wilke

0

Non funziona esattamente, ma potresti forse ottenere una risposta utile cercando di recuperare il dominio pezzo per pezzo e controllando la risposta, ad esempio, recupera " http: // uk ", quindi " http://co.uk " , quindi " http://domain.co.uk ". Quando ricevi una risposta non di errore hai il dominio e il resto è sottodominio.

A volte devi solo provarlo :)

Modificare:

Tom Leys sottolinea nei commenti che alcuni domini sono impostati solo sul sottodominio www, il che ci darebbe una risposta errata nel test sopra. Buon punto! Forse l'approccio migliore sarebbe controllare ogni parte con " http: // www " oltre a "http: //" e contare un hit come hit per quella sezione del nome di dominio? Ci mancherebbero ancora alcuni arrangiamenti "alternativi" come "web.domain.com", ma è da un po 'che non ne incontro uno :)


Non vi è alcuna garanzia che x.com punti a un server web sulla porta 80 anche se lo fa www.x.com. www è un sottodominio valido in questo caso. Forse un whois automatizzato potrebbe aiutare qui.
Tom Leys

Buon punto! Un whois lo chiarirebbe, pur mantenendo un elenco di quali server whois usare per quali per quale tld / 2 ° livello significherebbe risolvere lo stesso problema per i casi limite.
jTresidder

stai assumendo che esegua un server HTTP in ogni dominio
Francois Bourgeois

Non funzionerà per .DKe per alcuni altri, così http://dk/com'è. Questo tipo di euristica non è la strada da percorrere ...
Patrick Mevzek

0

Utilizzare URIBuilder quindi ottenere l'attributo URIBUilder.host suddividendolo in un array su "." ora hai un array con il dominio diviso.


0
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

È possibile utilizzare questa lib tld.js: API JavaScript per lavorare con nomi di dominio complessi, sottodomini e URI.

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

Se stai ottenendo il dominio principale nel browser. Puoi usare questo file 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;
    }
  }
};

Usare i cookie è complicato.


0

Se stai cercando di estrarre sottodomini e / o domini da un elenco arbitrario di URL, questo script python potrebbe essere utile. Attenzione però, non è perfetto. Questo è un problema complicato da risolvere in generale ed è molto utile se hai una whitelist di domini che ti aspetti.

  1. Ottieni domini di primo livello da publicsuffix.org
richieste di importazione

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

domini = []
per la riga in page.text.splitlines ():
    se line.startswith ('//'):
        Continua
    altro:
        dominio = line.strip ()
        se dominio:
            domains.append (dominio)

domains = [d [2:] if d.startswith ('*.') else d for d in domains]
print ('found {} domains'.format (len (domains)))
  1. Crea regex
import re

_regex = ''
per dominio in domini:
    _regex + = r '{} |' .format (domain.replace ('.', '\.'))

subdomain_regex = r '/([^/”*)\.[^/.”+\.({})/.*$'. format (_regex)
domain_regex = r '([^ /.] + \. ({})) /.*$'. formato (_regex)
  1. Usa regex nell'elenco di URL
FILE_NAME = '' # inserisce qui il nome del file CSV
URL_COLNAME = '' # inserisci qui il nome della colonna URL

importa i panda come pd

df = pd.read_csv (FILE_NAME)
urls = df [URL_COLNAME] .astype (str) + '/' # nota: aggiunta di / come hack per aiutare regex

df ["sub_domain_extracted"] = urls.str.extract (pat = subdomain_regex, expand = True) [0]
df ["domain_extracted"] = urls.str.extract (pat = domain_regex, expand = True) [0]

df.to_csv ('extracted_domains.csv', index = False)

-1

Elenco di suffissi comuni (.co.uk, .com, eccetera) da eliminare insieme a http: // e quindi avrai solo "sotto.dominio" con cui lavorare invece di " http: // sub. domain.suffix ", o almeno questo è quello che probabilmente farei.

Il problema più grande è l'elenco dei possibili suffissi. C'è molto, dopotutto.


-3

Dopo aver dato una rapida occhiata all'elenco publicsuffix.org, sembra che potresti fare un'approssimazione ragionevole rimuovendo gli ultimi tre segmenti ("segmento" qui significa una sezione tra due punti) dai domini in cui il segmento finale è lungo due caratteri, supponendo che sia un codice paese e verrà ulteriormente suddiviso. Se il segmento finale è "noi" e anche il penultimo segmento è composto da due caratteri, rimuovere gli ultimi quattro segmenti. In tutti gli altri casi, rimuovere gli ultimi due segmenti. per esempio:

"esempio" non è composto da due caratteri, quindi rimuovi "dominio.esempio", lasciando "www"

"example" non è composto da due caratteri, quindi rimuovi "domain.example", lasciando "super.duper"

"uk" è composto da due caratteri (ma non "us"), quindi rimuovi "dominio.co.uk", lasciando "super.duper"

"us" è composto da due caratteri ed è "us", più "wy" è anche due caratteri, quindi rimuovi "pvt.k12.wy.us", lasciando "foo".

Nota che, sebbene questo funzioni per tutti gli esempi che ho visto nelle risposte finora, rimane solo un'approssimazione ragionevole. Non è del tutto corretto, anche se sospetto che sia quanto di più probabile si possa ottenere senza creare / ottenere un elenco effettivo da utilizzare come riferimento.


3
Ci sono molti casi di errore. Questo è il tipo di browser di algoritmi utilizzati per provare e utilizzare. Non farlo, usa il PSL: funziona e ci sono biblioteche per aiutarti.
Gervase Markham

Niente vieta anche di "segmentare" i gTLD, questo era il caso, ad .NAMEesempio, all'inizio , quando si potevano acquistare solo firstname.lastname.namenomi di dominio. E nella direzione opposta, ora .USè anche piatto, quindi puoi avere x.y.z.whatever.ussemplicemente acquistando whatever.usnel registro e quindi il tuo algoritmo fallirà su di esso.
Patrick Mevzek

1
Anche su ("segmento" qui significa una sezione tra due punti) : questa è chiamata etichetta nel mondo DNS, non c'è bisogno di inventare un nuovo nome.
Patrick Mevzek
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.