URL에서 하위 도메인 가져 오기


101

URL에서 하위 도메인을 가져 오는 것은 처음에는 쉽습니다.

http://www.domain.example

첫 번째 마침표를 검색 한 다음 "http : //"다음에 오는 모든 것을 반환합니다. ...

그럼 당신은 기억 해요

http://super.duper.domain.example

오. 그래서 당신은 생각합니다. 좋아, 마지막 기간을 찾고, 한 단어로 돌아가서 이전에 모든 것을 얻으십시오!

그럼 당신은 기억 해요

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

그리고 당신은 원점으로 돌아 왔습니다. 누구나 모든 TLD 목록을 저장하는 것 외에 훌륭한 아이디어가 있습니까?


이 질문은 이미 여기에서 요청되었습니다. URL의 일부 가져 오기 편집 : 유사한 질문이 여기에서 요청되었습니다.)
jb.

캠 당신이 원하는 것을 명확하게? 앞에 나타나는 DNS 레이블 수에 관계없이 URL의 "공식"도메인 부분 (예 : domain.co.uk) 뒤에있는 것 같습니다.
Alnitak

나는 그것이 같은 질문이라고 생각하지 않는다 – 이것은 단지 문자열을 보는 것만으로는 해결할 수없는 도메인 이름의 관리적 삭감에 관한 것 같다
Alnitak

나는 동의한다. 최종 목표가 무엇인지 더 확장하십시오.
BuddyJoe

이 답변을 참조하십시오 : stackoverflow.com/a/39307593/530553
에산 Chavoshi

답변:


73

누구나 모든 TLD 목록을 저장하는 것 외에 훌륭한 아이디어가 있습니까?

아니요, 각 TLD는 하위 도메인, 두 번째 수준 도메인 등으로 간주되는 항목이 다르기 때문입니다.

최상위 도메인, 두 번째 수준 도메인 및 하위 도메인이 있습니다. 기술적으로 말하면 TLD를 제외한 모든 것이 하위 도메인입니다.

domain.com.uk 예에서 "domain"은 하위 도메인, "com"은 두 번째 수준 도메인, "uk"는 TLD입니다.

따라서 질문은 처음 붉어지는 것보다 더 복잡하며 각 TLD가 어떻게 관리되는지에 따라 다릅니다. 특정 파티셔닝을 포함하는 모든 TLD의 데이터베이스와 두 번째 수준 도메인 및 하위 도메인으로 간주되는 항목이 필요합니다. 하지만 TLD가 너무 많지 않기 때문에 목록을 합리적으로 관리 할 수 ​​있지만 모든 정보를 수집하는 것은 간단하지 않습니다. 이러한 목록이 이미있을 수 있습니다.

http://publicsuffix.org/ 가 이러한 목록 중 하나 인 것처럼 보입니다 . 검색에 적합한 목록의 모든 일반적인 접미사 (.com, .co.uk 등)입니다. 여전히 파싱하기는 쉽지 않지만 적어도 목록을 유지할 필요는 없습니다.

"공용 접미사"는 인터넷 사용자가 이름을 직접 등록 할 수있는 접미사입니다. 공개 접미사의 예로는 ".com", ".co.uk"및 "pvt.k12.wy.us"가 있습니다. 공용 접미사 목록은 알려진 모든 공용 접미사 목록입니다.

공용 접미사 목록은 Mozilla 재단의 이니셔티브입니다. 모든 소프트웨어에서 사용할 수 있지만 원래 브라우저 제조업체의 요구를 충족하기 위해 만들어졌습니다. 예를 들어 브라우저는 다음을 수행 할 수 있습니다.

  • 높은 수준의 도메인 이름 접미사에 개인 정보를 손상시키는 "슈퍼 쿠키"가 설정되지 않도록합니다.
  • 사용자 인터페이스에서 도메인 이름의 가장 중요한 부분을 강조
  • 사이트별로 기록 항목을 정확하게 정렬

목록을 살펴보면 사소한 문제가 아니라는 것을 알 수 있습니다. 나는 목록이 이것을 달성하는 유일한 올바른 방법이라고 생각합니다 ...


