Отримайте субдомен з URL-адреси


101

Отримання піддомену з URL-адреси спочатку звучить легко.

http://www.domain.example

Скануйте перший період, а потім поверніть те, що з’явилося після "http: //" ...

Тоді ти згадуєш

http://super.duper.domain.example

Ой. Тоді ви думаєте, гаразд, знайдіть останній період, поверніться до слова і отримайте все раніше!

Тоді ти згадуєш

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

І ти повертаєшся до квадратного. У когось є чудові ідеї, крім того, щоб зберігати список усіх TLD?


Це питання вже задавались тут: Отримання частин редагування URL-адреси : Аналогічне запитання було задано тут
:)

Cam ти уточниш, чого хочеш? Здається, ви перебуваєте після "офіційної" доменної частини URL-адреси (тобто domain.co.uk), незалежно від кількості міток DNS перед цим?
Альнітак

Я не думаю, що це одне й те саме питання - це, мабуть, стосується адміністративних скорочень доменного імені, які неможливо розробити, просто переглянувши рядок
Alnitak

Я згоден. Детальніше розкрийте, яка ваша кінцева мета.
BuddyJoe

Дивіться цей відповідь: stackoverflow.com/a/39307593/530553
Ehsan Chavoshi

Відповіді:


73

У когось є чудові ідеї, крім того, щоб зберігати список усіх 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". Список загальнодоступних суфіксів - це список усіх відомих загальнодоступних суфіксів.

Список загальнодоступних суфіксів - це ініціатива фонду Mozilla. Він доступний для використання в будь-якому програмному забезпеченні, але спочатку був створений для задоволення потреб виробників браузерів. Це дозволяє браузерам, наприклад:

  • Уникайте конфіденційності "суперкокі", встановленої для суфіксів доменного імені високого рівня
  • Виділіть найважливішу частину доменного імені в інтерфейсі користувача
  • Точно сортуйте записи історії за сайтом

Переглядаючи список , ви бачите, що це не тривіальна проблема. Я думаю, що список є єдино правильним способом досягти цього ...


У Mozilla є код, який використовує цю послугу. Проект було відмовлено, оскільки оригінальна специфікація файлів cookie пов'язувала TLD з довірою до файлів cookie, але ніколи не працювала. Помилка "Monster Cookie" була першою проблемою, і архітектура ніколи не була виправлена ​​чи замінена.
benc

Краща мова для вирішення цього питання не вказана, але є проект із відкритими джерелами, який використовує цей список у C # коді тут: code.google.com/p/domainname-parser
Dan Esparza

Незалежно від того, домен є "загальнодоступним суфіксом" чи ні, він дійсно повинен бути доступний через сам протокол DNS, можливо, через прапор EDNS. У цьому випадку власник може встановити його, і немає необхідності вести окремий список.
Пітер Еннес

@PieterEnnes EDNS призначений для "прапорів, пов'язаних з транспортом", і їх не можна використовувати для метаданих, пов’язаних із вмістом. Я згоден, що цю інформацію найкраще розмістити в самій DNS. ISTR є плани на "сесію BoF" на майбутньому IETF у Ванкувері, щоб обговорити це.
Альнітак

26

Як каже Адам, це непросто, і наразі єдиним практичним способом є використання списку.

Навіть тоді є винятки - наприклад, в .ukцьому є декілька доменів, які діють одразу на тому рівні, які не знаходяться .co.uk, тому їх потрібно додавати як винятки.

Наразі це роблять основні браузери - це потрібно, щоб example.co.ukне вдалося встановити файл cookie, .co.ukякий потім буде надісланий на будь-який інший веб-сайт .co.uk.

Хороша новина полягає в тому, що на сайті http://publicsuffix.org/ вже є список .

Також в IETF є деяка робота над створенням якогось стандарту, щоб TLD могли оголосити, як виглядає їх структура домену. Це дещо складне, хоча подібне .uk.com, яке функціонує так, ніби це публічний суфікс, але .comреєстр не продається .


1
Так, IETF повинен знати краще, ніж дозволяти їхнім URL-адресам вмирати. З проектом (останній раз оновлено у вересні 2012 року) тепер можна ознайомитися тут: tools.ietf.org/html/draft-pettersen-subtld-structure
IMSoP

Робоча група IETF з цього питання (DBOUND) закрита.
Патрік Мевзек

Зауважте, що оскільки я писав це, .ukреєстр доменів тепер дозволяє реєстрацію безпосередньо на другому рівні. Це відображено відповідно до PSL.
Альнітак

