Scrapy - 动态创建字段的正确选择器

Posted

技术标签:

【中文标题】Scrapy - 动态创建字段的正确选择器【英文标题】:Scrapy - Correct Selector for dynamically created field 【发布时间】:2021-02-25 22:06:18 【问题描述】:

我正在开发网络抓取工具,但在抓取正确的选择器时遇到了麻烦。这是我的代码:

# -*- coding: utf-8 -*-
import scrapy
import pandas as pd
from ..items import HomedepotpricespiderItem
from scrapy.http import Request


class HomedepotspiderSpider(scrapy.Spider):
    name = 'homeDepotSpider'
    allowed_domains = ['homedepot.com']


    



    start_urls = ['https://www.homedepot.com/pep/304660691']#.format(omsID = omsID)
        #for omsID in omsList]

    def parse(self, response):

    #call home depot function
        for item in self.parseHomeDepot(response):
            yield item

        pass

    def parseHomeDepot(self, response):

        #get top level item
        items = response.css('#zone-a-product')
        for product in items:
            item = HomedepotpricespiderItem()

    
    #get the price
            productPrice = product.xpath('//div[@class="price-format__main-price"]/span/text()').getall()

    #get rid of all the stuff i dont need
   
        
            item['productPrice'] = productPrice
            
            yield item

因此,使用我当前的选择器,它看起来像是在获取这些项目的价格。

因为我的输出是:

'productPrice': ['$',
                  '2167',
                  '49',
                  '$',
                  '1798',
                  '00',
                  '$',
                  '2698',
                  '00',
                  '$',
                  '2099',
                  '99',
                  '$',
                  '2968',
                  '00',
                  '$',
                  '2294',
                  '99',
                  '$',
                  '2068',
                  '00',
                  '$',
                  '1649',
                  '99',
                  '$',
                  '2399',
                  '00',
                  '$',
                  '1649',
                  '99',
                  '$',
                  '1549',
                  '99',
                  '$',
                  '1799',
                  '99',
                  '$',
                  '3360',
                  '89',
                  '$',
                  '2899',
                  '95',
                  '$',
                  '3699',
                  '00',
                  '$',
                  '2719',
                  '96',
                  '$',
                  '1954',
                  '99',
                  '$',
                  '2699',
                  '00',
                  '$',
                  '2294',
                  '96',
                  '$',
                  '3149',
                  '00',
                  '$',
                  '3499',
                  '00',
                  '$',
                  '3749',
                  '00',
                  '$',
                  '4999',
                  '00',
                  '$',
                  '2799',
                  '99'],

什么时候正确的输出应该是:2099

此外,我认为我的选择器根本没有抢到商品的价格。

【问题讨论】:

【参考方案1】:

首先,如果您想接收 SINGLE 值,则不需要使用 getall()(改用 get()。您的表达式不起作用的另一个原因是您应该使用 relative 路径(对于您的product 节点):

product.xpath('.//div[@class="price-format__main-price"]/span/text()').getall()

接下来,没有简单的方法可以使用单个 XPath 表达式获得格式正确的价格(事实上,您可以为此使用 concat()),因为价格的整数和小数部分由 spans 分隔。 (对我来说)最简单的方法是获取整个值,然后将其格式化为小数部分:

product_price = response.xpath('normalize-space(//div[@id="zone-a-product"]//div[@class="price"])').re_first(r'\$(.+)')
# product_price is 209999

更新 试试这个 XPath:

response.xpath('normalize-space(//div[@class="price"])').re_first(r'\$(.+)')

【讨论】:

谢谢!该选择器是否为您获得了正确的输出?我的输出是“无” 这样选择器获得了推荐的第一项的价格,但您的回答/解释确实让我走上了正轨【参考方案2】:

首先,您尝试访问的类对于该特定价格标签不是唯一的,其次,即使您的类或 id 是唯一的,您仍然需要使用 extract_first() 或可能 get() ,如另一个答案中提到的提取第一个值。

# "price-detailed__wrapper" is the unique class slightly above price
# there is only one price tag inside this class so i will add another class inside xpath 
# Now '//text()' to get all the text inside all sub tags 

response.xpath('//div[@class="price-detailed__wrapper"]//div[@class="price"]//text()').extract()

#This expath will return a list of strings something like this

['$','2099','99']

#now join the list if 
productPrice = response.xpath('//div[@class="price-detailed__wrapper"]//div[@class="price"]//text()').extract()

productPrice = ''.join(productPrice)

#or if there is too much spaces use strip inside loop

productPrice = ''.join([x.strip() for x in productPrice])

【讨论】:

感谢您的回答!不幸的是,当我运行它时,它正在返回“” 如果我使用 get() 那么它返回 'None'【参考方案3】:
productPrice = product.xpath('//div[@class="priceformat__mainprice"]/span/text()').getall()

在这里,xpath 不是应用于产品,而是应用于整个响应。

在 xpath 中,当我们在 xpath 选择器中搜索时,我们必须在 xpath 之前使用 .,如下所示:.//div[@class="price-format__mainprice"]/span/text()

而且产品的价格不在页面源中,因此它可能是通过另一个请求或 javascript 生成或获取的。那你就不能把它拉出这个页面了;您必须弄清楚如何分别获取和提取该信息。

【讨论】:

以上是关于Scrapy - 动态创建字段的正确选择器的主要内容,如果未能解决你的问题,请参考以下文章

动态表单的jQuery选择器

如何动态创建石墨烯对象?例如,我想在运行时根据配置文件添加字段和解析器

动态创建控件的日期选择器

如何创建年份选择器下拉菜单

单选按钮在动态创建的 RadioGroup 中没有正确选择/取消选择

从 json 动态创建的 Javascript 表单输入,需要将对象映射到另一个对象的正确字段并保存