Получить поддомен с URL-адреса

Получение субдомена из URL-адреса сначала легко.

http://www.domain.example

Отсканируйте первый период, затем верните все, что было после "http://"...

Затем вы помните

http://super.duper.domain.example

О. Итак, тогда вы думаете, хорошо, найдите последний период, верните слово и получите все раньше!

Затем вы помните

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

И ты вернешься к квадрату. У кого-нибудь есть отличные идеи помимо хранения списка всех TLD?

Ответы

Ответ 1

У кого-нибудь есть отличные идеи, кроме хранения списка всех TLD?

Нет, потому что каждый TLD отличается тем, что считается субдоменом, доменом второго уровня и т.д.

Имейте в виду, что есть домены верхнего уровня, домены второго уровня и поддоменов. Технически говоря, все, кроме TLD, является поддоменом.

В примере domain.com.uk "домен" - это поддомен, "com" - это домен второго уровня, а "uk" - это TLD.

Таким образом, вопрос остается более сложным, чем на первый взгляд, и зависит от того, как управляется каждый TLD. Вам понадобится база данных всех TLD, которые включают в себя их конкретное разделение и то, что считается доменом второго уровня и поддоменом. Однако TLD не слишком много, поэтому этот список достаточно управляем, но собрать всю эту информацию нетривиально. Возможно, такой список уже есть.

Похоже, http://publicsuffix.org/ является одним из таких списков - все распространенные суффиксы (.com,.co.uk и т.д.) В списке, подходящем для поиска. Разобрать его все равно будет непросто, но, по крайней мере, вам не нужно вести список.

"Открытый суффикс" - это тот, под которым пользователи Интернета могут напрямую регистрировать имена. Некоторыми примерами общедоступных суффиксов являются ".com", ".co.uk" и "pvt.k12.wy.us". Public Suffix List - это список всех известных общедоступных суффиксов.

Публичный список суффиксов является инициативой фонда Mozilla. Он доступен для использования в любом программном обеспечении, но изначально был создан для удовлетворения потребностей производителей браузеров. Это позволяет браузерам, например:

  • Избегайте использования "супер-куки", нарушающих конфиденциальность, для высокоуровневых суффиксов доменных имен
  • Выделите наиболее важную часть доменного имени в пользовательском интерфейсе
  • Точная сортировка записей истории по сайту

Просматривая список, вы видите, что это не тривиальная проблема. Я думаю, что список является единственным правильным способом сделать это...

Ответ 2

Как говорит Адам, это непросто, и в настоящее время единственным практическим способом является использование списка.

Даже тогда есть исключения - например, в .uk имеется несколько доменов, которые немедленно действительны на этом уровне, которые не находятся в .co.uk, поэтому они должны быть добавлены как исключения.

В настоящее время, как это делают основные браузеры, необходимо убедиться, что example.co.uk не может установить Cookie для .co.uk, который затем будет отправлен на любой другой сайт под .co.uk.

Хорошей новостью является то, что уже существует список доступных http://publicsuffix.org/.

Там также есть работа в IETF, чтобы создать какой-то стандарт, позволяющий TLD объявлять, как выглядит их структура домена. Это немного сложно, хотя подобным .uk.com, который работает, как будто это открытый суффикс, но не продается реестром .com.

Ответ 4

Как уже говорили Адам и Джон publicsuffix.org, это правильный путь. Но если по какой-либо причине вы не можете использовать этот подход, здесь эвристика основана на предположении, что работает для 99% всех доменов:

Существует одно свойство, которое отличает (не все, но почти все) "реальные" домены от поддоменов и TLD, а также запись DNS MX. Вы можете создать алгоритм, который выполняет поиск: Удалите части имени узла один за другим и запросите DNS, пока не найдете запись MX. Пример:

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 the domain

Вот пример в 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");
}

Ответ 5

Как уже говорилось, Public Suffix List - это единственный способ правильно разобрать домен. Для PHP вы можете попробовать TLDExtract. Вот пример кода:

$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'

Ответ 6

Просто написал программу для этого в clojure на основе информации из publicsuffix.org:

https://github.com/isaksky/url_dom

Например:

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

