2017-03-05 6 views
2

Ich habe Spinne, die Anfragen in Kette mit meta verarbeitet, um Elemente, die Daten aus mehreren Anforderungen haben. Die Art und Weise, wie ich Anfragen generierte, ist die Initiierung aller Anfragen beim ersten Aufruf der Parse-Funktion. Wenn ich zu viele Links zur Anfrage habe, werden nicht alle eingeplant und ich bekomme am Ende nicht alles, was ich brauche.Scrapy Spider nicht Spider_idle Signal

Um das zu beheben, versuche ich, die Spinne anzufordern, 5 Produkte zu einem Zeitpunkt anzufordern, wieder anfordert, wenn die Spinne im Leerlauf ist (durch Anschließen eines Signals in from_crawler). Das Problem ist, dass, wie mein Code gerade jetzt ist, spider_idle nicht die request Funktion ausführt und der Spider schließt sofort. Es ist, als ob die Spinne nicht untätig ist.

Hier ist ein Teil des Codes:

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 

Antwort

2

Ich nehme an, Sie bereits bewiesen, dass Ihre request Methode und das eigentliche Problem ist erreicht wird, dass diese Methode die Anforderungen nicht nachgibt (und sogar die Elemente) .

Dies ist ein häufiger Fehler beim Umgang mit Signalen in Scrapy, da die zugehörigen Methoden keine Elemente/Anforderungen liefern können. Die Art und Weise, dies zu umgehen, wird mit

für Anfrage:

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

zum Artikel:

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

Auch die spider_idle Signalverfahren des spider Argument empfangen muss, so in Ihr Fall sollte es wie sein:

def request(self, spider): 
    ... 

Es sollte funktionieren, aber ich würde einen besseren Methodennamen empfehlen.

+0

In Ordnung! Danke, es scheint zu funktionieren :) Was ist der Unterschied zwischen einer normalen scrapy.Request() und self.crawler.engine.crawl? – AimiHat

+1

Es gibt keinen wirklichen Unterschied, die einzige Sache ist, dass 'scrapy' die Callback-Methoden handhabt, die sie der Requests-Queue hinzufügen, ohne dass Sie es bemerken, und mit' self.crawler.engine..' fügen Sie die Anfragen explizit hinzu – eLRuLL

Verwandte Themen