5

我正在构建一个简单的网络抓取工具,我需要获取同一页面几百次,并且页面中有一个动态属性,并且应该在每次请求时更改。我已经构建了一个基于多线程 HttpClient 的类来处理请求,并且我正在使用一个ExecutorService来创建一个线程池并运行线程。问题是动态属性有时不会在每个请求上发生变化,我最终会在 3 或 4 个后续线程上获得相同的值。我已经阅读了很多关于 HttpClient 的内容,但我真的找不到这个问题来自哪里。可能是关于缓存的东西,或者类似的东西!?

更新:这是在每个线程中执行的代码:

HttpContext localContext = new BasicHttpContext();

HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params,
        HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);

ClientConnectionManager connman = new ThreadSafeClientConnManager();

DefaultHttpClient httpclient = new DefaultHttpClient(connman, params);

HttpHost proxy = new HttpHost(inc_proxy, Integer.valueOf(inc_port));
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
        proxy);

HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("User-Agent",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)");

String iden = null;
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpGet.getParams(),
        timeoutConnection);

try {

    HttpResponse response = httpclient.execute(httpGet, localContext);

    HttpEntity entity = response.getEntity();

    if (entity != null) {

        InputStream instream = entity.getContent();
        String result = convertStreamToString(instream);
        // System.out.printf("Resultado\n %s",result +"\n");
        instream.close();

        iden = StringUtils
                .substringBetween(result,
                        "<input name=\"iden\" value=\"",
                        "\" type=\"hidden\"/>");
        System.out.printf("IDEN:%s\n", iden);
        EntityUtils.consume(entity);
    }

}

catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    System.out.println("Excepção CP");

} catch (IOException e) {
    // TODO Auto-generated catch block
    System.out.println("Excepção IO");
}
4

3 回答 3

5

HTTPClient 默认不使用缓存(仅当您使用DefaultHttpClient类时)。如果您使用启用缓存的接口装饰器CachingHttpClient,它会这样做:HttpClient

HttpClient client = new CachingHttpClient(new DefaultHttpClient(), cacheConfiguration);

然后,它分析If-Modified-SinceIf-None-Match标头以确定是否执行了对远程服务器的请求,或者其结果是否从缓存中返回。

我怀疑,您的问题是由位于您的应用程序和远程服务器之间的代理服务器引起的。

您可以使用应用程序轻松测试它curl;执行一些省略代理的请求:

#!/bin/bash

for i in {1..50}
do
  echo "*** Performing request number $i"
  curl -D - http://yourserveraddress.com -o $i -s
done

然后,diff在所有下载的文件之间执行。他们都应该有你提到的差异。然后,-x/--proxy <host[:port]>为 curl 添加选项,执行此脚本并再次比较文件。如果某些响应与其他响应相同,则可以确定这是代理服务器问题。

于 2012-03-10T14:04:57.257 回答
3

一般来说,为了测试是否通过网络发出 HTTP 请求,您可以使用分析网络流量的“嗅探”工具,例如:

我非常怀疑 HttpClient 是否正在执行任何类型的缓存(这意味着它需要将页面存储在内存或磁盘上 - 而不是它的功能之一)。

虽然这不是一个答案,但值得深思:服务器(或介于两者之间的某个代理)是否有可能返回您缓存的内容?如果您对同一内容执行许多请求(同时或几乎同时),则服务器可能会返回您缓存的内容,因为它已确定信息尚未“过期”。事实上,HTTP 协议为此类功能提供了缓存指令。这是一个提供不同 HTTP 缓存机制的高级概述的站点:

http://betterexplained.com/articles/how-to-optimize-your-site-with-http-caching/

我希望这能给你一个起点。如果您已经考虑过这些途径,那就太好了。

于 2012-03-09T22:25:38.333 回答
1

您可以尝试在每个请求的 URL 上附加一些唯一的虚拟参数,以尝试破坏任何基于 URL 的缓存(在服务器中或沿途的某个地方)。如果缓存不是问题,或者如果服务器足够聪明以拒绝带有未知参数的请求,或者如果服务器正在缓存但仅基于它关心的参数,或者如果您选择的参数名称与网站实际使用的参数。

如果这是您使用的 URL http://www.example.org/index.html 尝试使用 http://www.example.org/index.html?dummy=1

为每个请求将 dummy 设置为不同的值。

于 2012-03-09T23:04:16.320 回答