我正在构建一个简单的web-scraper,我需要获取相同的页面几百次,并且页面中的属性是动态的,并且应该在每个请求时更改。我已经构建了一个基于多线程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");
}
答案 0 :(得分:4)
默认情况下,HTTPClient不使用缓存(仅当您使用DefaultHttpClient
类时)。它会这样做,如果你使用CachingHttpClient
HttpClient
接口装饰器启用缓存:
HttpClient client = new CachingHttpClient(new DefaultHttpClient(), cacheConfiguration);
然后,它会分析If-Modified-Since
和If-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,执行此脚本并再次比较文件。如果某些响应与其他响应相同,那么您可以确定这是代理服务器问题。
答案 1 :(得分:3)
一般来说,为了测试是否通过网络发出HTTP请求,您可以使用分析网络流量的“嗅探”工具,例如:
我非常怀疑HttpClient正在执行任何类型的缓存(这意味着它需要将页面存储在内存或磁盘上 - 而不是其功能之一)。
虽然这不是一个答案,但它需要思考:服务器(或其中的某个代理)是否有可能返回缓存的内容?如果您为同一内容执行许多请求(同时或几乎同时),服务器可能会返回缓存内容,因为它已确定信息尚未“过期”。事实上,HTTP协议为此类功能提供了缓存指令。这是一个提供不同HTTP缓存机制的高级概述的站点:
http://betterexplained.com/articles/how-to-optimize-your-site-with-http-caching/
我希望这能为你提供一个起点。如果您已经考虑过这些途径,那就太棒了。
答案 2 :(得分:1)
您可以尝试在每次请求时向URL添加一些唯一的伪参数,以尝试打败任何基于URL的缓存(在服务器中或沿途的某个位置)。如果缓存不是问题,或者服务器足够聪明以拒绝具有未知参数的请求,或者服务器正在缓存但仅基于其关注的参数,或者您选择的参数名称是否与之发生冲突,则它将无法工作网站实际使用的参数。
如果这是您正在使用的网址 http://www.example.org/index.html 尝试使用 http://www.example.org/index.html?dummy=1
为每个请求将dummy设置为不同的值。