109

URLからサブドメインを取得することは、最初は簡単に聞こえます。

http://www.domain.example

最初の期間をスキャンしてから、「http://」の後に来るものを返します...

その後、あなたは覚えています

http://super.duper.domain.example

おー。それで、あなたは、大丈夫、最後の期間を見つけて、一言戻って、前にすべてを手に入れようと思います!

その後、あなたは覚えています

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

そして、あなたは正方形に戻っています。すべてのTLDのリストを保存する以外に、すばらしいアイデアはありますか?

4

18 に答える 18

75

すべての TLD のリストを保存する以外に、何か素晴らしいアイデアはありますか?

いいえ、各 TLD は、サブドメイン、第 2 レベル ドメインなどとしてカウントされるものが異なるためです。

トップ レベル ドメイン、セカンド レベル ドメイン、およびサブドメインがあることに注意してください。技術的に言えば、TLD を除くすべてがサブドメインです。

domain.com.uk の例では、「domain」はサブドメイン、「com」は第 2 レベルのドメイン、「uk」は TLD です。

そのため、問題は一見したよりも複雑なままであり、各 TLD がどのように管理されているかによって異なります。特定のパーティショニングを含むすべての TLD のデータベースと、第 2 レベル ドメインおよびサブドメインとしてカウントされるものが必要になります。ただし、TLD の数はそれほど多くないため、リストはかなり管理しやすいものですが、すべての情報を収集するのは簡単ではありません。すでにそのようなリストが利用可能である可能性があります。

http://publicsuffix.org/はそのようなリストの 1 つで、検索に適したリスト内のすべての一般的なサフィックス (.com、.co.uk など) のようです。解析するのは簡単ではありませんが、少なくともリストを維持する必要はありません。

「パブリック サフィックス」は、インターネット ユーザーが直接名前を登録できるサフィックスです。パブリック サフィックスの例としては、「.com」、「.co.uk」、「pvt.k12.wy.us」などがあります。パブリック サフィックス リストは、既知のすべてのパブリック サフィックスのリストです。

Public Suffix List は、Mozilla Foundation のイニシアチブです。どのソフトウェアでも使用できますが、もともとはブラウザ メーカーのニーズを満たすために作成されました。たとえば、ブラウザは次のことができます。

  • 高レベルのドメイン名サフィックスにプライバシーを侵害する「スーパークッキー」が設定されないようにする
  • ユーザー インターフェイスでドメイン名の最も重要な部分を強調表示する
  • 履歴エントリをサイトごとに正確に並べ替える

リストを見ると、些細な問題ではないことがわかります。これを達成するための唯一の正しい方法はリストだと思います...

于 2008-11-14T00:21:58.517 に答える
25

Adam が言うように、それは簡単なことではなく、現在のところ唯一の実用的な方法はリストを使用することです。

それでも例外があります。たとえば、.ukそのレベルですぐに有効になる少数のドメインが にない.co.ukため、それらを例外として追加する必要があります。

これは現在主流のブラウザがこれを行う方法です -example.co.ukが Cookie を設定できないことを確認する必要が.co.ukあります.co.uk

良いニュースは、既にhttp://publicsuffix.org/で利用可能なリストがあることです。

IETFでは、 TLD がドメイン構造がどのように見えるかを宣言できるようにするための何らかの標準を作成する作業もあります。.uk.comこれは、パブリック サフィックスであるかのように操作されますが、.comレジストリによって販売されていないのようなものによって少し複雑になります。

于 2008-11-14T00:32:12.503 に答える
22

Publicsuffix.org がその方法のようです。publicsuffix データ ファイル ファイルの内容を簡単に解析するための実装がたくさんあります。

于 2009-06-06T23:24:55.030 に答える
9

Adam と John が既に述べたように、 publicsuffix.orgが正しい方法です。ただし、何らかの理由でこのアプローチを使用できない場合は、すべてのドメインの 99% で機能するという仮定に基づくヒューリスティックを次に示します。

(すべてではなくほぼすべての)「実際の」ドメインをサブドメインおよび TLD から区別する 1 つのプロパティがあり、それが DNS の MX レコードです。これを検索するアルゴリズムを作成できます。ホスト名の一部を 1 つずつ削除し、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");
}
于 2013-02-04T14:33:26.550 に答える
2

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 を参照してください。

