Nhận miền phụ từ một URL


100

Việc lấy tên miền phụ từ một URL thoạt nghe có vẻ dễ dàng.

http://www.domain.example

Quét khoảng thời gian đầu tiên, sau đó trả về bất kỳ thứ gì đến sau "http: //" ...

Sau đó, bạn nhớ

http://super.duper.domain.example

Oh. Vì vậy, sau đó bạn nghĩ, được rồi, hãy tìm thời kỳ cuối cùng, quay lại một từ và nhận được mọi thứ trước đó!

Sau đó, bạn nhớ

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

Và bạn trở lại hình vuông. Có ai có ý tưởng tuyệt vời nào ngoài việc lưu trữ danh sách tất cả các TLD không?


Câu hỏi này đã được hỏi ở đây: Lấy các phần của URL Chỉnh sửa: Một câu hỏi tương tự đã được hỏi ở đây:)
jb.

Cam bạn làm rõ những gì bạn muốn? Có vẻ như bạn đang theo dõi phần miền "chính thức" của URL (tức là domain.co.uk), bất kể có bao nhiêu nhãn DNS xuất hiện trước nó?
Alnitak

Tôi không nghĩ rằng đó là cùng một câu hỏi - đây có vẻ là thêm về việc cắt giảm hành chính trong tên miền mà không thể làm việc ra chỉ bằng cách nhìn vào chuỗi
Alnitak

Tôi đồng ý. Mở rộng hơn về mục tiêu cuối cùng của bạn.
BuddyJoe

Câu trả lời:


73

Có ai có ý tưởng tuyệt vời nào ngoài việc lưu trữ danh sách tất cả các TLD không?

Không, vì mỗi TLD khác nhau về những gì được tính là miền phụ, miền cấp hai, v.v.

Hãy nhớ rằng có miền cấp cao nhất, miền cấp hai và miền phụ. Về mặt kỹ thuật, mọi thứ ngoại trừ TLD đều là một miền phụ.

Trong ví dụ domain.com.uk, "miền" là miền phụ, "com" là miền cấp hai và "uk" là TLD.

Vì vậy, câu hỏi vẫn phức tạp hơn so với lúc đầu, và nó phụ thuộc vào cách quản lý của mỗi TLD. Bạn sẽ cần một cơ sở dữ liệu của tất cả các TLD bao gồm phân vùng cụ thể của chúng và những gì được tính là miền cấp hai và miền phụ. Tuy nhiên, không có quá nhiều TLD, vì vậy danh sách có thể quản lý hợp lý, nhưng việc thu thập tất cả thông tin đó không phải là chuyện nhỏ. Có thể đã có sẵn một danh sách như vậy.

Có vẻ như http://publicsuffix.org/ là một trong những danh sách như vậy — tất cả các hậu tố phổ biến (.com, .co.uk, v.v.) trong một danh sách phù hợp để tìm kiếm. Sẽ không dễ dàng để phân tích cú pháp nó, nhưng ít nhất bạn không cần phải duy trì danh sách.

"Hậu tố công khai" là hậu tố mà người dùng Internet có thể trực tiếp đăng ký tên. Một số ví dụ về hậu tố công khai là ".com", ".co.uk" và "pvt.k12.wy.us". Danh sách hậu tố công khai là danh sách tất cả các hậu tố công khai đã biết.

Danh sách Hậu tố Công khai là một sáng kiến ​​của Mozilla Foundation. Nó có sẵn để sử dụng trong bất kỳ phần mềm nào, nhưng ban đầu được tạo ra để đáp ứng nhu cầu của các nhà sản xuất trình duyệt. Nó cho phép các trình duyệt, ví dụ:

  • Tránh đặt "supercookies" làm tổn hại đến quyền riêng tư cho hậu tố tên miền cấp cao
  • Đánh dấu phần quan trọng nhất của tên miền trong giao diện người dùng
  • Sắp xếp chính xác các mục lịch sử theo trang web

Nhìn qua danh sách , bạn có thể thấy nó không phải là một vấn đề tầm thường. Tôi nghĩ rằng một danh sách là cách chính xác duy nhất để thực hiện điều này ...


Mozilla có mã sử dụng dịch vụ này. Dự án đã bị loại bỏ vì thông số cookie ban đầu đã liên kết TLD với sự tin cậy vào cookie, nhưng không bao giờ hoạt động. Lỗi "Cookie Monster" là vấn đề đầu tiên và kiến ​​trúc không bao giờ được sửa hoặc thay thế.
benc

Ngôn ngữ ưa thích để giải quyết vấn đề này trong không được liệt kê, nhưng có một dự án nguồn mở sử dụng danh sách này trong mã C # tại đây: code.google.com/p/domainname-parser
Dan Esparza

