【问题标题】:Python Scrapy - how to call variable from another spider method?Python Scrapy - 如何从另一个蜘蛛方法调用变量?
【发布时间】:2020-09-07 22:48:15
【问题描述】:

所以我尝试学习scrapy,并且为了学习项目,我想抓取这个站点项目名称(仅来自 1 个类别 atm)https://www.killertools.com/Dent-Removal-Aluminum-Steel_c_11.html,然后输入这些项目 url 并获取描述文本。

我已经得到了一些编写 2 个蜘蛛的建议,但我不知道如何从第一个蜘蛛的 parse 方法中的变量中获取数据到第二个蜘蛛以填充 start_urls。

这就是我所在的地方:

import scrapy


class Names(scrapy.Spider):

    name = 'killernames'

    start_urls = ['https://www.killertools.com/Dent-Removal-Aluminum-Steel_c_11.html?viewall=1',]

    def parse(self, response):
        self.detail = response.xpath('//div[contains(@class, "product-item")]/div[@class="name"]/a/@href').getall()

        for item in response.xpath('//div[@class="name"]'):
            yield {
                'name': item.xpath('./a/text()').extract_first(),
                'url': item.xpath('./a/@href').extract_first(),
                 }

class Detail(scrapy.Spider):

    name = 'killerdetail'

    start_urls = []

    for item in self.detail: (I dont know how to get it from first spider)
        url = 'https://www.killertools.com/' + item
        start_urls.append(url)



    def parse(self, response):

        for item in response.xpath('//div[@itemprop="description"]'):
            yield {
                   'detail': item.xpath('./p/strong/text()').extract_first(),
                  }

【问题讨论】:

    标签: scrapy python-3.7


    【解决方案1】:

    您可以使用一个蜘蛛跟踪各个页面的链接,而不是使用两个蜘蛛。首先是关于创建蜘蛛的几点,然后是一些你需要理解的概念才能进行这种类型的抓取。然后是下面的代码示例和解释。

    代码审查

    • 使用get() 而不是extract_first(),它更简洁,总是会给你一个字符串和scrapy docs 建议它
    • 不要混淆使用getall()extract()。有时 extract() 会给你一个列表或字符串,getall() 总是会给你一个列表。
    • 使用项目字典而不是生成字典。特别是在这种数据不干净的情况下。

    需要了解的概念

    项目

    items 字典是scrapy 内部收集数据的方式。如果需要,它允许您稍后更改传入和输出的数据。它比产生字典更灵活。 要开始使用项目,您需要在 items.py 中包含要用作潜在列的字段名称。在这种情况下,名称、URL、描述。

    项目.py

    导入scrapy

    class KillerItem(scrapy.Item):
       
        name = scrapy.Field()
        url = scrapy.Field()
        description = scrapy.Field()
    

    我们正在创建一个 KillerItem 类,它是 scrapy.Item 的子类。我们正在实例化 Field() 对象并将其命名为我们想要作为列生成的名称。

    您还需要包含在您的蜘蛛脚本中

    from ..items import KillerItem
    

    这是一个相对导入,.. 表示 items.py 所在的父目录。 KillerItem 是一个需要实例化以创建项目字典的类。我们通过下面的代码做到这一点。

    items = KillerItem()
    

    它创建了 items 字典,但它具有与我们在 items.py 中创建的字段名称相对应的键。所以我们现在可以用与我们想要的数据对应的值来填充这些键。在这种情况下,名称、URL 和描述。

    items['name] = ...
    

    当我们完成填充项目字典后,我们必须使用yield items。这很重要,因为当我们拥有每个单独页面的名称、URL 和描述时,我们希望产生。

    元参数的使用

    您可以通过 scrapy 请求的元参数在函数之间传输变量。 meta 参数接受一个字典,在这种情况下,我们希望传输我们在 parse 函数中创建的带有名称和 URL 的项目字典。我们想用来自各个页面的描述来填充这个项目字典。我们通过创建一个带有我们选择的键的字典来做到这一点,然后值是我们在实例化 KillerItems 类时定义的项目字典。

    meta= {'items',items}
    

    在下一个函数中访问这个项目字典,即在哪里解析各个页面。我们可以通过响应访问

    items = response.meta['items']
    

    我们与 items 变量保持一致,并通过 meta['items'] 访问该值

    现在解释完了,我们可以进入代码示例。

    代码示例

    import scrapy
    from ..items import KillerItem
    
    class Names(scrapy.Spider):
    
        name = 'killernames'
    
        start_urls = ['https://www.killertools.com/Dent-Removal-Aluminum-Steel_c_11.html?viewall=1']
    
        def parse(self, response):
            
    
            for item in response.xpath('//div[@class="name"]'):
                items = KillerItem()
              
                items['name'] = item.xpath('./a/text()').get()
                items['url'] = 'https://www.killertools.com/' + item.xpath('./a/@href').get()
                
    
                
                yield response.follow(url=items['url'], callback=self.page, meta={'items':items})
               
        def page(self,response):
           
            items = response.meta['items']
            base = response.xpath('//div[@itemprop="description"]')
            if base.xpath('./p/strong/text()') and base.xpath('./p/span/text()'):
                items['description'] = base.xpath('./p/strong/text()').get().replace('\xa0','') + base.xpath('./p/span/text()').get().replace('\xa0','')
            elif base.xpath('./p/strong/text()'):
                items['description'] = base.xpath('./p/strong/text()').get().replace('\xa0','')
            elif base.xpath('./p/span/text()'):
                items['description'] = base.xpath('./p/span/text()').get().replace('\xa0','')
            elif base.xpath('./span/text()'):
                items['description'] = base.xpath('./span/text()').get().replace('\xa0','')
            elif base.xpath('./h3/text()'):
                items['description'] = base.xpath('./h3/text()').get().replace('\xa0','')
            else:
                items['description'] = base.xpath('./text()').get()
            yield items
    

    解释

    解析函数没有太大变化,我们使用您的 xpath 选择器为名称和 URL 创建值。我们填充与我们在 items.py 中创建的字段名称对应的 items 键。

    。我们使用 response.follow 方法,在参数中,我们为 for 循环的每次迭代指定 URL,即 items['url'] 和我们称为 self.page 的回调函数,我们还有 meta 参数创建一个简单的名称项字典和我们创建的项字典的值,以将我们的项字典传输到解析函数。

    在 pages 函数中,我们有相当多的 elif 语句,因为每个页面的描述并不一致,很遗憾。

    最后,我们生成了 items 字典,现在我们有了每个单独页面的描述。

    您并没有真正指定描述要点,但如果需要,您应该有足够的时间去获得额外的日期。

    【讨论】:

    • 你先生是男人中的神!可悲的是,我还没有代表对此进行投票,但是您基本上为我节省了一个多星期的阅读文档的时间,而这些文档我几乎无法理解,因此甚至可能还有 1 周的盲测时间。 4 个月前,我开始在 python 上观看一些终极初学者的东西,比如 print("Hello World!") 级别的东西。仍然有很多概念让我感到困惑,尤其是在后端工作的框架中。因此,通过剖析工作示例对我来说最容易学习。再次感谢!
    • 不客气!您能否在答案左侧将我的答案勾选为已接受的答案?谢谢! Python 很难,但要坚持下去。它确实变得更容易了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多