一种非常强大的方法来逃避Java中的URL?

时间:2015-10-01 13:44:19

标签: java url

我正在运行一个小型网络爬虫,所以我真的需要一种方法来统一管理所有发现的网址。所以,我已经确定标准是带有punycode主机名的百分比编码的URL。如何将垃圾解析器找到的任何内容转换为正确转义的URL?到目前为止,我想出了以下代码:

import java.io.UnsupportedEncodingException;
import java.net.IDN;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;

public class URLEscaper {

 public static String toURI(String url) throws Exception {

    if (url == null) return null;

    // The input string might already be an escaped url, so decode
    // it first, which is an idempotent operation:
    URL u = new URL(URLDecoder.decode(url,"UTF-8"));

    String scheme = u.getProtocol();
    String usercreds = u.getUserInfo();
    String host = IDN.toASCII(u.getHost());
    int port = u.getPort();
    String path = u.getPath();
    String query = u.getQuery();
    String fragment = u.getRef();
    URI result = new URI(scheme, usercreds, host, port, path, query, fragment);

    return result.toASCIIString();

 }
}

此函数的问题是遵循RFC的java.net.URI严格,它声明主机名不能包含除[a-z0-9-]之外的任何符号。因此,如果主机名包含,例如下划线'_',那么URI构造函数将抛出URISyntaxException。互联网上有很多完全可访问的网站,其中包含主机名中的下划线。而且我不想失去那些。我可以使用什么代替java.net.URI?

1 个答案:

答案 0 :(得分:1)

因此它适用于Apache的commons-httpclient版本的URI实现。

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

简单测试

org.apache.commons.httpclient.URI uri = new URI("http://a_domain_with_underscores.com:8080/demo/index.hp?query=param", true);
System.out.println(uri.getHost());

您可以在控制台中打印域名

a_domain_with_underscores.com

它不适用于apache commons 4,不同的maven groupId / artifact,因为apache已经放弃了URI的内部实现,而是停留在java.net.URI;关于它的好处是Apache提供了一个很好的org.apache.http.client.utils.URIBuilder而不是那些丑陋的java.net.URI构造函数:)

这是Apache的http客户端工件的最新版本......

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.1</version>
</dependency>

所以代码看起来像这样

URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme("http").setHost("a_domain_with_underscores.com").setPort(8080);
java.net.URI builtURI = uriBuilder.build();
System.out.println(builtURI.getHost());

你最终会在控制台中找到一个令人讨厌的null