Tên miền có phải là "hậu tố công khai" hay không thực sự nên được cung cấp thông qua chính giao thức DNS, có thể thông qua cờ EDNS. Trong trường hợp đó, chủ sở hữu có thể đặt nó và không cần phải duy trì một danh sách riêng.
Pieter Ennes 21/09/13

@PieterEnnes EDNS dành cho cờ "liên quan đến vận tải" và không thể được sử dụng cho siêu dữ liệu liên quan đến nội dung. Tôi đồng ý rằng thông tin này tốt nhất nên được đặt trong chính DNS. ISTR có kế hoạch cho một "phiên họp BoF" tại IETF sắp tới ở Vancouver để thảo luận về điều này.
Alnitak

26

Như Adam nói, nó không dễ dàng, và hiện tại cách thực tế duy nhất là sử dụng một danh sách.

Ngay cả khi đó vẫn có những ngoại lệ - ví dụ: .ukcó một số miền có giá trị ngay lập tức ở cấp đó mà không có trong đó .co.uk, vì vậy những tên miền đó phải được thêm vào làm ngoại lệ.

Đây hiện là cách các trình duyệt chính thống thực hiện điều này - cần phải đảm bảo rằng example.co.ukkhông thể đặt Cookie .co.ukmà sau đó sẽ được gửi đến bất kỳ trang web nào khác theo.co.uk .

Tin tốt là đã có một danh sách tại http://publicsuffix.org/ .

Cũng có một số công việc trong IETF để tạo ra một số loại tiêu chuẩn để cho phép TLD khai báo cấu trúc miền của chúng trông như thế nào. Điều này hơi phức tạp mặc dù như thế .uk.com, được vận hành như thể nó là một hậu tố công khai, nhưng không được cơ .comquan đăng ký bán.


1
Mặc dù vậy, IETF nên biết tốt hơn là để các URL của họ chết. Bản nháp (cập nhật lần cuối vào tháng 9 năm 2012) hiện có thể được truy cập tại đây: tools.ietf.org/html/draft-pettersen-subtld-osystem
IMSoP

Nhóm làm việc của IETF về chủ đề này (DBOUND) đã bị đóng.
Patrick Mevzek

Lưu ý rằng kể từ khi tôi viết bài này, .uksổ đăng ký tên miền hiện cho phép đăng ký trực tiếp ở cấp thứ hai. Điều này được phản ánh tương ứng trong PSL.
Alnitak

22

Publicsuffix.org có vẻ là cách để làm. Có rất nhiều cách triển khai để phân tích cú pháp nội dung của tệp dữ liệu publicsuffix một cách dễ dàng:


2
Nhưng hãy nhớ nó không chỉ là vấn đề phân tích cú pháp! Danh sách này tại Publicsuffix.org là một dự án không chính thức, chưa hoàn chỉnh (ví dụ: thiếu eu.org), KHÔNG phản ánh tự động các chính sách của TLD và có thể trở nên không rõ ràng bất cứ lúc nào.
bortzmeyer


7
Danh sách tại publicsuffix.org không phải là "không chính thức" hơn bất kỳ thứ gì khác mà Mozilla làm. Với việc Mozilla, Opera và Chrome sử dụng nó, nó không có khả năng trở nên vô nghĩa. Đối với việc chưa hoàn thiện, bất kỳ nhà khai thác miền nào như eu.org đều có thể đăng ký đưa vào nếu họ muốn và họ hiểu hậu quả của việc làm đó. Nếu bạn muốn thêm miền, hãy yêu cầu chủ sở hữu đăng ký. Có, nó không tự động phản ánh chính sách TLD, nhưng sau đó không có gì - không có nguồn lập trình của thông tin đó.
Gervase Markham

dao găm / android: okhttp sẽ cung cấp cho bạn topPrivateDomain
bladerunner

9

Như đã nói bởi Adam và John publicsuffix.org là cách chính xác để đi. Tuy nhiên, nếu vì bất kỳ lý do gì bạn không thể sử dụng phương pháp này, thì đây là phương pháp phỏng đoán dựa trên giả định hoạt động cho 99% tất cả các miền:

Có một thuộc tính phân biệt (không phải tất cả, nhưng gần như tất cả) miền "thực" với miền phụ và TLD và đó là bản ghi MX của DNS. Bạn có thể tạo một thuật toán tìm kiếm điều này: Loại bỏ từng phần của tên máy chủ và truy vấn DNS cho đến khi bạn tìm thấy bản ghi MX. Thí dụ:

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

Đây là một ví dụ trong 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");
}

Đó có phải là những gì IETF cũng đang đề xuất ở đây ?
Ellie Kesselman

1
Ngay cả publicsuffix.org cũng nói (xem đoạn thứ sáu) rằng cách thích hợp để làm điều này là thông qua DNS, giống như bạn đã nói trong câu trả lời của mình!
Ellie Kesselman

