相同项目但有多个URL

时间:2019-03-19 15:27:15

标签: python-3.x scrapy

class MySiteSpider(scrapy.Spider):
    name = 'MySite'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/']

    def parse(self, response):
        links = LinkExtractor(unique=True).extract_links(response)
        for link in links:
            yield response.follow(link, callback=self.parse)
            pass

        if response.css('.product-page-content'):
            id_ = response.css('#id::text').extract_first()
            item = MyItem()
            item['id'] = id
            item['urls'] = [response.url]
            # Sorting some data
            yield item

问题是,有时我得到的页面具有不同的url但具有相同的id_,在这种情况下,我需要将此新url添加到具有旧id_ /的旧项目中喜欢:

if response.css('.product-page-content'):
    id_ = response.css('#id::text').extract_first()
    if this_id_already_processed:
        old_item['url'].append(response.url)
    else
        item = MyItem()
        item['id'] = id
        item['urls'] = [response.url]
        # Sorting some data
        yield item

2 个答案:

答案 0 :(得分:3)

有趣的情况。有几种方法可以做到,但这种情况下的主要障碍是记忆。

当scrapy产生一个项目时,它将其导出到您具有的任何输出(stdout,json,csv等),然后就完成了。 如果您希望通过这种方式合并项目,则需要对输出进行后处理或将所有内容保存到内存中。

  1. 后处理输出
    如果您在output.csv中有文件,则可以简单地对结果运行脚本以加入您的项目。看到spider_closed信号-蜘蛛关闭时打开ouput.json并调整内容

  2. 管道
    通过这种方法,您可以将所有项目存储在内存中,并在爬网程序运行时对其进行处理:

    import json
    class MyPipeline:
        items = {}
    
        def process_item(self, item):
            if item['id'] in self.items:
                self.items['id']['urls'].append(item['url'])
            else:
                self.items[item['id']] = item
            return item
    
        close_spider(self, spider):
            with open('output.json') as f:
                f.write(json.dumps(self.items))
    
  3. 饲料出口商
    这几乎与管道方法相同-在导出之前将项目保存到内存中

如果您的Spider很小,请选择#2,否则,#1是一种内存效率更高,更清洁的方法。

答案 1 :(得分:-1)

由于Scrapy的工作原理,因此无法以简单的方式执行此操作。它异步处理请求,一个接一个地产生项目,它本身不维护任何历史记录。您可以做的是在蜘蛛网中使用一些项目缓冲区,并在抓取结束时使用signals转储所有项目。

请参见以下虚拟示例:

import json
import scrapy
from scrapy import signals


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    start_urls = ['http://quotes.toscrape.com/page/1/']
    items = []

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = super(QuotesSpider, cls).from_crawler(crawler, *args, **kwargs)
        crawler.signals.connect(spider.spider_closed, signal=signals.spider_closed)
        return spider

    def parse(self, response):
        for quote in response.xpath('//div[@class="quote"]'):
            item = {
                'text': quote.xpath('normalize-space(./span[@class="text"])').extract_first()
            }
            self.items.append(item)

    def spider_closed(self, spider):
        with open('items.json', 'wt') as f:
            json.dump(self.items, f)