2012-03-17 9 views
2

Preambule:Scrapy:スパイダーミドルウェアの非同期データベース要求?

私は、データベースにその結果を保存するクモを持っています。それで、時間と遠隔Webサーバーのリソースを節約するために、私は既にデータベースにあるアイテムを要求しないことに決めました。ドキュメントを読む私はカスタムスパイダーミドルウェアが私が持っている最良の選択だと決めました。 item_in_databaseはデシベルを照会

class SkipDupeMiddleware(object): 
    process_spider_output(response, result, spider): 
     for r in result: 
      if isinstance(r, Request) and item_in_database(r.url): 
       log.msg('Skip %s' % r.url) 
      else: 
       yield r 

また、素晴らしい動作と多くの時間を節約できます。

は今本当の問題:

後、私は非ブロッキングアプリケーションでのブロッキングデータベース要求を使用することは良い考えではないことをお読みください。私はいつもまで「正しいことを行う」だと私はadbapiでパイプラインを使用するレシピを発見したadbapi

内のすべての私のDBリクエストをラップすることを決めたが、それはその中のミドルウェアレベルを行うことが可能ですか?ミドルウェアはBaseItemRequestまたはNoneを返すと予想されますが、adbapitwistedDeferredを返します。後でRequestまたはNoneを返します。

今、私は立ち往生しています。

+0

は、この問題はすでに私が知っている他の例では、パイプラインを使用して解決されます。 db lagの問題がまだ残っている場合は、動的なローカル索引を作成して、解析した後に更新することができます(サーバーにメモリーの問題がないため)。ミドルウェアは静かなdbデータの可用性によっても影響を受けます。 – Kruser

答えて

1

AFAIK、

治療はほとんど同期的です。ページのダウンロードだけが非同期で行われるため、リクエストにコールバックがあるのです。

パイプラインとミドルウェアは同期しています。

+0

実際には、パイプラインメソッドと要求コールバックの両方が非同期になり、遅延を返す可能性があります。 –

2

process_item()パイプラインから遅延を返すことができます。

+0

私はパイプラインについて知っている、質問はミドルウェアについてだった – dmzkrsk

1

既定では、重複フィルタを使用して、デフォルトではスクラブはクロールで重複要求を行いません(デフォルトではenalbedby)。設定パラメータDUPEFILTER_CLASは、使用するフィルタを決定します デフォルト値は 'scrapy.dupefilter.RFPDupeFilter'です。実際には、今は の選択のみです。 永続機能を使用する場合は、JOBDIRを設定する必要があります。それから、scrapyは、アクセスされたURLを格納し、次の実行時にそれらを(フィルタのdictに)ロードします。

あなたがここにいくつかのヒントを得ることができます。 http://groups.google.com/group/scrapy-users/browse_thread/thread/56546e9fab7030f3

0

は、同様の問題が、私はいくつかのチェックをしたい最初の数項目のためのクモ中(デシベルコールが含まれます)と、チェックが渡された場合(クロールを停止私は、ほんの少しのリクエストがある場合、DB接続をブロックすることでそれらを行うことができると思います。

私は心配しています。もし、スパイダースパイダーが、私たちが掻き集めたサイトへのHTTPリクエストをうまく行っているなら、同じメカニズムを使って非同期dbリクエストをしましょう。 elasticsearchのように、REST APIを持つデータベースに実装するのは簡単でなければなりません。これは私がAWS S3のために作られたものです

from types import MethodType 

import botocore.session 
import treq 
from scrapy import Request 


class BotocoreRequest(Exception): 

    def __init__(self, request, *args, **kwargs): 
     super(BotocoreRequest, self).__init__(*args, **kwargs) 
     self.method = request.method 
     # https://github.com/twisted/treq/issues/185 
     self.url = request.url.replace('https://', 'http://') 
     self.headers = dict(request.headers) 
     self.body = request.body and request.body.read() 


def _send_request(self, request_dict, operation_model): 
    request = self.create_request(request_dict, operation_model) 
    raise BotocoreRequest(request=request) 


class ScrapyAWSClient(object): 
    def __init__(self, service, access_key, secret_key, region, timeout=30): 
     session = botocore.session.get_session() 
     session.set_credentials(
      access_key=access_key, 
      secret_key=secret_key 
     ) 
     self.client = session.create_client(service, region_name=region) 
     endpoint = self.client._endpoint 
     endpoint._send_request = MethodType(_send_request, endpoint) 
     self.timeout = timeout 

    def request(self, method, callback, meta, **kwargs): 
     try: 
      getattr(self.client, method)(**kwargs) 
     except BotocoreRequest as e: 
      return Request(
       method=e.method, 
       url=e.url, 
       body=e.body, 
       headers=e.headers, 
       meta=meta, 
       callback=callback, 
       dont_filter=True 
      ) 

スパイダー:

class MySpider(Spider): 

    def __init__(self, *args, **kwargs): 
     super(MySpider, self).__init__(*args, **kwargs) 
     self.client = ScrapyAWSClient(
      service='s3', 
      access_key='', 
      secret_key='', 
      region='your-region' 
     ) 

    def parse(self, response): 
     ... 
     yield self.client.request(
      method='get_object', 
      Bucket='my-s3-bucket', 
      Key='my-key', 
      callback=self.my_parser, 
      meta={ 
       'handle_httpstatus_list': [200, 403] 
      } 
     ) 
関連する問題