1
Ngoại trừ việc bạn hoàn toàn có thể có một miền mà không cần bản ghi MX. Và rằng thuật toán sẽ bị đánh lừa bởi các bản ghi ký tự đại diện. Và ở phía đối diện, bạn có TLD có bản ghi MX (giống như .aihoặc .axchỉ đặt tên một vài).
Patrick Mevzek

@patrick: Tôi hoàn toàn đồng ý; như tôi đã nói trong phần giới thiệu, thuật toán này không chống đạn, nó chỉ là một phương pháp heuristic hoạt động tốt một cách đáng ngạc nhiên.
Francois Bourgeois

2

Như đã nói Danh sách hậu tố công khai chỉ là một cách để phân tích cú pháp miền chính xác. Đối với PHP, bạn có thể thử TLDExtract . Đây là mã mẫu:

$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

Chỉ cần viết một chương trình cho điều này trong clojure dựa trên thông tin từ publicsuffix.org:

https://github.com/isaksky/url_dom

Ví dụ:

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

1

Đối với thư viện C (với tạo bảng dữ liệu bằng Python), tôi đã viết http://code.google.com/p/domain-registry-provider/ vừa nhanh vừa tiết kiệm dung lượng.

Thư viện sử dụng ~ 30kB cho các bảng dữ liệu và ~ 10kB cho mã C. Không có chi phí khởi động vì các bảng được xây dựng tại thời điểm biên dịch. Xem http://code.google.com/p/domain-registry-provider/wiki/DesignDoc để biết thêm chi tiết.

Để hiểu rõ hơn về mã tạo bảng (Python), hãy bắt đầu tại đây: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/registry_tables_generator/registry_tables_generator.py

Để hiểu rõ hơn về API C, hãy xem: http://code.google.com/p/domain-registry-provider/source/browse/trunk/src/domain_registry/domain_registry.h


1
Tôi cũng có một thư viện C / C ++ có danh sách riêng của nó mặc dù nó cũng được kiểm tra dựa trên danh sách publicsuffix.org. Nó được gọi là libtld và hoạt động dưới Unix và MS-Windows snapwebsites.org/project/libtld
Alexis Wilke

0

Nó không hoạt động chính xác, nhưng bạn có thể nhận được câu trả lời hữu ích bằng cách cố gắng tìm nạp từng mảnh miền và kiểm tra phản hồi, tức là tìm nạp ' http: // uk ', sau đó tìm ' http://co.uk ' , rồi đến ' http://domain.co.uk '. Khi bạn nhận được phản hồi không lỗi, bạn đã có miền và phần còn lại là miền phụ.

Đôi khi bạn phải thử nó :)

Biên tập:

Tom Leys chỉ ra trong các nhận xét rằng một số tên miền chỉ được thiết lập trên tên miền phụ www, điều này sẽ cho chúng tôi câu trả lời không chính xác trong bài kiểm tra ở trên. Điểm tốt! Có lẽ cách tiếp cận tốt nhất sẽ là kiểm tra từng phần với ' http: // www ' cũng như 'http: //' và tính một lần truy cập thành một lần truy cập cho phần đó của tên miền? Chúng tôi vẫn còn thiếu một số sắp xếp 'thay thế' chẳng hạn như 'web.domain.com', nhưng tôi đã không gặp một trong những sắp xếp đó trong một thời gian :)


Không có gì đảm bảo rằng x.com trỏ đến một máy chủ web tại cổng 80 ngay cả khi www.x.com có. www là một miền phụ hợp lệ trong trường hợp này. Có lẽ một whois tự động sẽ giúp ở đây.
Tom Leys

Điểm tốt! Whois sẽ xóa nó, mặc dù duy trì một danh sách các máy chủ whois sẽ sử dụng cho tld / cấp 2 có nghĩa là giải quyết vấn đề tương tự cho các trường hợp cạnh.
jTresidder

bạn đang giả định rằng có một máy chủ HTTP chạy trong mọi miền
Francois Bourgeois

Sẽ không hoạt động cho .DKvà một số người khác, cũng như http://dk/hoạt động. Đây là loại công nghệ tự động được không phải là cách để đi ...
Patrick Mevzek

0

Sử dụng URIBuilder sau đó lấy thuộc tính URIBUilder.host chia nó thành một mảng trên "." bây giờ bạn có một mảng với miền được tách ra.


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

Bạn có thể sử dụng API lib tld.js: JavaScript này để làm việc với các tên miền, tên miền phụ và URI phức tạp.

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

Nếu bạn đang nhận được miền gốc trong trình duyệt. Bạn có thể sử dụng lib AngusFu / browser-root-domain này .

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