22

Publicsuffix.org, здається, це зробити. Існує безліч реалізацій, щоб легко проаналізувати вміст файлу файлу publicsuffix:


2
Але пам’ятайте, це не лише питання розбору! Цей список на Publicsuffix.org є неофіційним проектом, який є неповним (наприклад, eu.org відсутній), НЕ відображає автоматично політику TLD і може стати незмінним у будь-який час.
bortzmeyer


7
Список на publicsuffix.org є не "неофіційним" більше, ніж все, що робить Mozilla. З огляду на те, що Mozilla, Opera і Chrome використовують його, навряд чи він залишиться без збереження. Що стосується неповного, будь-який оператор домену, наприклад eu.org, може подати заявку на включення, якщо цього хочуть, і вони розуміють наслідки цього. Якщо ви хочете додати домен, попросіть власника подати заявку. Так, це автоматично не відображає політику TLD, але тоді нічого не відбувається - програмного джерела цієї інформації немає.
Gervase Markham

кинджал / андроїд: okhttp дасть вам topPrivateDomain
bladerunner

9

Як уже говорили Адам та Джон, publicsuffix.org - це правильний шлях. Але, якщо з будь-якої причини ви не можете скористатися таким підходом, ось евристика, заснована на припущенні, що працює для 99% усіх доменів:

Є одна властивість, яка відрізняє (не всі, але майже всі) "реальні" домени від субдоменів та TLD, і це запис MX DNS. Ви можете створити алгоритм, який шукає це: Видаліть частини імені хоста по черзі та запитайте 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's 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");
}

Це те, що IETF також пропонує тут ?
Еллі Кессельман

1
Навіть publicsuffix.org каже (див. Шостий абзац), що правильний спосіб зробити це через DNS, як ви сказали у своїй відповіді!
Еллі Кессельман

1
За винятком того, що ви можете повністю мати домен без запису MX. І що алгоритм буде обдурений записами підстановок. А на протилежному боці у вас є TLD, у яких є записи MX (наприклад, .aiабо .axлише декілька).
Патрік Мевзек

@patrick: Я повністю згоден; як я вже говорив у вступі, цей алгоритм не є кулезахисним, це просто евристика, яка працює напрочуд добре.
Франсуа Буржуа

2

Як уже було сказано, список загальнодоступних суфіксів - лише один із способів правильного розбору домену. Для 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'

1

Щойно написав програму для цього на підставі інформації з 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"}

1

Для бібліотеки С (з генерацією таблиці даних у Python) я написав http://code.google.com/p/domain-registry-provider/ який є швидким та просторовим.

Бібліотека використовує ~ 30 кБ для таблиць даних і ~ 10 кБ для коду С. Немає накладних витрат, оскільки таблиці створюються під час компіляції. Дивіться 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


1
У мене також є бібліотека C / C ++, яка має власний список, хоча вона також перевірена на список publicsuffix.org. Він називається libtld і працює під Unix та MS-Windows snapwebsites.org/project/libtld
Alexis Wilke

0

Це не працює точно, але, можливо, ви можете отримати корисну відповідь, спробувавши добути фрагмент домену за частиною і перевіривши відповідь, тобто отримати " http: // uk ", а потім " http://co.uk " , потім " http://domain.co.uk ". Коли ви отримаєте відповідь про помилки, ви отримали домен, а решта - субдомен.

Іноді просто потрібно спробувати :)

Редагувати:

Том Лейс в коментарях зазначає, що деякі домени створені лише на веб-піддомені www, що дасть нам неправильну відповідь у вищенаведеному тесті. Гарна думка! Можливо, найкращим підходом було б перевірити кожну частину за допомогою " http: // www ", а також "http: //", і порахувати хіт як попадання для цього розділу доменного імені? У нас все ще бракує деяких "альтернативних" домовленостей, таких як "web.domain.com", але я не стикався з одним із них :)


Немає гарантій, що x.com вказує на веб-сервер на порту 80, навіть якщо www.x.com це робить. У цьому випадку www є дійсним субдоменом. Можливо, тут допоможе автоматизований Whois.
Том Лейс

Гарна думка! Whois зрозумів би це, хоча підтримуючи список, які сервери whois використовувати, для яких для якого tld / 2nd рівня означало б вирішення тієї ж проблеми для кращих випадків.
jTresidder

ви припускаєте, що в кожному домені працює сервер HTTP
Франсуа Буржуа

