Obtener el subdominio de una URL


100

Obtener el subdominio de una URL parece fácil al principio.

http://www.domain.example

Escanee el primer período y luego devuelva lo que vino después de "http: //" ...

Entonces te acuerdas

http://super.duper.domain.example

Oh. Entonces piensas, está bien, encuentra el último punto, retrocede una palabra y obtén todo antes.

Entonces te acuerdas

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

Y has vuelto al punto de partida. ¿Alguien tiene alguna gran idea además de almacenar una lista de todos los TLD?


Esta pregunta ya se ha hecho aquí: Obtener partes de una edición de URL : Aquí se ha hecho una pregunta similar
:)

¿Le aclaras lo que quieres? Parece que busca la parte de dominio "oficial" de la URL (es decir, dominio.co.uk), independientemente de cuántas etiquetas DNS aparezcan antes.
Alnitak

No creo que sea la misma pregunta, esto parece ser más sobre los recortes administrativos en el nombre de dominio que no se pueden resolver con solo mirar la cadena
Alnitak

Estoy de acuerdo. Amplíe más sobre cuál es su objetivo final.
BuddyJoe

Respuestas:


73

¿Alguien tiene alguna gran idea además de almacenar una lista de todos los TLD?

No, porque cada TLD difiere en lo que cuenta como subdominio, dominio de segundo nivel, etc.

Tenga en cuenta que existen dominios de nivel superior, dominios de segundo nivel y subdominios. Técnicamente hablando, todo excepto el TLD es un subdominio.

En el ejemplo de domain.com.uk, "dominio" es un subdominio, "com" es un dominio de segundo nivel y "uk" es el TLD.

Por tanto, la cuestión sigue siendo más compleja que a primera vista y depende de cómo se gestione cada TLD. Necesitará una base de datos de todos los TLD que incluyen su partición particular y lo que cuenta como dominio de segundo nivel y subdominio. Sin embargo, no hay demasiados TLD, por lo que la lista es razonablemente manejable, pero recopilar toda esa información no es trivial. Es posible que ya exista una lista de este tipo.

Parece que http://publicsuffix.org/ es una de esas listas: todos los sufijos comunes (.com, .co.uk, etc.) en una lista adecuada para la búsqueda. Aún no será fácil analizarlo, pero al menos no tiene que mantener la lista.

Un "sufijo público" es aquel bajo el cual los usuarios de Internet pueden registrar nombres directamente. Algunos ejemplos de sufijos públicos son ".com", ".co.uk" y "pvt.k12.wy.us". La lista de sufijos públicos es una lista de todos los sufijos públicos conocidos.

La lista de sufijos públicos es una iniciativa de la Fundación Mozilla. Está disponible para su uso en cualquier software, pero se creó originalmente para satisfacer las necesidades de los fabricantes de navegadores. Permite a los navegadores, por ejemplo:

  • Evite que se establezcan "supercookies" que dañan la privacidad para sufijos de nombres de dominio de alto nivel
  • Resalte la parte más importante de un nombre de dominio en la interfaz de usuario
  • Ordene con precisión las entradas del historial por sitio

Mirando la lista , puede ver que no es un problema trivial. Creo que una lista es la única forma correcta de lograr esto ...


Mozilla tiene un código que utiliza este servicio. El proyecto se escindió porque la especificación de cookies original había vinculado los TLD a la confianza en las cookies, pero nunca funcionó. El error "Cookie Monster" fue el primer problema y la arquitectura nunca fue reparada ni reemplazada.
benc

El idioma preferido para resolver esto no está en la lista, pero hay un proyecto de código abierto que usa esta lista en código C # aquí: code.google.com/p/domainname-parser
Dan Esparza

Si un dominio es un "sufijo público" o no, debería estar disponible a través del propio protocolo DNS, quizás a través de una bandera EDNS. En ese caso, el propietario puede configurarlo y no es necesario mantener una lista separada.
Pieter Ennes

@PieterEnnes EDNS es para indicadores "relacionados con el transporte" y no se puede usar para metadatos relacionados con el contenido. Estoy de acuerdo en que esta información estaría mejor ubicada en el propio DNS. ISTR hay planes para una "sesión de BoF" en el próximo IETF en Vancouver para discutir esto.
Alnitak

26

Como dice Adam, no es fácil y actualmente la única forma práctica es utilizar una lista.

Incluso entonces hay excepciones, por ejemplo, .ukhay un puñado de dominios que son válidos inmediatamente en ese nivel que no están .co.ukincluidos, por lo que deben agregarse como excepciones.

Actualmente, así es como lo hacen los navegadores convencionales: es necesario asegurarse de que example.co.ukno se pueda establecer una cookie para la .co.ukque luego se enviaría a cualquier otro sitio web .co.uk.

La buena noticia es que ya hay una lista disponible en http://publicsuffix.org/ .

