5

私は単純な Web スクレイパーを構築していますが、同じページを数百回フェッチする必要があります。また、ページには動的であり、要求ごとに変更する必要がある属性があります。リクエストを処理するためにマルチスレッドの 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-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 にオプションを追加し、このスクリプトを実行して再度ファイルを比較します。一部の応答が他の応答と同じである場合、これはプロキシ サーバーの問題であると確信できます。

于 2012-03-10T14:04:57.257 に答える
3

一般的に言えば、HTTP リクエストがネットワーク経由で行われているかどうかをテストするには、ネットワーク トラフィックを分析する「スニッフィング」ツールを使用できます。次に例を示します。

HttpClient が何らかのキャッシュを実行していることは非常に疑わしいです (これは、その機能の 1 つでなく、ページをメモリまたはディスクに保存する必要があることを意味します)。

これは答えではありませんが、熟考するポイントは次のとおりです。サーバー (またはその間のプロキシ) がキャッシュされたコンテンツを返している可能性はありますか? 同じコンテンツに対して多くのリクエストを (同時にまたはほぼ同時に) 実行している場合、サーバーは情報がまだ「期限切れ」になっていないと判断したため、キャッシュされたコンテンツを返している可能性があります。実際、HTTP プロトコルは、そのような機能のためのキャッシュ ディレクティブを提供します。さまざまな HTTP キャッシュ メカニズムの概要を説明しているサイトを次に示します。

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

これが出発点になることを願っています。これらの方法をすでに検討している場合は、それで問題ありません。

于 2012-03-09T22:25:38.333 に答える
1

すべてのリクエストで一意のダミー パラメータを URL に追加して、URL ベースのキャッシング (サーバー内または途中のどこか) を無効にしようとすることができます。キャッシングが問題ではない場合、またはサーバーが未知のパラメーターを含むリクエストを拒否するほどスマートである場合、またはサーバーがキャッシングしているが関心のあるパラメーターのみに基づいている場合、または選択したパラメーター名が競合する場合は機能しませんサイトが実際に使用するパラメータ。

これが http://www.example.org/index.htmlを使用している URL である場合は、http://www.example.org/index.html?dummy=1 を使用してみて ください

ダミーをリクエストごとに異なる値に設定します。

于 2012-03-09T23:04:16.320 に答える