Не буде працювати для .DKдеяких інших, як http://dk/працює. Цей вид евристики - це не шлях ...
Патрік Мевзек

0

Використовуйте URIBuilder, тоді отримайте атрибут URIBUilder.host розділити його на масив на ". тепер у вас є масив з розділеним доменом.


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

Ви можете використовувати цю lib tld.js: API API для роботи зі складними доменними іменами, субдоменами та URI.

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

Якщо ви отримуєте кореневий домен у браузері. Ви можете використовувати цю ліб AngusFu / browser-root-домен .

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 є складним.


0

Якщо ви хочете витягнути піддомени та / або домени з довільного списку URL-адрес, цей сценарій пітона може бути корисним. Будьте уважні, хоча це не ідеально. Це складна проблема, яку потрібно вирішити загалом, і це дуже корисно, якщо у вас є білий список доменів, яких ви очікуєте.

  1. Отримайте домени верхнього рівня з publicsuffix.org
імпортні запити

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

домени = []
для рядка у page.text.splitlines ():
    якщо line.startswith ('//'):
        продовжувати
    ще:
        domain = line.strip ()
        якщо домен:
            domeins.append (домен)

domeins = [d [2:], якщо d.startswith ('*.') else d для d в доменах]
print ('знайдено {} domeins'.format (len (domeins)))
  1. Побудуйте регулярний вираз
імпорт ре

_regex = ''
для домену в доменах:
    _regex + = r '{} |' .format (domain.replace ('.', '\.'))

subdomain_regex = r '/( evidence^/ kome.
domain_regex = r '([^ /.] + \. ({})) /.*$'. формат (_regex)
  1. Використовуйте регулярні вирази в списку URL-адрес
FILE_NAME = '' # введіть сюди ім'я файлу CSV
URL_COLNAME = '' # поставити назву стовпця URL-адреси тут

імпортувати панди як pd

df = pd.read_csv (FILE_NAME)
urls = df [URL_COLNAME] .astype (str) + '/' # note: додавання / як хак, щоб допомогти регулярно висловити

df ['sub_domain_extracted'] = urls.str.extract (pat = піддомен_regex, розгорнути = True) [0]
df ['domain_extracted'] = urls.str.extract (pat = domain_regex, expand = Істинно) [0]

df.to_csv ('extracted_domains.csv', index = Неправильно)

-1

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

Найбільша проблема - перелік можливих суфіксів. Зрештою, багато.


-3

Швидко переглянувши список publicsuffix.org, виявляється, що ви можете зробити розумне наближення, видаливши остаточні три сегменти ("сегмент" тут означає розділ між двома крапками) з доменів, де кінцевий сегмент має два символи, за припущенням, що це код країни та буде надалі підрозділений. Якщо підсумковий сегмент є "ми", а другий-останній сегмент також два символи, видаліть останні чотири сегменти. У всіх інших випадках видаліть останні два сегменти. наприклад:

"example" - це не два символи, тому видаліть "domain.example", залишивши "www"

"example" - це не два символи, тому видаліть "domain.example", залишивши "super.duper"

"uk" - це два символи (але не "нам"), тому видаліть "domain.co.uk", залишивши "super.duper"

"us" - це два символи, це "us", плюс "wy" - це також два символи, тому видаліть "pvt.k12.wy.us", залишивши "foo".

Зауважте, що, хоча це працює для всіх прикладів, які я бачив у відповідях досі, це залишається лише розумним наближенням. Це не зовсім коректно, хоча я підозрюю, що це приблизно так близько, як ви, швидше за все, отримаєте, не роблячи / отримуючи фактичний список, який використовуватимете для довідок.


3
Є багато випадків відмов. Це такий тип браузерів алгоритму, який використовується для спроб та використання. Не робіть цього, використовуйте PSL - він працює, і є бібліотеки, які допоможуть вам.
Gervase Markham

Ніщо не забороняє також "сегментувати" gTLD, так це було на початку, .NAMEнаприклад, коли ви могли купувати лише firstname.lastname.nameдоменні імена. І в зворотному напрямку тепер .USтакож є плоскою, тож ви можете x.y.z.whatever.usпросто придбати whatever.usв реєстрі, і тоді ваш алгоритм вийде з ладу.
Патрік Мевзек

1
Також про ("сегмент" тут означає розділ між двома крапками) : це називається міткою у світі DNS, не потрібно вигадувати нову назву.
Патрік Мевзек
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.