Scrapy объединяет урожай в одном пакете - PullRequest
0 голосов
/ 28 апреля 2019

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

def parse_main_page(self, response):
    dropdown = response.xpath(".//form[@name='somenname']")
    if dropdown:
        options = dropdown.xpath("./select//option")
        for option in options:
            text = option.xpath("./text()").get()
            value = option.xpath("./@value").get()
            url = self.compose_fin_link(value, pkg)
            req= scrapy.Request(url, callback= self.parse_option)
            req.meta['method'] = 'FINSIT'
            req.meta['item'] = pkg
            req.meta['year'] = text
            yield req

def parse_option(self, response):

    pkg = response.meta['item']
    year = response.meta['year']
    pkg[year] = dict()
    main = response.xpath(".//div[@id = 'main']//table//tr")
    for row in main:
        texts = row.xpath(".//font/text()").getall()
        texts = [x.replace('.','') for x in texts]
        if len(texts) > 1:
            pkg[year][texts[0]] = texts[1]
        else:
            pass
    yield pkg

Если у dropdown есть 3 варианта, например, в моем конвейере я получу 3 пакета, каждый из которых даст parse_option. Мне нужно выдать only 1 package containing all three options не 3 пакета для каждого варианта.

За пределами scrapy я бы сделал что-то вроде этого:

def parse_main_page(self, response):
    pkg = dict()
    for option in options:
        pkg[year] = self.parse_option(url)
    yield pkg

def parse_option(self, response):

    ##Do something here
    return option_content

1 Ответ

1 голос
/ 28 апреля 2019

Есть несколько вариантов, как это сделать. Первый состоит в том, чтобы собрать URL-адреса в атрибут meta в методе parse_main_page, а затем в методе parse_option вставлять один URL-адрес за раз и накапливать результаты в другой ключ meta, например. item. Что-то вроде этого:

def parse_main_page(self, response):
    dropdown = response.xpath(".//form[@name='somenname']")
    if dropdown:
        options = []
        for option in dropdown.xpath("./select//option"):
            text = option.xpath("./text()").get()
            value = option.xpath("./@value").get()
            url = self.compose_fin_link(value, pkg)
            options.append({
                'url': url,
                'method': 'FINSIT',
                'item': pkg,
                'year': text
            })
        next_option = options.pop()
        url = next_option.pop('url')
        meta = {
            'data': next_option,
            'options': options,
            'item': {}  # we will collect the data for each individual option to this
        }
        yield scrapy.Request(url, callback=self.parse_option, meta=meta)

def parse_option(self, response):
    # parsing logic ommited as it stays mostly the same
    # ...
    item = response.meta['item']
    current_options = response.meta['data']
    # `current_option` contains `item` and `year` values, use it to populate an intermediate `item` dict
    options = response.meta['options']  # other options that need to get processed
    if options:
        next_option = options.pop()
        url = next_option.pop('url')
        meta = {
            'data': next_option,
            'options': options,
            'item': item  # contains data from all options processed so far
        }
        yield scrapy.Request(url, callback=self.parse_option, meta=meta)
    else:
        # no more options to process, our `item` is finalized
        yield item

Это не проверено, поскольку вы не предоставили всю необходимую информацию, но в принципе должно работать.

Другой вариант - использовать scrapy-inline-запросы , так как извлечение данных из выпадающих URL-адресов является заключительным этапом. Проверьте пример , предоставленный в репо. По сути, в вашем случае вы бы поступили так:

@inline_requests
def parse_main_page(self, response):
    dropdown = response.xpath(".//form[@name='somenname']")
    if dropdown:
        item = {}
        for option in dropdown.xpath("./select//option"):
            text = option.xpath("./text()").get()
            value = option.xpath("./@value").get()
            url = self.compose_fin_link(value, pkg)
            response = yield scrapy.Request(url)
            # ...
            # process the response as in `parse_option` method and collect results in `item`
            # ...
        yield item
...