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 - 动态创建字段的正确选择器的主要内容,如果未能解决你的问题,请参考以下文章
如何动态创建石墨烯对象?例如,我想在运行时根据配置文件添加字段和解析器