web-dev-qa-db-ja.com

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

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

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

107
RandomQuestion

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

"Mr。Gosling-なぜ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-httpで始まるパスコンポーネントを持つ相対URL。
  • HTTP://example.com/-プロトコルは大文字と小文字を区別しません。
  • //example.com/-ホストを含​​むプロトコル相対URL
  • www/foo-wwwで始まるパスコンポーネントを持つ相対URL
  • 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行目の数字は、読みやすくするためのものです。それらは、各部分式(つまり、それぞれの括弧)の参照点を示します。

252
Mike Samuel
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
  }
}

続きを読む

66
Michael Tarimo

以下は、グアバでInternetDomainName.topPrivateDomain()を使用した短くシンプルな行です:InternetDomainName.from(new URL(url).getHost()).topPrivateDomain().toString()

http://www.google.com/blahを指定すると、google.comが得られます。または、http://www.google.co.mxを指定すると、google.co.mxが提供されます。

Sa Qadaこの投稿に関する別の回答 でコメントされているため、この質問は以前に尋ねられました: 特定のURLからメインドメイン名を抽出ベストアンサー その質問に対する回答は Satya で、Guavaの 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);
  }
}
9
Kirby

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

上記のMike Samuelの投稿によると、Java.net.URIクラスでこれを行うことができました(そしてJava.net.URLクラスよりも好まれました)が、URIクラスで問題が発生しました。特に、URLにスキーム、つまりURI.getHost()ビットが含まれていない場合、"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;
}
4
Adil Hussain

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
migueloop

同様の質問があります 指定されたURLからメインドメイン名を抽出する 。この answer を見ると、非常に簡単であることがわかります。あなただけのJava.net.URLStringユーティリティを使用する必要があります-Split

1
Ayaz Alifov
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);
    }
    else {
        return null;
    }
}

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

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

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

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

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

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

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

1
cegprakash

これを試してください: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
Eko Didik

私の場合、私はメインドメインのみを必要とし、サブドメインは必要ありませんでした(「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];
    }
    else {
        return domainArray[domainArray.length - 2] + "." + domainArray[domainArray.length - 1];
    }
}

このメソッドでは、URL「 https://rest.webtoapp.io/llSlider?lg=en&t=8 」はドメイン「webtoapp.io」に対して使用されます。

1
Laurent

入力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
spaceMonkey

上記はすべて良いです。これは私には本当にシンプルで、理解しやすいように思えます。引用をすみません。 Groovy用にDataCenterというクラス内で作成しました。

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
Lee Meador