2016-07-18 4 views
0

Я пытаюсь создать паук, который берет данные из csv (две ссылки и имя для каждой строки) и сбрасывает простой элемент (цену) из каждой из этих ссылок, возвращая элемент для каждого строка с именем элемента, являющимся именем в csv, и двумя скремблированными ценами (по одному от каждой ссылки).Запрос на Scrapy не вызывает обратный вызов

Все работает, как и ожидалось, за исключением того, что вместо возвращения цены, которые будут возвращены из функции обратного вызова каждого запроса, я получаю объект запроса, как это:

< GET https://link.com> ..

Функции обратного вызова вообще не вызываются, почему?

Вот паук:

f = open('data.csv') 
f_reader = csv.reader(f) 
f_data = list(f_reader) 

parsed_data = [] 

for product in f_data: 
    product = product[0].split(';') 
    parsed_data.append(product) 

f.close() 

class ProductSpider(scrapy.Spider): 
    name = 'products' 
    allowed_domains = ['domain1', 'domain2'] 

    start_urls = ["domain1_but_its_fairly_useless"] 

    def parse(self, response): 
     global parsed_data 
     for product in parsed_data: 

      item = Product() 

      item['name'] = product[0] 
      item['first_price'] = scrapy.Request(product[1], callback=self.parse_first) 
      item['second_price'] = scrapy.Request(product[2], callback=self.parse_second) 
      yield item 


    def parse_first(self, response): 
     digits = response.css('.price_info .price span').extract() 
     decimals = response.css('.price_info .price .price_demicals').extract() 
     yield float(str(digits)+'.'+str(decimals)) 

    def parse_second(self, response): 
     digits = response.css('.lr-prod-pricebox-price .lr-prod-pricebox-price-primary span[itemprop="price"]').extract() 
     yield digits 

Заранее спасибо за вашу помощь!

+0

немного не по теме, но вы не должны использовать глобалам так и при записи в файл, как это плохая идея, как хорошо. Scrapy может автоматически создавать 'csv' с помощью' scrapy crawl spider -o output.csv'. – Granitosaurus

+0

Как я могу обойтись без глобального? Я знаю, что это плохая привычка, но я не знаю, как это сделать. CSV только для чтения существующего файла. Я экспортирую с помощью openpyxl в excel – AimiHat

+0

А, я вижу, что вы хотите сделать здесь. Почему бы не использовать переменную простого экземпляра? В комментарии очень сложно показать код, но то, что вы должны изучить, - это то, как '__init__' работает в python и что такое переменные экземпляра и класса. – Granitosaurus

ответ

3

TL; DR: Вы получаете объект с объектами Request внутри него, когда вы должны давать либо Item, либо Request.


Длинная версия:
методы Разбор в вашем паук должен либо возвращать scrapy.Item - в этом случае цепь для этого ползти остановится и SCRAPY будет гасить элемент или scrapy.Requests в этом случае SCRAPY будет запланировать попросите продолжить цепочку.

Scrapy является асинхронным, поэтому, чтобы создать элемент из нескольких запросов, вам нужно связать все эти запросы, неся свой предмет на каждый элемент и постепенно заполняя его. Объект запроса имеет атрибут meta, в котором вы можете хранить все, что хотите (в значительной степени), и оно будет перенесено на вашу функцию обратного вызова. Очень часто использовать его для цепочки запросов для элементов, которые требуют нескольких запросов для формирования одного элемента.

Ваш паук должен выглядеть примерно так:

class ProductSpider(scrapy.Spider): 
    # <...> 
    def parse(self, response): 
     for product in parsed_data: 
      item = Product() 
      item['name'] = product[0] 
      # carry next url you want to crawl in meta 
      # and carry your item in meta 
      yield Request(product[1], self.parse_first, 
          meta={"product3": product[2], "item":item}) 


    def parse_first(self, response): 
     # retrieve your item that you made in parse() func 
     item = response.meta['item'] 
     # fill it up 
     digits = response.css('.price_info .price span').extract() 
     decimals = response.css('.price_info .price .price_demicals').extract() 
     item['first_price'] = float(str(digits)+'.'+str(decimals)) 
     # retrieve next url from meta 
     # carry over your item to the next url 
     yield Request(response.meta['product3'], self.parse_second, 
         meta={"item":item}) 


    def parse_second(self, response): 
     # again, retrieve your item 
     item = response.meta['item'] 
     # fill it up 
     digits = response.css('.lr-prod-pricebox-price .lr-prod-pricebox-price-primary 
           span[itemprop="price"]').extract() 
     item['secodn_price'] = digits 
     # and finally return the item after 3 requests! 
     yield item 
+0

Вы лучшие – AimiHat