问题描述
因此,我试图学习scrapy和用于学习项目,我想从此站点项目名称(仅从1个类别的atm中)https://www.killertools.com/Dent-Removal-Aluminum-Steel_c_11.html进行爬行,然后输入这些项目的网址并获取描述文字。
我已经有了写2个Spider的建议,但是我不知道如何在解析方法中从变量中获取数据,从第一个Spider到第二个Spider来填充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(),}
解决方法
您可以使用一个蜘蛛将链接转到各个页面,而不是使用两个蜘蛛。首先介绍创建蜘蛛的几点,然后介绍一些需要了解的概念才能进行这种抓取。然后是下面的代码示例和说明。
代码查看
- 使用
get()
代替extract_first()
更为简洁,它将始终为您提供一个字符串,而且草率的文档建议使用 - 不要混淆使用
getall()
和extract()
。有时候extract()会给您一个列表或字符串,getall()
总是会给您一个列表。 - 使用项字典而不是产生字典。尤其是在数据不干净的情况下。
要了解的概念
项目
项字典是scrapy收集数据的惯用方式。它允许您更改传入的数据并在需要时稍后输出。它比产生字典更灵活。 要开始使用项目,您需要在想要用作潜在列的items.py中包括字段名称。在这种情况下,名称,URL,描述。
items.py
进口沙皮
class KillerItem(scrapy.Item):
name = scrapy.Field()
url = scrapy.Field()
description = scrapy.Field()
我们正在创建一个KillerItem类,该类将scrapy.Item子类化。我们正在实例化Field()对象,并将其命名为我们要作为列产生的名称。
您还需要在蜘蛛脚本中添加
from ..items import KillerItem
这是一个相对导入,..表示上级目录,item.py位于其中。 KillerItem是需要实例化以创建项目字典的类。我们通过下面的代码来做到这一点。
items = KillerItem()
哪个创建了item字典,但是它具有与我们在items.py中创建的字段名称相对应的键。因此,我们现在可以使用与所需数据相对应的值来填充这些键。在这种情况下,请输入名称,URL和说明。
items['name] = ...
完成项目字典的填充后,我们必须使用yield items
。这一点很重要,因为当我们拥有每个页面的名称,URL和描述时,我们要屈服。
使用元参数
您可以通过scrapy请求的meta参数在函数之间传递变量。 meta参数接受一个字典,在这种情况下,我们要转移在解析函数中使用名称和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,该URL为items ['url'],我们将其称为self.page
的回调函数,我们还使用了meta参数它创建了一个简单的名称项字典,并创建了我们的项字典的值,以将项字典转移到解析函数。
不幸的是,在pages函数中,我们有很多elif语句,因为每个页面的描述不一致。
最后,我们得到了item字典,现在我们有了每个页面的描述。
您实际上并没有指定说明的要点,但是如果需要,您应该有足够的时间获得额外的日期。