También hay algo de trabajo en el IETF para crear algún tipo de estándar que permita a los TLD declarar cómo se ve su estructura de dominio. Sin embargo, esto es un poco complicado para los gustos de .uk.com, que se opera como si fuera un sufijo público, pero el .comregistro no lo vende .


1
Eugh, el IETF debería saber mejor que dejar morir sus URL. El borrador (actualizado por última vez en septiembre de 2012) ahora se puede acceder aquí: tools.ietf.org/html/draft-pettersen-subtld-structure
IMSoP

El grupo de trabajo del IETF sobre el tema (DBOUND) ha sido cerrado.
Patrick Mevzek

Tenga en cuenta que desde que escribí esto, el .ukregistro de dominio ahora permite los registros directamente en el segundo nivel. Esto se refleja en consecuencia en el PSL.
Alnitak

22

Publicsuffix.org parece la forma de hacerlo. Existen muchas implementaciones para analizar fácilmente el contenido del archivo de datos publicsuffix:


2
¡Pero recuerde que no es solo una cuestión de análisis! Esta lista en Publicsuffix.org es un proyecto no oficial, que está incompleto (falta eu.org, por ejemplo), NO refleja automáticamente las políticas de TLD y puede dejar de mantenerse en cualquier momento.
bortzmeyer


7
La lista en publicsuffix.org no es "no oficial" más que cualquier otra cosa que haga Mozilla. Dado que Mozilla, Opera y Chrome lo usan, es poco probable que no se le dé mantenimiento. En cuanto a estar incompleto, cualquier operador de un dominio como eu.org puede solicitar la inclusión si lo desea y comprende las consecuencias de hacerlo. Si desea agregar un dominio, haga que el propietario lo solicite. Sí, no refleja automáticamente la política de TLD, pero nada lo hace: no existe una fuente programática de esa información.
Gervase Markham

dagger / android: okhttp le dará topPrivateDomain
bladerunner

9

Como ya dijeron Adam y John, publicsuffix.org es el camino correcto a seguir. Pero, si por alguna razón no puede usar este enfoque, aquí hay una heurística basada en una suposición que funciona para el 99% de todos los dominios:

Hay una propiedad que distingue (no todos, pero casi todos) los dominios "reales" de los subdominios y TLD y ese es el registro MX del DNS. Puede crear un algoritmo que busque esto: elimine las partes del nombre de host una por una y consulte el DNS hasta que encuentre un registro MX. Ejemplo:

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

Aquí hay un ejemplo 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");
}

¿Es eso lo que también sugiere IETF aquí ?
Ellie Kesselman

1
Incluso publicsuffix.org dice (vea el sexto párrafo) que la forma correcta de hacer esto es a través del DNS, ¡tal como dijo en su respuesta!
Ellie Kesselman

1
Excepto que puede tener un dominio completamente sin un registro MX. Y que el algoritmo será engañado por registros comodín. Y en el lado opuesto, tiene TLD que tienen registros MX (como .aio .axsolo para nombrar algunos).
Patrick Mevzek

@patrick: Estoy totalmente de acuerdo; como dije en la introducción, este algoritmo no es a prueba de balas, es solo una heurística que funciona sorprendentemente bien.
Francois Bourgeois

2

Como ya se dijo, Public Suffix List es solo una forma de analizar el dominio correctamente. Para PHP, puede probar TLDExtract . Aquí hay un código de muestra:

$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

Acabo de escribir un programa para esto en clojure basado en la información de publicsuffix.org:

https://github.com/isaksky/url_dom

Por ejemplo:

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

1

Para una biblioteca C (con generación de tablas de datos en Python), escribí http://code.google.com/p/domain-registry-provider/ que es rápido y eficiente en el espacio.

La biblioteca usa ~ 30kB para las tablas de datos y ~ 10kB para el código C. No hay sobrecarga de inicio ya que las tablas se construyen en tiempo de compilación. Consulte http://code.google.com/p/domain-registry-provider/wiki/DesignDoc para obtener más detalles.

Para comprender mejor el código de generación de tablas (Python), comience aquí: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Para comprender mejor la API de C, consulte: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h


1
También tengo una biblioteca C / C ++ que tiene su propia lista, aunque también se compara con la lista publicsuffix.org. Se llama libtld y funciona en Unix y MS-Windows snapwebsites.org/project/libtld
Alexis Wilke

0

No lo está resolviendo exactamente, pero tal vez pueda obtener una respuesta útil si intenta buscar el dominio pieza por pieza y verifica la respuesta, es decir, busque ' http: // uk ', luego ' http://co.uk ' , luego ' http://domain.co.uk '. Cuando obtiene una respuesta sin error, tiene el dominio y el resto es subdominio.

A veces solo tienes que probarlo :)

Editar:

Tom Leys señala en los comentarios que algunos dominios están configurados solo en el subdominio www, lo que nos daría una respuesta incorrecta en la prueba anterior. ¡Buen punto! ¿Quizás el mejor enfoque sería verificar cada parte con ' http: // www ' así como con 'http: //', y contar una visita como una visita para esa sección del nombre de dominio? Todavía nos faltarían algunos arreglos 'alternativos' como 'web.domain.com', pero no me he encontrado con uno de esos por un tiempo :)


