it-swarm.com.de

Wie normalisiere ich eine URL in Java?

URL-Normalisierung (oder URL-Kanonisierung) ist der Prozess, durch den URLs konsistent modifiziert und standardisiert werden. Das Ziel des Normalisierungsprozesses besteht darin, eine URL in eine normalisierte oder kanonische URL umzuwandeln, sodass festgestellt werden kann, ob zwei syntaktisch unterschiedliche URLs gleichwertig sind.

Zu den Strategien gehören das Hinzufügen nachstehender Schrägstriche, https => http usw. Die Wikipedia-Seite enthält viele.

Hast du eine Lieblingsmethode dafür in Java? Vielleicht eine Bibliothek ( Nutch ?), Aber ich bin offen. Kleinere und weniger Abhängigkeiten sind besser.

Ich werde jetzt etwas von Handcode schreiben und diese Frage im Auge behalten.

EDIT: Ich möchte aggressiv normalisieren, um URLs als gleich zu zählen, wenn sie sich auf denselben Inhalt beziehen. Zum Beispiel ignoriere ich die Parameter utm_source, utm_medium, utm_campaign. Zum Beispiel ignoriere ich die Subdomain, wenn der Titel derselbe ist.

28
dfrankow
22
Nitrodist

Ich habe diese Frage gestern Abend gefunden, aber es gab keine Antwort, nach der ich gesucht hatte. Hier ist es unvorstellbar, dass jemand in der Zukunft es will:

/**
 * - Covert the scheme and Host to lowercase (done by Java.net.URL)
 * - Normalize the path (done by Java.net.URI)
 * - Add the port number.
 * - Remove the fragment (the part after the #).
 * - Remove trailing slash.
 * - Sort the query string params.
 * - Remove some query string params like "utm_*" and "*session*".
 */
public class NormalizeURL
{
    public static String normalize(final String taintedURL) throws MalformedURLException
    {
        final URL url;
        try
        {
            url = new URI(taintedURL).normalize().toURL();
        }
        catch (URISyntaxException e) {
            throw new MalformedURLException(e.getMessage());
        }

        final String path = url.getPath().replace("/$", "");
        final SortedMap<String, String> params = createParameterMap(url.getQuery());
        final int port = url.getPort();
        final String queryString;

        if (params != null)
        {
            // Some params are only relevant for user tracking, so remove the most commons ones.
            for (Iterator<String> i = params.keySet().iterator(); i.hasNext();)
            {
                final String key = i.next();
                if (key.startsWith("utm_") || key.contains("session"))
                {
                    i.remove();
                }
            }
            queryString = "?" + canonicalize(params);
        }
        else
        {
            queryString = "";
        }

        return url.getProtocol() + "://" + url.getHost()
            + (port != -1 && port != 80 ? ":" + port : "")
            + path + queryString;
    }

    /**
     * Takes a query string, separates the constituent name-value pairs, and
     * stores them in a SortedMap ordered by lexicographical order.
     * @return Null if there is no query string.
     */
    private static SortedMap<String, String> createParameterMap(final String queryString)
    {
        if (queryString == null || queryString.isEmpty())
        {
            return null;
        }

        final String[] pairs = queryString.split("&");
        final Map<String, String> params = new HashMap<String, String>(pairs.length);

        for (final String pair : pairs)
        {
            if (pair.length() < 1)
            {
                continue;
            }

            String[] tokens = pair.split("=", 2);
            for (int j = 0; j < tokens.length; j++)
            {
                try
                {
                    tokens[j] = URLDecoder.decode(tokens[j], "UTF-8");
                }
                catch (UnsupportedEncodingException ex)
                {
                    ex.printStackTrace();
                }
            }
            switch (tokens.length)
            {
                case 1:
                {
                    if (pair.charAt(0) == '=')
                    {
                        params.put("", tokens[0]);
                    }
                    else
                    {
                        params.put(tokens[0], "");
                    }
                    break;
                }
                case 2:
                {
                    params.put(tokens[0], tokens[1]);
                    break;
                }
            }
        }

        return new TreeMap<String, String>(params);
    }

    /**
     * Canonicalize the query string.
     *
     * @param sortedParamMap Parameter name-value pairs in lexicographical order.
     * @return Canonical form of query string.
     */
    private static String canonicalize(final SortedMap<String, String> sortedParamMap)
    {
        if (sortedParamMap == null || sortedParamMap.isEmpty())
        {
            return "";
        }

        final StringBuffer sb = new StringBuffer(350);
        final Iterator<Map.Entry<String, String>> iter = sortedParamMap.entrySet().iterator();

        while (iter.hasNext())
        {
            final Map.Entry<String, String> pair = iter.next();
            sb.append(percentEncodeRfc3986(pair.getKey()));
            sb.append('=');
            sb.append(percentEncodeRfc3986(pair.getValue()));
            if (iter.hasNext())
            {
                sb.append('&');
            }
        }

        return sb.toString();
    }

    /**
     * Percent-encode values according the RFC 3986. The built-in Java URLEncoder does not encode
     * according to the RFC, so we make the extra replacements.
     *
     * @param string Decoded string.
     * @return Encoded string per RFC 3986.
     */
    private static String percentEncodeRfc3986(final String string)
    {
        try
        {
            return URLEncoder.encode(string, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
        }
        catch (UnsupportedEncodingException e)
        {
            return string;
        }
    }
}
19
Amy B

Die RL - Bibliothek: https://github.com/backchatio/rl Geht weit über Java.net.URL.normalize () ..__ hinaus. Sie befindet sich in Scala , aber ich kann mir vorstellen, dass es von Java aus verwendet werden kann.

3
pdxleif

Da Sie auch URLs identifizieren möchten, die sich auf denselben Inhalt beziehen, fand ich dieses Dokument aus dem WWW2007 sehr interessant: Nicht im DUST kriechen: Unterschiedliche URLs mit ähnlichem Text . Es bietet Ihnen einen schönen theoretischen Ansatz.

2
H6.

Nein, die Standardbibliotheken enthalten dazu nichts. Die Kanonisierung umfasst Dinge wie das Dekodieren unnötig codierter Zeichen, das Konvertieren von Hostnamen in Kleinbuchstaben usw.

z.B. http://ACME.com/./foo%26bar wird zu:

http://acme.com/foo&bar

URIs normalize() macht nicht tut dies.

2
Randy Hudson

Normalisieren Sie in Java eine URL manuell

String company_website = "http://www.foo.bar.com/whatever&stuff";

try {
    URL url = new URL(company_website);
    System.out.println(url.getProtocol() + "://" + url.getHost());
} catch (MalformedURLException e) {
    e.printStackTrace();
}

//prints `http://www.foo.bar.com`

Die Java-URL-Klasse verfügt über alle Arten von Methoden, um einen beliebigen Teil der URL zu analysieren.

1
Eric Leschinski

Sie können dies mit dem Restlet framework mit Reference.normalize() tun. Sie sollten auch in der Lage sein, die Elemente, die Sie nicht benötigen, mit dieser Klasse bequem zu entfernen.

1
Bruno

Ich habe eine einfache Möglichkeit, es zu lösen. Hier ist mein Code 

public static String normalizeURL(String oldLink)
{
    int pos=oldLink.indexOf("://");
    String newLink="http"+oldLink.substring(pos);
    return newLink;
}
0
Thanh Duy Phan