Mozilla에는이 서비스를 사용하는 코드가 있습니다. 원래 쿠키 사양이 TLD를 쿠키를 신뢰하도록 연결했기 때문에 프로젝트가 분리되었지만 작동하지 않았습니다. "쿠키 몬스터"버그가 첫 번째 문제였으며 아키텍처는 수정되거나 교체되지 않았습니다.
benc

이 문제를 해결하는 데 선호하는 언어는 나열되어 있지 않지만 C # 코드에서이 목록을 사용하는 오픈 소스 프로젝트가 있습니다. code.google.com/p/domainname-parser
Dan Esparza

도메인이 "공용 접미사"인지 여부는 DNS 프로토콜 자체를 통해, 아마도 EDNS 플래그를 통해 실제로 사용할 수 있어야합니다. 이 경우 소유자가 설정할 수 있으며 별도의 목록을 유지할 필요가 없습니다.
Pieter Ennes 2013 년

@PieterEnnes EDNS는 "전송 관련"플래그 용이며 콘텐츠 관련 메타 데이터에 사용할 수 없습니다. 이 정보가 DNS 자체에 가장 잘 배치된다는 데 동의합니다. ISTR은 이에 대해 논의하기 위해 다가오는 밴쿠버 IETF에서 "BoF 세션"에 대한 계획이 있습니다.
Alnitak 2013 년

26

Adam이 말했듯이 쉽지는 않으며 현재 유일한 실용적인 방법은 목록을 사용하는 것입니다.

그럼에도 불구하고 예외가 있습니다. 예를 들어에 .uk없는 해당 수준에서 즉시 유효한 소수의 도메인이 .co.uk있으므로 예외로 추가해야합니다.

이것이 현재 주류 브라우저가이 작업을 수행하는 방식 example.co.uk입니다. 쿠키를 설정할 수 없는지 확인 .co.uk하여 .co.uk.

좋은 소식은 이미 http://publicsuffix.org/에 목록이 있다는 것 입니다.

IETF 에는 TLD가 도메인 구조가 어떻게 생겼는지 선언 할 수 있도록 일종의 표준을 만드는 작업도 있습니다 . 이것은 마치 .uk.com공개 접미사 인 것처럼 작동하지만 .com레지스트리에서 판매되지 않는와 같은 경우에 약간 복잡 합니다 .


1
Eugh, IETF는 URL을 죽이는 것보다 더 잘 알아야합니다. 이제 초안 (2012 년 9 월에 마지막으로 업데이트 됨)에 도달 할 수 있습니다. tools.ietf.org/html/draft-pettersen-subtld-structure
IMSoP

주제에 대한 IETF 워킹 그룹 (DBOUND)이 폐쇄되었습니다.
Patrick Mevzek

내가 이것을 작성했기 때문에 .uk도메인 레지스트리는 이제 두 번째 수준에서 직접 등록을 허용합니다. 이는 PSL에 그에 따라 반영됩니다.
Alnitak

22

Publicsuffix.org가 그 방법 인 것 같습니다. publicsuffix 데이터 파일 파일의 내용을 쉽게 구문 분석 할 수있는 많은 구현이 있습니다.


2
그러나 그것은 단지 파싱의 문제가 아님을 기억하십시오! Publicsuffix.org의이 목록은 불완전한 (예를 들어, eu.org가 누락 된) 비공식 프로젝트로, TLD의 정책을 자동으로 반영하지 않으며 언제든지 유지되지 않을 수 있습니다.
bortzmeyer


7
publicsuffix.org의 목록은 Mozilla가하는 것보다 "비공식적 인"것이 아닙니다. Mozilla, Opera 및 Chrome이 사용한다는 점을 감안할 때 유지 관리되지 않을 가능성은 거의 없습니다. 불완전하다는 점은 eu.org와 같은 도메인의 모든 운영자가 원할 경우 포함을 신청할 수 있으며 그렇게했을 때의 결과를 이해합니다. 도메인을 추가하려면 소유자에게 신청하십시오. 예, TLD 정책을 자동으로 반영하지는 않지만 해당 정보의 프로그래밍 소스가 없습니다.
Gervase Markham 2011-08-22

단검 / 안드로이드 : okhttp 당신에게 topPrivateDomain 줄 것이다
블레이드 러너

9

