Obtener el subdominio de una URL
Pregunta
Obtener el subdominio de una URL suena fácil al principio.
http://www.domain.example
Escanee durante el primer período y luego devuelva lo que vino después de " http: // " ...
Entonces recuerdas
http://super.duper.domain.example
Oh. Entonces piensas, está bien, encuentra el último período, retrocede una palabra y obtén todo antes.
Entonces recuerdas
http://super.duper.domain.co.uk
Y vuelves al punto de partida. ¿Alguien tiene alguna idea genial además de almacenar una lista de todos los TLD?
Solución
Alguien tiene grandes ideas 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 hay dominios de nivel superior, dominios de segundo nivel y subdominios. Técnicamente hablando, todo excepto el TLD es un subdominio.
En el ejemplo de dominio.com.uk, " dominio " es un subdominio, " com " es un dominio de segundo nivel, y '' uk '' es el TLD.
Por lo tanto, la pregunta 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 un dominio de segundo nivel y un subdominio. Sin embargo, no hay demasiados TLD, por lo que la lista es razonablemente manejable, pero recopilar toda esa información no es trivial. Puede que ya haya una lista disponible.
Parece que http://publicsuffix.org/ es una de esas listas & # 8212; todos los sufijos comunes ( .com, .co.uk, etc.) en una lista adecuada para la búsqueda. Todavía no será fácil analizarlo, pero al menos no tiene que mantener la lista.
A '' sufijo público '' es uno bajo el cual Los usuarios de Internet pueden registrarse directamente nombres Algunos ejemplos de publico los sufijos son " .com " ;, " .co.uk " y `` pvt.k12.wy.us ''. El sufijo público Lista es una lista de todos los públicos conocidos sufijos.
La Lista de sufijos públicos es un iniciativa de la Fundación Mozilla. Está disponible para su uso en cualquier software, pero fue creado originalmente para satisfacer las necesidades del navegador fabricantes. Permite a los navegadores por ejemplo:
- Evite las supercookies que dañan la privacidad estar preparado para sufijos de nombres de dominio de alto nivel
- Resalte la parte más importante de un nombre de dominio en el usuario interfaz
- Ordenar con precisión las entradas del historial por sitio
Otros consejos
Como dice Adam, no es fácil, y actualmente la única forma práctica es usar una lista.
Incluso entonces hay excepciones: por ejemplo, en .uk
hay un puñado de dominios que son válidos inmediatamente en ese nivel que no están en .co.uk
, por lo que deben agregarse como excepciones.
Así es como lo hacen los navegadores convencionales: es necesario asegurarse de que example.co.uk
no pueda establecer una Cookie para .co.uk
, que luego ser enviado a cualquier otro sitio web en .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 para permitir que los TLD declaren cómo se ve su estructura de dominio. Sin embargo, esto es un poco complicado por los gustos de .uk.com
, que funciona como si fuera un sufijo público, pero no se vende por el registro .com
.
Publicsuffix.org parece el camino a seguir. Hay muchas implementaciones para analizar fácilmente el contenido del archivo de datos publicsuffix:
- Perl: Domain :: PublicSuffix
- Java: http://sourceforge.net/projects/publicsuffix/
- PHP: php-domain-parser
- C # / .NET: https://github.com/danesparza/domainname-parser
- Python: http://pypi.python.org/pypi/publicsuffix
- Ruby: domainatrix , public_suffix
Como ya dijeron Adam y John, publicsuffix.org es el camino correcto. 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 todas, pero casi todas) "real" dominios de 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");
}
Como ya se dijo Lista de sufijos públicos es solo una forma de analizar el dominio correctamente. Para PHP, puede probar TLDExtract . Aquí está el 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'
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"}
Para una biblioteca C (con generación de tabla de datos en Python), escribí http: //code.google.com/p/domain-registry-provider/ que es rápido y eficiente en el espacio.
La biblioteca utiliza ~ 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. Ver http://code.google.com/p/domain-registry- proveedor / wiki / DesignDoc para 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
No está funcionando exactamente, pero tal vez podría obtener una respuesta útil al tratar de obtener el dominio pieza por pieza y verificar la respuesta, es decir, obtener ' http: // uk ', luego' http://co.uk ', luego ' http://domain.co.uk '. Cuando obtiene una respuesta sin errores, obtiene 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 'http: //', y contar un golpe para como un éxito 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 ninguno de ellos por un tiempo :)
Usa el URIBuilder luego obtenga el atributo URIBUilder.host dividirlo en una matriz en ". " ahora tiene una matriz con el dominio dividido.
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;
}
Acabo de escribir una biblioteca objc: https://github.com/kejinlu/KKDomain
Puede usar esta lib tld.js: API de JavaScript para trabajar con nombres de dominio complejos, subdominios y URI .
tldjs.getDomain('mail.google.co.uk');
// -> 'google.co.uk'
Si obtiene dominio raíz en el navegador. Puede usar 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.
Si está buscando extraer subdominios y / o dominios de una lista arbitraria de URL, este script de Python puede ser útil. Sin embargo, ten cuidado, no es perfecto. Este es un problema difícil de resolver en general y es muy útil si tiene una lista blanca de dominios que espera.
- Obtenga dominios de nivel superior de publicsuffix.org
import requests url = 'https://publicsuffix.org/list/public_suffix_list.dat' page = requests.get(url) domains = [] for line in page.text.splitlines(): if line.startswith('//'): continue else: domain = line.strip() if domain: domains.append(domain) domains = [d[2:] if d.startswith('*.') else d for d in domains] print('found {} domains'.format(len(domains)))
- Crear expresiones regulares
import re _regex = '' for domain in domains: _regex += r'{}|'.format(domain.replace('.', '\.')) subdomain_regex = r'/([^/]*)\.[^/.]+\.({})/.*
- Usar expresiones regulares en la lista de URL
FILE_NAME = '' # put CSV file name here URL_COLNAME = '' # put URL column name here import pandas as pd df = pd.read_csv(FILE_NAME) urls = df[URL_COLNAME].astype(str) + '/' # note: adding / as a hack to help 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).format(_regex) domain_regex = r'([^/.]+\.({}))/.*<*>.format(_regex)
- Usar expresiones regulares en la lista de URL
- Usar expresiones regulares en la lista de URL
Lista de sufijos comunes (.co.uk, .com, etcétera) para eliminar junto con http: // y luego solo tendrá "subdominio". para trabajar en lugar de " http: //sub.domain.suffix " ;, o al menos eso es lo que Probablemente lo haría.
El mayor problema es la lista de posibles sufijos. Hay mucho, después de todo.
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 está el segmento final dos caracteres de largo, en el supuesto de que sea un código de país y se subdividirá aún 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 segmentos finales. por ejemplo:
" ejemplo " no son dos caracteres, por lo tanto, elimine " domain.example " ;, dejando " www "
" ejemplo " no son dos caracteres, por lo tanto, elimine " dominio.example " ;, dejando " super.duper "
" reino unido " son dos caracteres (pero no "nosotros"), por lo tanto, elimine "dominio.co.uk", dejando "super.duper"
" nosotros " tiene dos caracteres y es "nosotros", más "wy" también tiene 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 completamente correcto, aunque sospecho que es lo más cercano posible sin hacer / obtener una lista real para usar como referencia.