Подтвердить что ты не робот

Как я могу использовать несколько запросов и передавать элементы между ними в scrapy python

У меня есть объект item, и мне нужно передать это на многих страницах для хранения данных в одном элементе

LIke мой элемент

class DmozItem(Item):
    title = Field()
    description1 = Field()
    description2 = Field()
    description3 = Field()

Теперь эти три описания находятся на трех отдельных страницах. я хочу сделать что-то вроде

Теперь это работает хорошо для parseDescription1

def page_parser(self, response):
    sites = hxs.select('//div[@class="row"]')
    items = []
    request =  Request("http://www.example.com/lin1.cpp",  callback =self.parseDescription1)
    request.meta['item'] = item
    return request 

def parseDescription1(self,response):
    item = response.meta['item']
    item['desc1'] = "test"
    return item

Но я хочу что-то вроде

def page_parser(self, response):
    sites = hxs.select('//div[@class="row"]')
    items = []
    request =  Request("http://www.example.com/lin1.cpp",  callback =self.parseDescription1)
    request.meta['item'] = item

    request =  Request("http://www.example.com/lin1.cpp",  callback =self.parseDescription2)
    request.meta['item'] = item

    request =  Request("http://www.example.com/lin1.cpp",  callback =self.parseDescription2)
    request.meta['item'] = item

    return request 

def parseDescription1(self,response):
    item = response.meta['item']
    item['desc1'] = "test"
    return item

def parseDescription2(self,response):
    item = response.meta['item']
    item['desc2'] = "test2"
    return item

def parseDescription3(self,response):
    item = response.meta['item']
    item['desc3'] = "test3"
    return item
4b9b3361

Ответ 1

Нет проблем. Ниже приведена правильная версия вашего кода:

def page_parser(self, response):
      sites = hxs.select('//div[@class="row"]')
      items = []

      request = Request("http://www.example.com/lin1.cpp", callback=self.parseDescription1)
      request.meta['item'] = item
      yield request

      request = Request("http://www.example.com/lin1.cpp", callback=self.parseDescription2, meta={'item': item})
      yield request

      yield Request("http://www.example.com/lin1.cpp", callback=self.parseDescription3, meta={'item': item})

def parseDescription1(self,response):
            item = response.meta['item']
            item['desc1'] = "test"
            return item

def parseDescription2(self,response):
            item = response.meta['item']
            item['desc2'] = "test2"
            return item

def parseDescription3(self,response):
            item = response.meta['item']
            item['desc3'] = "test3"
            return item

Ответ 2

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

  def page_parser(self, response):
        sites = hxs.select('//div[@class="row"]')
        items = []

        request = Request("http://www.example.com/lin1.cpp", callback=self.parseDescription1)
        request.meta['item'] = Item()
        return [request]


  def parseDescription1(self,response):
        item = response.meta['item']
        item['desc1'] = "test"
        return [Request("http://www.example.com/lin2.cpp", callback=self.parseDescription2, meta={'item': item})]


  def parseDescription2(self,response):
        item = response.meta['item']
        item['desc2'] = "test2"
        return [Request("http://www.example.com/lin3.cpp", callback=self.parseDescription3, meta={'item': item})]

  def parseDescription3(self,response):
        item = response.meta['item']
        item['desc3'] = "test3"
        return [item]

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

Если вы вернете элемент из каждого из обратных вызовов, в конечном итоге вы получите 4 элемента в разных состояниях полноты в конвейере, но если вы вернете следующий запрос, то вы можете гарантировать порядок запросов и что вы будет иметь ровно один элемент в конце выполнения.

Ответ 3

Принятый ответ возвращает всего три элемента [с desc (i), установленным для я = 1,2,3].

Если вы хотите вернуть один элемент, элемент Dave McLain действительно работает, однако для его возврата требуется parseDescription1, parseDescription2 и parseDescription3 для выполнения и без ошибок.

В моем случае использования некоторые из подзапросов МОГУТ возвращать ошибки HTTP 403/404 в случайном порядке, таким образом, я потерял некоторые элементы, хотя я мог бы частично их очистить.


Обход

Таким образом, в настоящее время я использую следующее обходное решение: вместо того, чтобы передавать объект только в request.meta dict, обходите стек вызовов, который знает, какой запрос называть следующий. Он выведет следующий элемент в стеке (пока он не будет пустым) и вернет элемент, если стек пуст.

Параметр запроса errback используется для возврата к методу диспетчера при ошибках и просто продолжения с последующим элементом стека.

def callnext(self, response):
    ''' Call next target for the item loader, or yields it if completed. '''

    # Get the meta object from the request, as the response
    # does not contain it.
    meta = response.request.meta

    # Items remaining in the stack? Execute them
    if len(meta['callstack']) > 0:
        target = meta['callstack'].pop(0)
        yield Request(target['url'], meta=meta, callback=target['callback'], errback=self.callnext)
    else:
        yield meta['loader'].load_item()

def parseDescription1(self, response):

    # Recover item(loader)
    l = response.meta['loader']

    # Use just as before
    l.add_css(...)

    # Build the call stack
    callstack = [
        {'url': "http://www.example.com/lin2.cpp",
        'callback': self.parseDescription2 },
        {'url': "http://www.example.com/lin3.cpp",
        'callback': self.parseDescription3 }
    ]

    return self.callnext(response)

def parseDescription2(self, response):

    # Recover item(loader)
    l = response.meta['loader']

    # Use just as before
    l.add_css(...)

    return self.callnext(response)


def parseDescription3(self, response):

    # ...

    return self.callnext(response)

Предупреждение

Это решение по-прежнему синхронно и будет по-прежнему терпеть неудачу, если у вас есть исключения в обратных вызовах.

Для получения дополнительной информации проверьте сообщение в блоге, которое я написал об этом решении.