于 2012-12-06T18:43:25.377 に答える
2

既に述べたように、 Public Suffix Listはドメインを正しく解析する 1 つの方法にすぎません。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'
于 2016-06-23T14:53:16.073 に答える
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"}
于 2012-03-20T15:54:39.083 に答える
1

のバージョン

Adam Davis の正解に加えて、この操作に対する独自のソリューションを投稿したいと思います。

リストは大きなものなので、さまざまなテスト済みソリューションのうちの 3 つがあります...

まず、その方法で TLD リストを準備します。

wget -O - https://publicsuffix.org/list/public_suffix_list.dat |
    grep '^[^/]' |
    tac > tld-list.txt

注:のtacに確実にテストするためにリストを反転します。.co.uk .uk

シェル バージョン

splitDom() {
    local tld
    while read tld;do
        [ -z "${1##*.$tld}" ] &&
            printf "%s : %s\n" $tld ${1%.$tld} && return
    done <tld-list.txt
}

テスト:

splitDom super.duper.domain.co.uk
co.uk : super.duper.domain

splitDom super.duper.domain.com
com : super.duper.domain

バージョン

フォークを減らす (構文を避けるmyvar=$(function..)) ために、bash 関数では出力を stdout にダンプする代わりに変数を設定することを好みます。

tlds=($(<tld-list.txt))
splitDom() {
    local tld
    local -n result=${2:-domsplit}
    for tld in ${tlds[@]};do
        [ -z "${1##*.$tld}" ] &&
            result=($tld ${1%.$tld}) && return
    done
}

それで:

splitDom super.duper.domain.co.uk myvar
declare -p myvar
declare -a myvar=([0]="co.uk" [1]="super.duper.domain")

splitDom super.duper.domain.com
declare -p domsplit
declare -a domsplit=([0]="com" [1]="super.duper.domain")

より速いバージョン:

同じ準備で、次のようになります。

