指定されたURLからドメイン名を取得します


130

URLを指定して、ドメイン名を抽出したい( 'www'の部分は含めないでください)。URLにはhttp / httpsを含めることができます。これが私が書いたJavaコードです。それはうまく機能しているように見えますが、より良いアプローチはありますか、それとも失敗する可能性があるいくつかのエッジケースがありますか?

public static String getDomainName(String url) throws MalformedURLException{
    if(!url.startsWith("http") && !url.startsWith("https")){
         url = "http://" + url;
    }        
    URL netUrl = new URL(url);
    String host = netUrl.getHost();
    if(host.startsWith("www")){
        host = host.substring("www".length()+1);
    }
    return host;
}

入力:http : //google.com/blah

出力:google.com


3
http://74.125.226.70それがどのように機能するかを試して私に知らせてください:)
Marvin Pinto

1
IPアドレスを返すだけです。74.125.226.70
RandomQuestion

2
そして、どのようにしてそこからドメイン名を取得しますか?それはあなたが...後にしているものだと仮定すると、
マーヴィン・ピント

5
たとえば、http://www.de/またはhttp://www.com/希望する結果が得られません。
Michael Konietzka

回答:


287

URLを解析する場合は、を使用しますjava.net.URIjava.net.URLたくさんの問題があります-そのequals方法はDNSルックアップを行うので、それを使用するコードは、信頼できない入力で使用されると、サービス拒否攻撃に対して脆弱になる可能性があります。

「ゴスリングさん-なぜURLをイコールにしたのですか?」このような問題の1つを説明します。java.net.URI代わりに使う習慣をつけてください。

public static String getDomainName(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;
}

あなたがしたいことをする必要があります。


それはうまく機能しているように見えますが、より良いアプローチはありますか、それとも失敗する可能性があるいくつかのエッジケースがありますか?

記述されたコードは、有効なURLに対して失敗します。

  • httpfoo/bar-で始まるパスコンポーネントを含む相対URL http
  • HTTP://example.com/ -プロトコルは大文字と小文字を区別しません。
  • //example.com/ -ホストとのプロトコル相対URL
  • www/foo -で始まるパスコンポーネントを含む相対URL www
  • wwwexample.com-で始まるしないドメイン名www.が、で始まりますwww

階層型URLの文法は複雑です。RFC 3986を注意深く読まずに独自のパーサーを転がそうとすると、おそらくそれは間違っているでしょう。コアライブラリに組み込まれているものを使用してください。

java.net.URI拒否する乱雑な入力を処理する必要がある場合は、RFC 3986付録Bを参照しください。

付録B.正規表現によるURI参照の解析

「first-match-wins」アルゴリズムは、POSIX正規表現で使用される「貪欲な」曖昧性解消方法と同じであるため、URI参照の5つの潜在的なコンポーネントを解析するために正規表現を使用するのは自然でありふれた方法です。

次の行は、整形式のURI参照をコンポーネントに分解するための正規表現です。

  ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
   12            3  4          5       6  7        8 9

上記の2行目の数値は、読みやすくするためのものです。それらは、各部分式(つまり、各対の括弧)の参照点を示します。


2
@Jitendra、私はあなたがそれらを修正することに取り組んでいないことをお勧めします。Javaライブラリの人々はすでにあなたのために仕事をしています。
Mike Samuel、

9
また、URIの場合netUrl = new URI( "www.google.com"); netUrl.getHost()はNULLを返します。私はまだhttp://またはhttps://をチェックする必要があると思います
RandomQuestion

2
@Jitendra www.google.comは、パスコンポーネントを含む相対URLですwww.google.com。たとえば、に対して解決された場合http://example.com/、を取得しhttp://example.com/www.google.comます。
Mike Samuel、

マイクありがとう。私が正しいと理解した場合、ライブラリでは、上記のURIまたは正規表現を使用しますか?
RandomQuestion 2012年

2
例: "öob.se"
inc

80
import java.net.*;
import java.io.*;

public class ParseURL {
  public static void main(String[] args) throws Exception {

    URL aURL = new URL("http://example.com:80/docs/books/tutorial"
                       + "/index.html?name=networking#DOWNLOADING");

    System.out.println("protocol = " + aURL.getProtocol()); //http
    System.out.println("authority = " + aURL.getAuthority()); //example.com:80
    System.out.println("host = " + aURL.getHost()); //example.com
    System.out.println("port = " + aURL.getPort()); //80
    System.out.println("path = " + aURL.getPath()); //  /docs/books/tutorial/index.html
    System.out.println("query = " + aURL.getQuery()); //name=networking
    System.out.println("filename = " + aURL.getFile()); ///docs/books/tutorial/index.html?name=networking
    System.out.println("ref = " + aURL.getRef()); //DOWNLOADING
  }
}