Ответ 7

Для библиотеки C (с генерацией таблицы данных в Python) я написал http://code.google.com/p/domain-registry-provider/, который является быстрым и эффективным по пространству.

Библиотека использует ~ 30kB для таблиц данных и ~ 10kB для кода C. Накладные расходы на запуск отсутствуют, поскольку таблицы создаются во время компиляции. Подробнее см. http://code.google.com/p/domain-registry-provider/wiki/DesignDoc.

Чтобы лучше понять код генерации таблицы (Python), начинайте здесь: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Чтобы лучше понять API C, см. http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h

Ответ 8

Это не работает точно, но вы могли бы получить полезный ответ, пытаясь извлечь домен по частям и проверить ответ, т.е. получить " http://uk ', затем http://co.uk', затем http://domain.co.uk '. Когда вы получаете ответ без ошибок, у вас есть домен, а остальное - субдомен.

Иногда вам просто нужно попробовать:)

Edit:

Том Лейс указывает в комментариях, что некоторые домены настраиваются только на субдомене www, что дало бы нам неправильный ответ в вышеприведенном тесте. Хорошая точка зрения! Возможно, лучший подход состоял бы в том, чтобы проверить каждую часть с помощью http://www ', а также' http://'и посчитать хит либо в качестве хита для этот раздел доменного имени? Нам все равно не хватает некоторых "альтернативных" аранжировок, таких как "web.domain.com", но я не натолкнулся на это некоторое время:)

Ответ 9

Использовать URIBuilder затем получить атрибут URIBUilder.host разделите его на массив на "." теперь у вас есть массив с разделом домена.

Ответ 10

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

Ответ 12

Вы можете использовать этот lib tld.js: JavaScript API для работы со сложными именами доменов, субдоменами и URI.

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

Если вы получаете корневой домен в браузере. Вы можете использовать этот 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;
    }
  }
};

Использование cookie сложно.

Ответ 13

Если вы хотите извлечь субдомены и/или домены из произвольного списка URL-адресов, этот скрипт на python может быть полезен. Будьте осторожны, это не идеально. Это сложная проблема для решения в целом, и это очень полезно, если у вас есть белый список доменов, которые вы ожидаете.

  1. Получить домены верхнего уровня от 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)))
  1. Построить регулярное выражение
import re

_regex = ''
for domain in domains:
    _regex += r'{}|'.format(domain.replace('.', '\.'))

subdomain_regex = r'/([^/]*)\.[^/.]+\.({})/.*$'.format(_regex)
domain_regex = r'([^/.]+\.({}))/.*$'.format(_regex)
  1. Использовать регулярное выражение в списке 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)

Ответ 14

Список общих суффиксов (.co.uk,.com, et cetera), чтобы вырезать вместе с http://, а затем вы будете иметь только "sub.domain", а не " http://sub.domain.suffix", или, по крайней мере, то, что я, вероятно, сделаю.

Самая большая проблема - список возможных суффиксов. В конце концов, много.

Ответ 16

Если вы быстро взглянете на список publicsuffix.org, вы можете сделать разумное приближение, удалив последние три сегмента ( "сегмент" здесь означает раздел между двумя точками) из доменов, где конечный сегмент равен двум длинными символами, исходя из предположения, что это код страны и будет далее разделен. Если конечный сегмент является "нами", а второй-последний сегмент также является двумя символами, удалите последние четыре сегмента. Во всех остальных случаях удалите последние два сегмента. например:.

"пример" не два символа, поэтому удалите "domain.example", оставив "www"

"example" не является двумя символами, поэтому удалите "domain.example", оставив "super.duper"

"uk" - это два символа (но не "мы" ), поэтому удалите "domain.co.uk", оставив "super.duper"

"us" - это два символа и "мы", плюс "wy" также два символа, поэтому удалите "pvt.k12.wy.us", оставив "foo".

Обратите внимание, что, хотя это работает для всех примеров, которые я видел в ответах до сих пор, он остается только разумным приближением. Это не совсем правильно, хотя я подозреваю, что это примерно так же близко, как вы, вероятно, получите, не сделав/не получив фактический список для использования для справки.