2017-03-05 128 views
2

我有蜘蛛處理鏈中的請求使用meta產生具有來自多個請求的數據的項目。 我用來生成請求的方式是在第一次調用解析函數時啓動所有請求,但是,如果我有太多的鏈接來請求並不是所有的請求都被調度,並且我最終沒有得到所需的一切。Scrapy蜘蛛沒有收到spider_idle信號

爲了解決這個問題,我試圖讓蜘蛛請求5種產品,當蜘蛛閒置時(通過連接from_crawler中的信號)再次請求蜘蛛。 問題是,因爲我的代碼是現在,spider_idle不運行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

我假設你已經證明了其爲達到您的request方法和實際的問題是,這個方法不屈服的要求(甚至項) 。

這是在處理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