2017-03-05 4 views
2

私は複数のリクエストからデータを持つアイテムを生成するためにmetaを使用してチェーン内のリクエストを処理するスパイダーを持っています。 リクエストを生成するために使用した方法は、最初に解析関数が呼び出されたときにすべてのリクエストを開始する方法ですが、リクエストするリンクが多すぎるとすべてのリクエストがスケジュールされず、最後に必要なものがすべて得られません。Scrapyスパイダーはspider_idleシグナルを受信しません

これを修正するために、スパイダーがアイドル状態になったときに再び要求する5つの製品を一度に5つの製品にしたいと考えています(from_crawlerの信号を接続して)。 問題は、私のコードが今では、spider_idleがrequest関数を実行せず、スパイダーがすぐに終了するということです。あたかもスパイダーが遊んでいないかのようです。私はすでにあなたのrequest方法に到達していると、実際の問題は、このメソッドはリクエスト(とさえアイテム)を得ていないことであることを証明したと仮定し

class ProductSpider(scrapy.Spider): 
    def __init__(self, *args, **kwargs): 
     super(ProductSpider, self).__init__(*args, **kwargs) 
     self.parsed_data = [] 
     self.header = {} 
     f = open('file.csv', 'r') 
     f_data = [[x.strip()] for x in f] 
     count=1 
     first = 'smth' 
     for product in f_data: 
      if first != '': 
       header = product[0].split(';') 
       for each in range(len(header[1:])): 
        self.header[header[each+1]] = each+1 
       first = '' 
      else: 
       product = product[0].split(';') 
       product.append(count) 
       count+=1 
       self.parsed_data.append(product) 
     f.close() 

    @classmethod 
    def from_crawler(cls, crawler, *args, **kwargs): 
     spider = super(ProductSpider, cls).from_crawler(crawler, *args, **kwargs) 
     crawler.signals.connect(spider.request, signal=signals.spider_idle) 
     return spider 

    name = 'products' 
    allowed_domains = [domains] 
    handle_httpstatus_list = [400, 404, 403, 503, 504] 

    start_urls = [start] 

    def next_link(self,response): 
     product = response.meta['product'] 
     there_is_next = False 
     for each in range(response.meta['each']+1, len(product)-1): 
      if product[each] != '': 
       there_is_next = True 
       yield scrapy.Request(product[each], callback=response.meta['func_dict'][each], meta={'func_dict': response.meta['func_dict'],'product':product,'each':each,'price_dict':response.meta['price_dict'], 'item':response.meta['item']}, dont_filter=True) 
       break 
     if not there_is_next: 
      item = response.meta['item'] 
      item['prices'] = response.meta['price_dict'] 
      yield item 

    #[...] chain parsing functions for each request 

    def get_products(self): 
     products = [] 
     data = self.parsed_data 

     for each in range(5): 
      if data: 
       products.append(data.pop()) 
     return products 

    def request(self): 
     item = Header() 
     item['first'] = True 
     item['sellers'] = self.header 
     yield item 

     func_dict = {parsing_functions_for_every_site} 

     products = self.get_products() 
     if not products: 
      return 

     for product in products: 

      item = Product() 

      price_dict = {1:product[1]} 
      item['name'] = product[0] 
      item['order'] = product[-1] 

      for each in range(2, len(product)-1): 
       if product[each] != '': 
        #print each, func_dict, product[each] 
        yield scrapy.Request(product[each], callback=func_dict[each], 
        meta={'func_dict': func_dict,'product':product, 
        'each':each,'price_dict':price_dict, 'item':item}) 
        break 

     raise DontCloseSpider 

def parse(self, response=None): 
     pass 

答えて

2

:ここ

は、コードの一部であります。

関連するメソッドがアイテム/リクエストを生成できないため、これはScrapyのシグナルを扱う際のよくある間違いです。アイテムの

request = Request('myurl', callback=self.method_to_parse) 
self.crawler.engine.crawl(
    request, 
    spider 
) 

:この要求に対して

を使用してバイパスするようにして

item = MyItem() 
self.crawler.engine.scraper._process_spidermw_output(
    item, 
    None, 
    Response(''), 
    spider, 
) 

はまた、spider_idle信号方式は、spider引数を受信する必要がありますあなたのケースは次のようになります:

def request(self, spider): 
    ... 

それはうまくいくはずですが、より良いメソッド名をお勧めします。

+0

いいえ!ありがとう、それは動作する:)通常のscrapy.Request()とself.crawler.engine.crawlの違いは何ですか? – AimiHat

+1

実際の違いはありません。唯一のことは、 'scrapy'がコールバックメソッドを処理して気付かずにリクエストキューに追加し、' self.crawler.engine..'でリクエストを明示的に追加していることです – eLRuLL

関連する問題