2017-03-05 88 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