获取URL的二级域(java)

时间:2009-12-17 18:54:18

标签: java url

我想知道在java中是否存在用于提取URL中的二级域(SLD)的解析器或库 - 或者未能使用算法或正则表达式来执行相同操作。例如:

URI uri = new URI("http://www.mydomain.ltd.uk/blah/some/page.html");

String host = uri.getHost();

System.out.println(host);

打印:

mydomain.ltd.uk

现在我想做的是强有力地识别SLD(“ltd.uk”)组件。有什么想法吗?

编辑:我理想地寻找一般解决方案,所以我在“police.uk”中匹配“.uk”,“。co.uk”在“bbc.co.英国“和”.com“在”amazon.com“中。

由于

11 个答案:

答案 0 :(得分:14)

不知道你的目的,但二级域名可能对你没有多大意义。您可能需要找到public suffix,其下方的域名正是您要找的。

Apache Http Component(HttpClient 4)附带了处理此问题的类,

org.apache.http.impl.cookie.PublicSuffixFilter
org.apache.http.impl.cookie.PublicSuffixListParser

您需要从此处下载公开后缀列表

http://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1

答案 1 :(得分:14)

在这里重复所有内容之后,正确的解决方案应该是(使用番石榴)

Internet Domain Name.from(uri Host).topPrivateDomain()。toString();

errors when using Guava to get the private domain name

答案 2 :(得分:10)

在查看这些答案并且不满意之后,我使用班级com.google.common.net.InternetDomainName从所有部分中减去域名的公共部分:

Set<String> nonePublicDomainParts(String uriHost) {
    InternetDomainName fullDomainName = InternetDomainName.from(uriHost);
    InternetDomainName publicDomainName = fullDomainName.publicSuffix();
    Set<String> nonePublicParts = new HashSet<String>(fullDomainName.parts());
    nonePublicParts.removeAll(publicDomainName.parts());
    return nonePublicParts;
}

那个班级在番石榴图书馆的maven上:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>10.0.1</version>
        <scope>compile</scope>
    </dependency>

在内部,这个类使用的是TldPatterns.class,它是包私有的,并且包含了顶级域名列表。

有趣的是,如果您在下面的链接中查看该类源,它会明确地将“police.uk”列为私有域名。这是正确的,因为police.uk是一个由警方控制的私人域名;其他criminals.police.uk将通过电子邮件向您询问有关他们正在进行的卡欺诈调查的信用卡详细信息;)

http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/net/TldPatterns.java?spec=svn8c3cc7e67132f8dcaae4bd214736a8ddf6611769&r=8c3cc7e67132f8dcaae4bd214736a8ddf6611769

答案 3 :(得分:2)

选择的答案是最好的方法。对于那些不想编码的人,我就是这样做的。

首先,要么我不理解org.apache.http.impl.cookie.PublicSuffixFilter,要么就是它有一个bug。

基本上如果你传入google.com,它会正确返回false。如果您传入google.com.au,则会错误地返回true。该错误存在于应用模式的代码中,例如* .AU。

以下是基于org.apache.http.impl.cookie.PublicSuffixFilter的检查程序代码:

public class TopLevelDomainChecker  {
    private Set<String> exceptions;
    private Set<String> suffixes;

    public void setPublicSuffixes(Collection<String> suffixes) {
        this.suffixes = new HashSet<String>(suffixes);
    }
    public void setExceptions(Collection<String> exceptions) {
        this.exceptions = new HashSet<String>(exceptions);
    }

    /**
     * Checks if the domain is a TLD.
     * @param domain
     * @return
     */
    public boolean isTLD(String domain) {
        if (domain.startsWith(".")) 
            domain = domain.substring(1);

        // An exception rule takes priority over any other matching rule.
        // Exceptions are ones that are not a TLD, but would match a pattern rule
        // e.g. bl.uk is not a TLD, but the rule *.uk means it is. Hence there is an exception rule
        // stating that bl.uk is not a TLD. 
        if (this.exceptions != null && this.exceptions.contains(domain)) 
            return false;


        if (this.suffixes == null) 
            return false;

        if (this.suffixes.contains(domain)) 
            return true;

        // Try patterns. ie *.jp means that boo.jp is a TLD
        int nextdot = domain.indexOf('.');
        if (nextdot == -1)
            return false;
        domain = "*" + domain.substring(nextdot);
        if (this.suffixes.contains(domain)) 
            return true;

        return false;
    }


    public String extractSLD(String domain)
    {
        String last = domain;
        boolean anySLD = false;
        do
        {
            if (isTLD(domain))
            {
                if (anySLD)
                    return last;
                else
                    return "";
            }
            anySLD = true;
            last = domain;
            int nextDot = domain.indexOf(".");
            if (nextDot == -1)
                return "";
            domain = domain.substring(nextDot+1);
        } while (domain.length() > 0);
        return "";
    }
}

解析器。我重命名了。