No hay garantía de que x.com apunte a un servidor web en el puerto 80, incluso si www.x.com lo hace. www es un subdominio válido en este caso. Quizás un whois automatizado ayudaría aquí.
Tom Leys

¡Buen punto! Un whois lo aclararía, aunque manteniendo una lista de qué servidores whois usar para qué nivel tld / 2nd significaría resolver el mismo problema para casos extremos.
jTresidder

está asumiendo que hay un servidor HTTP en cada dominio
Francois Bourgeois

No funcionará para .DKy algunos otros, ya que http://dk/funciona como está. Este tipo de heurísticas no son el camino a seguir ...
Patrick Mevzek

0

Utilice URIBuilder y luego obtenga el atributo URIBUilder.host dividirlo en una matriz en "." ahora tiene una matriz con el dominio dividido.


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

Puede usar esta lib tld.js: API de JavaScript para trabajar con nombres de dominio, subdominios y URI complejos.

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

Si obtiene el dominio raíz en el navegador. Puede utilizar esta 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;
    }
  }
};

Usar cookies es complicado.


0

Si está buscando extraer subdominios y / o dominios de una lista arbitraria de URL, este script de Python puede ser útil. Pero ten cuidado, no es perfecto. Este es un problema complicado de resolver en general y es muy útil si tiene una lista blanca de dominios que está esperando.

  1. Obtenga dominios de nivel superior de publicsuffix.org
solicitudes de importación

url = 'https://publicsuffix.org/list/public_suffix_list.dat'
página = solicitudes.get (url)

dominios = []
para la línea en page.text.splitlines ():
    if line.startswith ('//'):
        Seguir
    más:
        dominio = line.strip ()
        si dominio:
            domains.append (dominio)

dominios = [d [2:] if d.startswith ('*.') else d for d in domains]
print ('encontrados {} dominios'. formato (len (dominios)))
  1. Construir expresiones regulares
importar re

_regex = ''
para dominio en dominios:
    _regex + = r '{} |' .format (dominio.replace ('.', '\.'))

subdomain_regex = r '/([^/]*)\.[^/.]+\.({})/.*$'. formato (_regex)
dominio_regex = r '([^ /.] + \. ({})) /.*$'. formato (_regex)
  1. Utilice expresiones regulares en la lista de URL
FILE_NAME = '' # ponga el nombre del archivo CSV aquí
URL_COLNAME = '' # poner aquí el nombre de la columna URL

importar pandas como pd

df = pd.read_csv (NOMBRE DE ARCHIVO)
urls = df [URL_COLNAME] .astype (str) + '/' # nota: agregar / como truco para ayudar a las expresiones regulares

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 ('dominios_extraídos.csv', índice = Falso)


-3

Después de echar un vistazo rápido a la lista publicsuffix.org, parece que podría hacer una aproximación razonable eliminando los tres segmentos finales ("segmento" aquí significa una sección entre dos puntos) de los dominios donde el segmento final tiene dos caracteres de longitud, en el supuesto de que se trata de un código de país y se subdividirá más. Si el segmento final es "nosotros" y el penúltimo segmento también tiene dos caracteres, elimine los últimos cuatro segmentos. En todos los demás casos, elimine los dos últimos segmentos. p.ej:

"ejemplo" no tiene dos caracteres, así que elimine "dominio.example", dejando "www"

"ejemplo" no tiene dos caracteres, así que elimine "dominio.example", dejando "super.duper"

"reino unido" tiene dos caracteres (pero no "nosotros"), así que elimine "dominio.co.uk" y deje "super.duper"

"nosotros" son dos caracteres y es "nosotros", más "wy" también son dos caracteres, así que elimine "pvt.k12.wy.us", dejando "foo".

Tenga en cuenta que, aunque esto funciona para todos los ejemplos que he visto en las respuestas hasta ahora, sigue siendo solo una aproximación razonable. No es del todo correcto, aunque sospecho que es lo más parecido posible sin hacer / obtener una lista real para usar como referencia.


3
Hay muchos casos fallidos. Este es el tipo de algoritmo que los navegadores utilizan para probar y utilizar. No hagas eso, usa el PSL, funciona y hay bibliotecas para ayudarte.
Gervase Markham

Nada prohíbe que los gTLD sean "segmentados" también, este fue el caso al principio de, .NAMEpor ejemplo, cuando solo se podían comprar firstname.lastname.namenombres de dominio. Y en la dirección opuesta, ahora .UStambién es plana, por lo que puede x.y.z.whatever.uscomprar solo whatever.usen el registro y luego su algoritmo fallará.
Patrick Mevzek

1
También sobre ("segmento" aquí significa una sección entre dos puntos) : esto se llama una etiqueta en el mundo DNS, no es necesario inventar un nuevo nombre.
Patrick Mevzek
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.