declare -A TLDS='()'
while read tld ;do
    if [ "${tld##*.}" = "$tld" ];then
        TLDS[${tld##*.}]+="$tld"
      else
        TLDS[${tld##*.}]+="$tld|"
    fi
done <tld-list.txt

このステップはかなり遅くなりますが、splitDom関数は非常に速くなります:

shopt -s extglob 
splitDom() {
    local domsub=${1%%.*(${TLDS[${1##*.}]%\|})}
    local -n result=${2:-domsplit}
    result=(${1#$domsub.} $domsub)
}

私のラズベリーパイでのテスト:

両方のスクリプトを次のようにテストしました。

for dom in dom.sub.example.{,{co,adm,com}.}{com,ac,de,uk};do
    splitDom $dom myvar
    printf "%-40s %-12s %s\n" $dom ${myvar[@]}
done

版は詳細な forループでテストしましたが、

すべてのテスト スクリプトは同じ出力を生成します。

dom.sub.example.com                      com          dom.sub.example
dom.sub.example.ac                       ac           dom.sub.example
dom.sub.example.de                       de           dom.sub.example
dom.sub.example.uk                       uk           dom.sub.example
dom.sub.example.co.com                   co.com       dom.sub.example
dom.sub.example.co.ac                    ac           dom.sub.example.co
dom.sub.example.co.de                    de           dom.sub.example.co
dom.sub.example.co.uk                    co.uk        dom.sub.example
dom.sub.example.adm.com                  com          dom.sub.example.adm
dom.sub.example.adm.ac                   ac           dom.sub.example.adm
dom.sub.example.adm.de                   de           dom.sub.example.adm
dom.sub.example.adm.uk                   uk           dom.sub.example.adm
dom.sub.example.com.com                  com          dom.sub.example.com
dom.sub.example.com.ac                   com.ac       dom.sub.example
dom.sub.example.com.de                   com.de       dom.sub.example
dom.sub.example.com.uk                   uk           dom.sub.example.com

ファイルの読み取りとsplitDomループを含む完全なスクリプトは、posix バージョンで ~2m、配列に基づく最初の bash スクリプトでは ~1m29s かかります$tldsが、連想配列~22sに基づく最後の bash スクリプトでは ~1m29s かかります。$TLDS

                Posix version     $tldS (array)      $TLDS (associative array)
File read   :       0.04164          0.55507           18.65262
Split loop  :     114.34360         88.33438            3.38366
Total       :     114.34360         88.88945           22.03628

したがって、連想配列の作成がより強力な仕事である場合、splitDom関数ははるかに高速になります!

于 2020-09-06T07:24:07.957 に答える
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;
}
于 2012-03-29T01:09:07.307 に答える
0

正確には解決していませんが、ドメインを 1 つずつフェッチして応答を確認することで、有用な答えが得られる可能性あります。 、次に「http://domain.co.uk」。エラー以外の応答が得られた場合は、ドメインを取得しており、残りはサブドメインです。

時々、試してみる必要があります:)

編集:

Tom Leys はコメントで、一部のドメインは www サブドメインのみに設定されているため、上記のテストで間違った答えが得られると指摘しています。いい視点ね!「 http://www」と「http://」で各部分をチェックし、ドメイン名のそのセクションのヒットとしていずれかへのヒットをカウントするのが最善の方法でしょうか? 「web.domain.com」などの「代替」の配置がまだいくつか欠けていますが、しばらくの間、それらのいずれかに遭遇していません:)

于 2008-11-14T00:54:20.243 に答える
0

URIBuilder を使用して、URIBUilder.host 属性を取得し、「.」の配列に分割します。これで、ドメインが分割されたアレイができました。

于 2011-02-02T00:35:37.617 に答える
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;
    }
  }
};

クッキーの使用はトリッキーです。

于 2017-05-09T07:54:11.007 に答える
0

URL の任意のリストからサブドメインやドメインを抽出する場合は、この python スクリプトが役立つ場合があります。ただし、完璧ではないので注意してください。これは一般的に解決するのが難しい問題であり、予期しているドメインのホワイトリストがある場合は非常に役立ちます。

  1. publicsuffix.org からトップ レベル ドメインを取得する
インポートリクエスト

url = 'https://publicsuffix.org/list/public_suffix_list.dat'
ページ = requests.get(url)

ドメイン = []
page.text.splitlines() の行:
    if line.startswith('//'):
        継続する
    そうしないと:
        ドメイン = line.strip()
        ドメインの場合:
            domain.append(ドメイン)

domain = [d[2:] if d.startswith('*.') else d for d in domain]
print('見つかった {} ドメイン'.format(len(ドメイン)))
  1. 正規表現を構築する
再輸入

_regex = ''
ドメイン内のドメインの場合:
    _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(ファイル名)
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)
于 2018-11-28T22:29:40.773 に答える
-1

一般的なサフィックス (.co.uk、.com など) のリストを http:// と共に削除すると、" http://sub. domain.suffix "、または少なくともそれは私がおそらく行うことです.

最大の問題は、可能なサフィックスのリストです。結局のところ、たくさんあります。

于 2008-11-14T01:00:17.283 に答える
-3

publicsuffix.org リストをざっと見てみると、最後のセグメントが 2 文字の長さのドメインから最後の 3 つのセグメント (ここでの「セグメント」とは 2 つのドットの間のセクションを意味します) を削除することで、妥当な概算を行うことができるようです。それは国コードであり、さらに細分化されることを前提としています。最後のセグメントが「us」で、最後から 2 番目のセグメントも 2 文字の場合は、最後の 4 つのセグメントを削除します。それ以外の場合は、最後の 2 つのセグメントを削除します。例えば:

「example」は 2 文字ではないため、「domain.example」を削除し、「www」を残します。

「example」は 2 文字ではないため、「domain.example」を削除し、「super.duper」を残します

「uk」は 2 文字 (ただし「us」ではない) であるため、「domain.co.uk」を削除し、「super.duper」を残します。

"us" は 2 文字で "us" で、さらに "wy" も 2 文字なので、"pvt.k12.wy.us" を削除して "foo" を残します。

これは、これまでの回答で見たすべての例で機能しますが、妥当な概算にすぎないことに注意してください。完全に正しいわけではありませんが、参照用に実際のリストを作成/取得せずに取得できる可能性が最も高いと思われます。

于 2008-11-14T18:25:18.453 に答える