我正在创建一个(行为良好的)网络爬虫,并且注意到一些服务器会导致Apache HttpClient给我返回SocketException错误,具体地说:
java.net.SocketException: Connection reset
导致这个问题的代码是:
// Execute the request
HttpResponse response;
try {
response = httpclient.execute(httpget); //httpclient is of type HttpClient
} catch (NullPointerException e) {
return;//deep down in apache http sometimes throws a null pointer...
}
对于大多数服务器来说,这是完全可以的。但对于其他一些服务器,它会立即抛出SocketException异常。
导致立即抛出SocketException异常的网站示例:http://www.bhphotovideo.com/ 非常好用(像大多数网站一样):http://www.google.com/ 现在,您可以看到,www.bhphotovideo.com在Web浏览器中加载良好。当我不使用Apache的HTTP客户端时,它也可以正常加载。(例如以下代码:)
HttpURLConnection c = (HttpURLConnection)url.openConnection();
BufferedInputStream in = new BufferedInputStream(c.getInputStream());
Reader r = new InputStreamReader(in);
int i;
while ((i = r.read()) != -1) {
source.append((char) i);
}
那么为什么我不直接使用这段代码呢?因为我需要使用Apache HTTP Client中的一些关键功能。
有人知道是什么导致某些服务器引起这个异常吗?
到目前为止的研究:
问题发生在我的本地Mac开发机器和AWS EC2实例上,所以它不是一个本地防火墙的问题。
似乎错误不是由远程机器引起的,因为异常没有说“by peer”。
这个堆栈溢出看起来很相关java.net.SocketException:连接重置但答案并没有说明为什么只有使用Apache HTTP Client而不是其他方法会发生这种情况。
额外的问题:我正在使用这个系统进行相当多的爬取。除了Apache HTTP Client之外,通常是否有更好的Java类可用于此?我发现了许多问题(例如我必须在上面的代码中捕获NullPointerException)。HTTPClient似乎对服务器通信非常挑剔——比我想象的更挑剔,对于一个不能只在服务器行为不良时就退出的爬虫来说,这并不理想。
谢谢大家!
解决方案
老实说,我没有一个完美的解决方案,但它能够工作,所以对我来说已经足够好了。
正如oleg所指出的那样,Bixo创建了一个爬虫,定制了HttpClient,使其对服务器更加宽容。为了“绕过”问题而不是解决它,我只使用了Bixo提供的SimpleHttpFetcher:
(链接已删除- SO认为我是垃圾邮件发送者,所以你需要自己Google它)SimpleHttpFetcher fetch = new SimpleHttpFetcher(new UserAgent("botname","contact@yourcompany.com","ENTER URL"));
try {
FetchedResult result = fetch.fetch("ENTER URL");
System.out.println(new String(result.getContent()));
} catch (BaseFetchException e) {
e.printStackTrace();
}
这种解决方案的缺点是Bixo有很多依赖项,所以这可能不是每个人都适用的好方法。但是,您可以始终通过使用DefaultHttpClient来解决问题,并查看它们如何实例化它才能使其工作。我选择使用整个类,因为它为我处理了一些东西,例如自动重定向跟随(并报告最终目标URL),这对我很有帮助。
感谢所有人的帮助。
编辑:TinyBixo
大家好。所以,我喜欢Bixo的工作方式,但不喜欢它有很多依赖项(包括所有Hadoop)。因此,我创建了一个大大简化的Bixo,没有所有的依赖关系。如果您遇到上述问题,我建议使用它(如果您想更新,请随时提出拉取请求!)
它在这里可用:https://github.com/juliuss/TinyBixo