Adam과 John이 이미 말했듯이 publicsuffix.org 는 올바른 방법입니다. 그러나 어떤 이유로 든이 접근 방식을 사용할 수없는 경우 모든 도메인의 99 %에 대해 작동하는 가정에 기반한 휴리스틱이 있습니다.

"실제"도메인을 하위 도메인 및 TLD와 구별하는 속성이 하나 있습니다 (모두는 아니지만 거의 모두). 이것이 바로 DNS의 MX 레코드입니다. 이를 검색하는 알고리즘을 만들 수 있습니다. 호스트 이름의 일부를 하나씩 제거하고 MX 레코드를 찾을 때까지 DNS를 쿼리합니다. 예:

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가 여기서도 제안하는 입니까?
Ellie Kesselman 2016

1
심지어 publicsuffix.org 말한다 이 작업을 수행 할 수있는 적절한 방법은 당신이 당신의 대답했다 단지처럼 DNS를 통해입니다 (여섯 번째 단락을 참조)!
Ellie Kesselman 2016

1
MX 레코드없이 완전히 도메인을 가질 수 있다는 점을 제외하고. 그리고 알고리즘은 와일드 카드 레코드에 속을 것입니다. 그리고 반대 측에 당신은 (같은 MX 레코드가 TLD를 가지고 .ai또는 .ax단지 몇 가지 이름을).
Patrick Mevzek

@patrick : 전적으로 동의합니다. 소개에서 말했듯이이 알고리즘은 방탄이 아니며 놀랍게도 잘 작동하는 휴리스틱입니다.
Francois Bourgeois

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의 정보를 기반으로 clojure에이 프로그램을 작성했습니다.

https://github.com/isaksky/url_dom

예를 들면 :

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

1

C 라이브러리 (Python에서 데이터 테이블 생성 포함)의 경우 빠르고 공간 효율적인 http://code.google.com/p/domain-registry-provider/ 를 작성했습니다 .

라이브러리는 데이터 테이블에 ~ 30kB를 사용하고 C 코드에 ~ 10kB를 사용합니다. 컴파일 시간에 테이블이 구성되므로 시작 오버 헤드가 없습니다. 자세한 내용은 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

C API를 더 잘 이해하려면 다음을 참조하십시오. http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h


1
또한 publicsuffix.org 목록에서도 확인되지만 자체 목록이있는 C / C ++ 라이브러리가 있습니다. libtld라고하며 Unix 및 MS-Windows에서 작동합니다. snapwebsites.org/project/libtld
Alexis Wilke

0

정확히 작동하지 않지만 도메인을 하나씩 가져와 응답을 확인하여 유용한 답변을 얻을 수 있습니다. 즉, ' http : // uk '를 가져온 다음 ' http://co.uk '를 가져옵니다 . , ' http://domain.co.uk '. 오류가 아닌 응답을 받으면 도메인이 있고 나머지는 하위 도메인입니다.

때때로 당신은 그것을 시도해야합니다 :)

편집하다:

Tom Leys는 댓글에서 일부 도메인은 www 하위 도메인에만 설정되어 위 테스트에서 잘못된 답을 제공한다고 지적합니다. 좋은 지적! 아마도 가장 좋은 방법은 ' http : // www ' 및 ' http : // '로 각 부분을 확인 하고 도메인 이름의 해당 섹션에 대한 히트로 계산하는 것입니다. 우리는 여전히 'web.domain.com'과 같은 '대체'배열을 놓치고 있지만 한동안 그 중 하나를 실행하지 않았습니다. :)


www.x.com이 가리키는 경우에도 x.com이 포트 80에서 웹 서버를 가리킬 것이라는 보장은 없습니다. 이 경우 www는 유효한 하위 도메인입니다. 아마도 자동화 된 whois가 여기에 도움이 될 것입니다.
Tom Leys

좋은 지적! whois는 그것을 정리할 것입니다. 그러나 어떤 whois 서버에 어떤 tld / 2nd 레벨을 사용할지 목록을 유지하는 것은 엣지 케이스에 대해 동일한 문제를 해결하는 것을 의미합니다.
jTresidder

당신은 모든 도메인에서 HTTP 서버가 실행되는 가정합니다
프랑소와 부르주아

있는 .DK그대로 http://dk/작동 하지 않습니다 . 이런 종류의 휴리스틱은 갈 길이 아닙니다 ...
Patrick Mevzek

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

