6

私は実行中のscrapyプロジェクトを持っていますが、多くのバイナリファイル(zip、tar、mp3、.. etc)をダウンロードしようとするため、帯域幅を大量に消費します。

最善の解決策は、mimetype(Content-Type:)HTTPヘッダーに基づいてリクエストをフィルタリングすることだと思います。私はスクレイプコードを見て、この設定を見つけました:

DOWNLOADER_HTTPCLIENTFACTORY = 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory'

私はそれを次のように変更しました:DOWNLOADER_HTTPCLIENTFACTORY ='myproject.webclients.ScrapyHTTPClientFactory'

そして、で少し遊んだScrapyHTTPPageGetter、ここにハイライトされた編集があります:

class ScrapyHTTPPageGetter(HTTPClient):
    # this is my edit
    def handleEndHeaders(self):
        if 'Content-Type' in self.headers.keys():
            mimetype = str(self.headers['Content-Type'])
            # Actually I need only the html, but just in 
            # case I've preserved all the text
            if mimetype.find('text/') > -1: 
                # Good, this page is needed
                self.factory.gotHeaders(self.headers)
            else:
                self.factory.noPage(Exception('Incorrect Content-Type'))

これは間違っていると思います。不要なmimetypeであると判断した直後に、リクエストをキャンセル/ドロップするためのよりスクレイプな方法が必要です。データ全体がダウンロードされるのを待つ代わりに。

編集:
私は特にこの部分を求めself.factory.noPage(Exception('Incorrect Content-Type'))ていますが、それはリクエストをキャンセルする正しい方法です。

アップデート1:
現在のセットアップでScrapyサーバーがクラッシュしたため、問題を解決するために上記と同じコードを使用しないでください。

更新2:
次の構造を使用してテストするためにApacheベースのWebサイトをセットアップしました。

/var/www/scrapper-test/Zend -> /var/www/scrapper-test/Zend.zip (symlink)
/var/www/scrapper-test/Zend.zip

Scrapyは.zip拡張子の付いたものを破棄しますが、.zipのないものは単なるシンボリックリンクであるにもかかわらず、破棄することに気づきました。

4

3 に答える 3

11

正規表現のホワイトリストにない応答タイプを除外するために、このミドルウェアを構築しました。

from scrapy.http.response.html import HtmlResponse
from scrapy.exceptions import IgnoreRequest
from scrapy import log
import re

class FilterResponses(object):
    """Limit the HTTP response types that Scrapy dowloads."""

    @staticmethod
    def is_valid_response(type_whitelist, content_type_header):
        for type_regex in type_whitelist:
            if re.search(type_regex, content_type_header):
                return True
        return False

    def process_response(self, request, response, spider):
        """
        Only allow HTTP response types that that match the given list of 
        filtering regexs
        """
        # each spider must define the variable response_type_whitelist as an
        # iterable of regular expressions. ex. (r'text', )
        type_whitelist = getattr(spider, "response_type_whitelist", None)
        content_type_header = response.headers.get('content-type', None)
        if not type_whitelist:
            return response
        elif not content_type_header:
            log.msg("no content type header: {}".format(response.url), level=log.DEBUG, spider=spider)
            raise IgnoreRequest()
        elif self.is_valid_response(type_whitelist, content_type_header):
            log.msg("valid response {}".format(response.url), level=log.DEBUG, spider=spider)
            return response
        else:
            msg = "Ignoring request {}, content-type was not in whitelist".format(response.url)
            log.msg(msg, level=log.DEBUG, spider=spider)
            raise IgnoreRequest()

これを使用するには、settings.py に追加します。

DOWNLOADER_MIDDLEWARES = {
    '[project_name].middlewares.FilterResponses': 999,
}
于 2014-05-12T20:05:28.747 に答える
0

遅いかもしれません。Accept ヘッダーを使用して、探しているデータをフィルタリングできます。

于 2013-01-04T12:22:02.150 に答える
-1

解決策は、プロキシをセットアップし、環境変数Node.jsを介してそれを使用するように Scrapy を構成することです。http_proxy

プロキシがすべきことは次のとおりです。

  • Scrapy から HTTP リクエストを受け取り、クロールされているサーバーに送信します。次に、Scrapy からの応答を返します。つまり、すべての HTTP トラフィックをインターセプトします。
  • バイナリ ファイルの場合 (実装するヒューリスティックに基づく)、403 ForbiddenScrapy にエラーを送信し、要求/応答をすぐに閉じます。これにより、時間とトラフィックを節約でき、Scrapy はクラッシュしません。

サンプル プロキシ コード

それは実際に機能します!

http.createServer(function(clientReq, clientRes) {
    var options = {
        host: clientReq.headers['host'],
        port: 80,
        path: clientReq.url,
        method: clientReq.method,
        headers: clientReq.headers
    };


    var fullUrl = clientReq.headers['host'] + clientReq.url;
    
    var proxyReq = http.request(options, function(proxyRes) {
        var contentType = proxyRes.headers['content-type'] || '';
        if (!contentType.startsWith('text/')) {
            proxyRes.destroy();            
            var httpForbidden = 403;
            clientRes.writeHead(httpForbidden);
            clientRes.write('Binary download is disabled.');
            clientRes.end();
        }
        
        clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
        proxyRes.pipe(clientRes);
    });

    proxyReq.on('error', function(e) {
        console.log('problem with clientReq: ' + e.message);
    });

    proxyReq.end();
  
}).listen(8080);
于 2013-12-12T11:58:36.670 に答える