続きを読む


15

InternetDomainName.topPrivateDomain()Guavaで使用する短くてシンプルな行は次のとおりです。InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

与えられればhttp://www.google.com/blah、それはあなたに与えるでしょうgoogle.com。または、与えられればhttp://www.google.co.mx、それはあなたに与えるでしょうgoogle.co.mx

サQadaがでコメントこのポストの上に別の答え、この質問は以前に頼まれました:指定されたURLから、メインのドメイン名を抽出します最良の答えはその質問には、からであるサティヤグアバの示唆、)(InternetDomainName.topPrivateDomainを

public boolean isTopPrivateDomain()

このドメイン名が、1つのサブドメインコンポーネントとそれに続くパブリックサフィックスで構成されるかどうかを示します。たとえば、google.comとfoo.co.ukの場合はtrueを返しますが、www.google.comまたはco.ukの場合は返しません。

警告:多くのパブリックサフィックスもアドレス可能なホストであるため、このメソッドからの真の結果は、ドメインがホストとしてアドレス可能な最高レベルであることを意味しません。たとえば、ドメインbar.uk.comにはuk.comのパブリックサフィックスがあるため、このメソッドからtrueを返します。しかし、uk.com自体がアドレス可能なホストです。

このメソッドは、ドメインがCookieを設定できる最も高いレベルであるかどうかを判断するために使用できますが、個々のブラウザのCookieコントロールの実装にも依存します。詳細については、RFC 2109を参照してください。

URL.getHost()元の投稿に既に含まれていると組み合わせて使用​​すると、次のようになります。

import com.google.common.net.InternetDomainName;

import java.net.URL;

public class DomainNameMain {

  public static void main(final String... args) throws Exception {
    final String urlString = "http://www.google.com/blah";
    final URL url = new URL(urlString);
    final String host = url.getHost();
    final InternetDomainName name = InternetDomainName.from(host).topPrivateDomain();
    System.out.println(urlString);
    System.out.println(host);
    System.out.println(name);
  }
}

6

私は、URLのドメイン名を抽出し、単純な文字列マッチングを使用するメソッド(以下を参照)を作成しました。それが実際に行うことは、最初の"://"(またはインデックス0なしがある場合"://"含まれている)と第1、その後の"/"(またはインデックスをString.length()後続がない場合"/")。残りの先行"www(_)*."ビットは切り落とされます。これで十分でない場合もあると思いますが、ほとんどの場合それで十分です。

上記のMike Samuelの投稿によると、java.net.URIクラスはこれを行うことができ(クラスよりも優先されましたjava.net.URL)、URIクラスで問題が発生しました。特に、URI.getHost()URLにスキーム("http(s)"ビット)が含まれていない場合はnull値が返されます。

/**
 * Extracts the domain name from {@code url}
 * by means of String manipulation
 * rather than using the {@link URI} or {@link URL} class.
 *
 * @param url is non-null.
 * @return the domain name within {@code url}.
 */
public String getUrlDomainName(String url) {
  String domainName = new String(url);

  int index = domainName.indexOf("://");

  if (index != -1) {
    // keep everything after the "://"
    domainName = domainName.substring(index + 3);
  }

  index = domainName.indexOf('/');

  if (index != -1) {
    // keep everything before the '/'
    domainName = domainName.substring(0, index);
  }

  // check for and remove a preceding 'www'
  // followed by any sequence of characters (non-greedy)
  // followed by a '.'
  // from the beginning of the string
  domainName = domainName.replaceFirst("^www.*?\\.", "");

  return domainName;
}

これは正しくないと思うhttp://bob.com:8080/service/read?name=robert
リー・メアドール

リーを指摘してくれてありがとう。私は私の答えを「これで十分ではないケースがあると確信しています...」で修飾したことに注意してください。私の答えはあなたの特定のケースのために若干の修正を必要とするでしょう。
アディルフセイン

3

URIオブジェクト作成後にちょっとした扱いをしました

 if (url.startsWith("http:/")) {
        if (!url.contains("http://")) {
            url = url.replaceAll("http:/", "http://");
        }
    } else {
        url = "http://" + url;
    }
    URI uri = new URI(url);
    String domain = uri.getHost();
    return domain.startsWith("www.") ? domain.substring(4) : domain;

2

私の場合、メインドメインだけが必要で、サブドメインは必要ありませんでした( "www"などのサブドメインは必要ありません)。

public static String getUrlDomain(String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    String[] domainArray = domain.split("\\.");
    if (domainArray.length == 1) {
        return domainArray[0];
    }
    return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
}

この方法では、URL「https://rest.webtoapp.io/llSlider?lg=en&t=8」はドメイン「webtoapp.io」に対して持つことになります。


1

これを試してください:java.net.URL;
JOptionPane.showMessageDialog(null、getDomainName(new URL( " https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains ")));

public String getDomainName(URL url){
String strDomain;
String[] strhost = url.getHost().split(Pattern.quote("."));
String[] strTLD = {"com","org","net","int","edu","gov","mil","arpa"};

if(Arrays.asList(strTLD).indexOf(strhost[strhost.length-1])>=0)
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else if(strhost.length>2)
    strDomain = strhost[strhost.length-3]+"."+strhost[strhost.length-2]+"."+strhost[strhost.length-1];
else
    strDomain = strhost[strhost.length-2]+"."+strhost[strhost.length-1];
return strDomain;}


1
private static final String hostExtractorRegexString = "(?:https?://)?(?:www\\.)?(.+\\.)(com|au\\.uk|co\\.in|be|in|uk|org\\.in|org|net|edu|gov|mil)";
private static final Pattern hostExtractorRegexPattern = Pattern.compile(hostExtractorRegexString);

public static String getDomainName(String url){
    if (url == null) return null;
    url = url.trim();
    Matcher m = hostExtractorRegexPattern.matcher(url);
    if(m.find() && m.groupCount() == 2) {
        return m.group(1) + m.group(2);
    }
    return null;
}

説明: 正規表現には4つのグループがあります。最初の2つは一致しないグループで、次の2つは一致するグループです。

一致しない最初のグループは「http」または「https」または「」です

一致しない2番目のグループは「www」です。または「」

2番目に一致するグループはトップレベルドメインです

最初に一致するグループは、一致しないグループの後にあり、トップレベルドメインの前にあります。

2つの一致するグループを連結すると、ドメイン/ホスト名がわかります。

PS:サポートされているドメインをいくつでも正規表現に追加できることに注意してください。


0

入力URLがユーザー入力の場合。このメソッドは、最も適切なホスト名を提供します。見つからない場合は、入力URLを返します。

private String getHostName(String urlInput) {
        urlInput = urlInput.toLowerCase();
        String hostName=urlInput;
        if(!urlInput.equals("")){
            if(urlInput.startsWith("http") || urlInput.startsWith("https")){
                try{
                    URL netUrl = new URL(urlInput);
                    String host= netUrl.getHost();
                    if(host.startsWith("www")){
                        hostName = host.substring("www".length()+1);
                    }else{
                        hostName=host;
                    }
                }catch (MalformedURLException e){
                    hostName=urlInput;
                }
            }else if(urlInput.startsWith("www")){
                hostName=urlInput.substring("www".length()+1);
            }
            return  hostName;
        }else{
            return  "";
        }
    }

0

上記はすべて良好です。これは私には本当にシンプルで理解しやすいようです。失礼します。DataCenterと呼ばれるクラス内でGroovy用に作成しました。

static String extractDomainName(String url) {
    int start = url.indexOf('://')
    if (start < 0) {
        start = 0
    } else {
        start += 3
    }
    int end = url.indexOf('/', start)
    if (end < 0) {
        end = url.length()
    }
    String domainName = url.substring(start, end)

    int port = domainName.indexOf(':')
    if (port >= 0) {
        domainName = domainName.substring(0, port)
    }
    domainName
}

そしてここにいくつかのjunit4テストがあります:

@Test
void shouldFindDomainName() {
    assert DataCenter.extractDomainName('http://example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('http://subpart.example.com/path/') == 'subpart.example.com'
    assert DataCenter.extractDomainName('http://example.com') == 'example.com'
    assert DataCenter.extractDomainName('http://example.com:18445/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com/path/') == 'example.com'
    assert DataCenter.extractDomainName('example.com') == 'example.com'
}

0

すべてのケースで私が作業した方法の1つは、Guava Libraryとregexを組み合わせて使用​​することです。

public static String getDomainNameWithGuava(String url) throws MalformedURLException, 
  URISyntaxException {
    String host =new URL(url).getHost();
    String domainName="";
    try{
        domainName = InternetDomainName.from(host).topPrivateDomain().toString();
    }catch (IllegalStateException | IllegalArgumentException e){
        domainName= getDomain(url,true);
    }
    return domainName;
}

getDomain()は、正規表現を使用する一般的なメソッドです。


0

サブドメインなしで実際のドメイン名を取得するには、以下を使用します。

private String getDomainName(String url) throws URISyntaxException {
    String hostName = new URI(url).getHost();
    if (!hostName.contains(".")) {
        return hostName;
    }
    String[] host = hostName.split("\\.");
    return host[host.length - 2];
}

これはセカンドレベルドメイン(.co.ukなど)では機能しないことに注意してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.