/**
 * Parses the list from <a href="http://publicsuffix.org/">publicsuffix.org
 * Copied from http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/cookie/PublicSuffixListParser.java
 */
public class TopLevelDomainParser {
    private static final int MAX_LINE_LEN = 256;
    private final TopLevelDomainChecker filter;

    TopLevelDomainParser(TopLevelDomainChecker filter) {
        this.filter = filter;
    }
    public void parse(Reader list) throws IOException {
        Collection<String> rules = new ArrayList();
        Collection<String> exceptions = new ArrayList();
        BufferedReader r = new BufferedReader(list);
        StringBuilder sb = new StringBuilder(256);
        boolean more = true;
        while (more) {
            more = readLine(r, sb);
            String line = sb.toString();
            if (line.length() == 0) continue;
            if (line.startsWith("//")) continue; //entire lines can also be commented using //
            if (line.startsWith(".")) line = line.substring(1); // A leading dot is optional
            // An exclamation mark (!) at the start of a rule marks an exception to a previous wildcard rule
            boolean isException = line.startsWith("!"); 
            if (isException) line = line.substring(1);

            if (isException) {
                exceptions.add(line);
            } else {
                rules.add(line);
            }
        }

        filter.setPublicSuffixes(rules);
        filter.setExceptions(exceptions);
    }
    private boolean readLine(Reader r, StringBuilder sb) throws IOException {
        sb.setLength(0);
        int b;
        boolean hitWhitespace = false;
        while ((b = r.read()) != -1) {
            char c = (char) b;
            if (c == '\n') break;
            // Each line is only read up to the first whitespace
            if (Character.isWhitespace(c)) hitWhitespace = true;
            if (!hitWhitespace) sb.append(c);
            if (sb.length() > MAX_LINE_LEN) throw new IOException("Line too long"); // prevent excess memory usage
        }
        return (b != -1);
    }
}

最后,如何使用它

    FileReader fr = new FileReader("effective_tld_names.dat.txt");
    TopLevelDomainChecker checker = new TopLevelDomainChecker();
    TopLevelDomainParser parser = new TopLevelDomainParser(checker);
    parser.parse(fr);
    boolean result;
    result = checker.isTLD("com"); // true
    result = checker.isTLD("com.au"); // true
    result = checker.isTLD("ltd.uk"); // true
    result = checker.isTLD("google.com"); // false
    result = checker.isTLD("google.com.au"); // false
    result = checker.isTLD("metro.tokyo.jp"); // false
    String sld;
    sld = checker.extractSLD("com"); // ""
    sld = checker.extractSLD("com.au"); // ""
    sld = checker.extractSLD("google.com"); // "google.com"
    sld = checker.extractSLD("google.com.au"); // "google.com.au"
    sld = checker.extractSLD("www.google.com.au"); // "google.com.au"
    sld = checker.extractSLD("www.google.com"); // "google.com"
    sld = checker.extractSLD("foo.bar.hokkaido.jp"); // "foo.bar.hokkaido.jp"
    sld = checker.extractSLD("moo.foo.bar.hokkaido.jp"); // "foo.bar.hokkaido.jp"

答案 4 :(得分:1)

答案 5 :(得分:0)

我对你的具体案例没有答案 - 而Jonathan的评论指出你应该重构你的问题。

不过,我建议看一下Reference项目的Restlet类。它有很多有用的方法。由于Restlet是开源的,因此您不必使用整个库 - 您可以下载源代码并将该类添加到您的项目中。

答案 6 :(得分:0)

这是你想要的。 publicSuffix

答案 7 :(得分:0)

1

来自simbo1905贡献的方法nonePublicDomainParts应该更正,因为TLD包含".",例如"com.ac"

input: "com.abc.com.ac"

output: "abc"

正确的输出是"com.abc"

要获得SLD,您可以使用方法TLD从特定域中删除publicSuffix()

2

由于包含相同部分的域,不应使用集合,例如:

input: part1.part2.part1.TLD

output: part1, part2

正确输出为:part1, part2, part1或格式为part1.part2.part1

而不是Set<String>使用List<String>

答案 8 :(得分:0)

public static String getTopLevelDomain(String uri) {

InternetDomainName fullDomainName = InternetDomainName.from(uri);
InternetDomainName publicDomainName = fullDomainName.topPrivateDomain();
String topDomain = "";

Iterator<String> it = publicDomainName.parts().iterator();
while(it.hasNext()){
    String part = it.next();
    if(!topDomain.isEmpty())topDomain += ".";
    topDomain += part;
}
return topDomain;
}

只需提供域名,您将获得顶级域名。 从http://code.google.com/p/guava-libraries/下载jar文件

答案 9 :(得分:0)

Dnspypublicsuffix lib的另一种更灵活的替代方法。

答案 10 :(得分:-1)

如果您想要二级域名,可以将字符串拆分为“。”并采取最后两部分。当然,这假设您总是拥有一个非特定于该网站的二级域名(因为它听起来就像您想要的那样)。