Sử dụng cookie rất khó.


0

Nếu bạn đang tìm cách trích xuất miền phụ và / hoặc miền từ danh sách URL tùy ý, thì tập lệnh python này có thể hữu ích. Hãy cẩn thận, mặc dù nó không hoàn hảo. Đây là một vấn đề khó giải quyết nói chung và nó rất hữu ích nếu bạn có một danh sách trắng các miền mà bạn đang mong đợi.

  1. Nhận các miền cấp cao nhất từ ​​publicsuffix.org
yêu cầu nhập khẩu

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

miền = []
cho dòng trong page.text.splitlines ():
    if line.startswith ('//'):
        tiếp tục
    khác:
        domain = line.strip ()
        nếu miền:
            domains.append (miền)

domain = [d [2:] if d.startswith ('*.') else d for d in domains]
print ('found {} domains'.format (len (domains)))
  1. Xây dựng regex
nhập lại

_regex = ''
cho miền trong các miền:
    _regex + = r '{} |' .format (domain.replace ('.', '\.'))

subdomain_regex = r '/([^/]*)\.[[^/.]+\.({})/.*$'. format (_regex)
domain_regex = r '([^ /.] + \. ({})) /.*$'. format (_regex)
  1. Sử dụng regex trên danh sách các URL
FILE_NAME = '' # đặt tên tệp CSV ở đây
URL_COLNAME = '' # đặt tên cột URL ở đây

nhập gấu trúc dưới dạng pd

df = pd.read_csv (FILE_NAME)
urls = df [URL_COLNAME] .astype (str) + '/' # lưu ý: thêm / làm bản hack để giúp 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 ('extract_domains.csv', index = False)

-1

Danh sách các hậu tố phổ biến (.co.uk, .com, v.v.) cần loại bỏ cùng với http: // và sau đó bạn sẽ chỉ có "sub.domain" để làm việc thay vì " http: // sub. domain.suffix ", hoặc ít nhất đó là những gì tôi có thể làm.

Vấn đề lớn nhất là danh sách các hậu tố có thể có. Rốt cuộc thì có rất nhiều.


-3

Sau khi xem nhanh danh sách publicsuffix.org, có vẻ như bạn có thể ước tính hợp lý bằng cách xóa ba phân đoạn cuối cùng ("phân đoạn" ở đây có nghĩa là một phần giữa hai dấu chấm) khỏi các miền có phân đoạn cuối cùng dài hai ký tự, với giả định rằng đó là mã quốc gia và sẽ được chia nhỏ hơn nữa. Nếu phân đoạn cuối cùng là "chúng tôi" và phân đoạn thứ hai đến cuối cùng cũng là hai ký tự, hãy xóa bốn phân đoạn cuối cùng. Trong tất cả các trường hợp khác, hãy xóa hai phân đoạn cuối cùng. ví dụ:

"example" không phải là hai ký tự, vì vậy hãy xóa "domain.example", để lại "www"

"example" không phải là hai ký tự, vì vậy hãy xóa "domain.example", để lại "super.duper"

"uk" là hai ký tự (nhưng không phải "chúng tôi"), vì vậy hãy xóa "domain.co.uk", để lại "super.duper"

"chúng tôi" là hai ký tự và là "chúng tôi", cộng với "wy" cũng là hai ký tự, vì vậy hãy xóa "pvt.k12.wy.us", để lại "foo".

Lưu ý rằng, mặc dù điều này hoạt động cho tất cả các ví dụ mà tôi đã thấy trong các câu trả lời cho đến nay, nó vẫn chỉ là một ước tính hợp lý. Nó không hoàn toàn chính xác, mặc dù tôi nghi ngờ rằng nó gần như bạn có thể nhận được nếu không lập / lấy một danh sách thực tế để sử dụng để tham khảo.


3
Có rất nhiều trường hợp thất bại. Đây là loại trình duyệt thuật toán được sử dụng để thử và sử dụng. Đừng làm điều đó, hãy sử dụng PSL - nó hoạt động và có các thư viện để giúp bạn.
Gervase Markham

Không có gì cấm gTLD cũng được "phân đoạn", đây là trường hợp lúc đầu .NAMEchẳng hạn, khi bạn chỉ có thể mua firstname.lastname.nametên miền. Và theo chiều ngược lại, bây giờ .UScũng bằng phẳng, vì vậy bạn có thể có x.y.z.whatever.usbằng cách mua whatever.ustại cơ quan đăng ký và sau đó thuật toán của bạn sẽ không thành công.
Patrick Mevzek

1
Còn về ("phân đoạn" ở đây nghĩa là phần nằm giữa hai dấu chấm) : đây được gọi là nhãn trong thế giới DNS, không cần phải phát minh ra tên mới.
Patrick Mevzek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.