쿠키 사용은 까다 롭습니다.


0

임의의 URL 목록에서 하위 도메인 및 / 또는 도메인을 추출하려는 경우이 Python 스크립트가 유용 할 수 있습니다. 하지만 조심하세요. 완벽하지는 않습니다. 이것은 일반적으로 해결하기 까다로운 문제이며 예상하는 도메인의 화이트리스트가있는 경우 매우 유용합니다.

  1. publicsuffix.org에서 최상위 도메인 가져 오기
수입 요청

URL = 'https://publicsuffix.org/list/public_suffix_list.dat'
페이지 = requests.get (url)

도메인 = []
page.text.splitlines ()의 행 :
    line.startswith ( '//') :
        계속하다
    그밖에:
        도메인 = line.strip ()
        도메인 :
            domains.append (도메인)

도메인 = [d [2 :] if d.startswith ( '*.') else d for d in domains]
print ( '{} 도메인을 찾았습니다'.format (len (도메인)))
  1. 정규식 빌드
다시 가져 오기

_ 정규식 = ''
도메인의 도메인 :
    _regex + = r '{} |'.format (domain.replace ( '.', '\.'))

subdomain_regex = r '/([^/]*)\.[^/.]+\.({})/.*$'. format (_regex)
domain_regex = r '([^ /.] + \. ({})) /.*$'. format (_regex)
  1. URL 목록에 정규식 사용
FILE_NAME = ''# 여기에 CSV 파일 이름 입력
URL_COLNAME = ''# 여기에 URL 열 이름 입력

팬더를 pd로 가져 오기

df = pd.read_csv (FILE_NAME)
urls = df [URL_COLNAME] .astype (str) + '/'# 참고 : 정규식을 돕기 위해 해킹으로 / 추가

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)


-3

publicsuffix.org 목록을 간략히 살펴보면 최종 세그먼트가 두 문자 인 도메인에서 마지막 세 세그먼트 (여기서 "세그먼트"는 두 점 사이의 섹션을 의미 함)를 제거하여 합리적인 근사치를 만들 수있는 것으로 보입니다. 국가 코드이고 더 세분화 될 것이라는 가정하에. 마지막 세그먼트가 "us"이고 마지막에서 두 번째 세그먼트도 두 문자 인 경우 마지막 네 세그먼트를 제거합니다. 다른 모든 경우에는 마지막 두 세그먼트를 제거하십시오. 예 :

"example"은 두 문자가 아니므로 "www"는 그대로두고 "domain.example"을 제거하십시오.

"example"은 두 문자가 아니므로 "super.duper"는 그대로두고 "domain.example"을 제거하십시오.

"uk"는 2 자 ( "us"는 아님)이므로 "super.duper"는 그대로두고 "domain.co.uk"를 제거합니다.

"us"는 두 문자이고 "us"이고 "wy"도 두 문자이므로 "foo"는 그대로두고 "pvt.k12.wy.us"를 제거하십시오.

이것은 지금까지 응답에서 본 모든 예제에서 작동하지만 합리적인 근사치로 남아 있습니다. 참조 용으로 사용할 실제 목록을 만들거나 얻지 않고도 얻을 수있는 것과 비슷하다고 생각하지만 완전히 정확하지는 않습니다.


3
많은 실패 사례가 있습니다. 이것은 시도하고 사용하는 데 사용되는 일종의 알고리즘 브라우저입니다. 그렇게하지 말고 PSL을 사용하십시오. 작동하며 도움이되는 라이브러리가 있습니다.
Gervase Markham 2011-08-22

gTLD가 "분할"되는 것을 금지하는 것은 없습니다. .NAME예를 들어 firstname.lastname.name도메인 이름 만 구입할 수 있는 경우와 같이 시작 부분에 해당 합니다. 그리고 반대 방향으로, 이제는 .US또한 평평하므로 레지스트리에서 x.y.z.whatever.us구매 whatever.us하면 알고리즘이 실패합니다.
Patrick Mevzek

1
또한 (여기서 "세그먼트"는 두 점 사이의 섹션을 의미 함) : DNS 세계에서 레이블이라고하며 새 이름을 만들 필요가 없습니다.
Patrick Mevzek
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.