【问题标题】:How to use "if" to handle with two xpath or more?如何使用“if”来处理两个或更多的xpath?
【发布时间】:2021-03-13 23:58:04
【问题描述】:

我正在通过下面的代码使用 python 训练网页抓取。

但是其中一个数据有两个 xpath,我想知道是否有一种方法可以使用“if”条件捕获两者,但我不知道如何将其插入到我的代码中。谁能指导我?

例如,如果其中一个 xpath 为 null,那么它肯定是另一个。不知道解释得好不好,但是如果我有a和b,如果a为null则b。

'vlr_atual'可以分别为:

product.xpath(".//span[@id='priceblock_ourprice']/text()").get()

product.xpath(".//span[@id='priceblock_saleprice']/text()").get()

https://www.amazon.com.br/Monitor-LG-19-5-LED-Inclina%C3%A7%C3%A3o/dp/B084TKF88Q/ref=sr_1_1?dchild=1&qid=1615682905&s=computers&sr=1-1

https://www.amazon.com.br/Monitor-Gamer-Dell-S2421HGF-23-8/dp/B086M269P3/ref=sr_1_19?dchild=1&qid=1615682905&s=computers&sr=1-19

import scrapy
import datetime

class ProductsSpider(scrapy.Spider):
    name = 'products'
    allowed_domains = ['www.amazon.com.br']
    start_urls = ['https://www.amazon.com.br/s?i=computers&bbn=16339926011&rh=n%3A16364756011&fs=true&qid=1615634908&ref=sr_pg_1']
    

    def parse(self, response):

        for produto in response.xpath("//div[@class='a-section a-spacing-medium']"):
            
            selo = produto.xpath(".//span[@class='a-badge-text']/text()").get()
            link = response.urljoin(produto.xpath(".//h2/a/@href").get())

            yield response.follow(url=link, callback=self.parse_details, meta={'selo' : selo})

        next_page = response.urljoin(response.xpath("//li[@class='a-last']/a/@href").get())
 
        if next_page:
            yield scrapy.Request(url=next_page, callback=self.parse)

    def parse_details(self, response):
        selo = response.request.meta['selo']
        for produto in response.xpath("//div[@id='dp']"):
            
            vlr_atual = produto.xpath(".//span[@id='priceblock_ourprice']/text()").get()
            if vlr_atual is None:
                 vlr_atual = produto.xpath(".//span[@id='priceblock_saleprice']/text()").get()
            yield{
                'data' : datetime.datetime.now().strftime("%Y%m%d"),
                'selo': selo,
                'nome': produto.xpath("normalize-space(.//span[@id='productTitle']/text())").get(),
                'vlr_atual': vlr_atual,
                'estoque': produto.xpath("normalize-space(.//select[@name='quantity']/option[last()]/text())").get(),
                'ean': produto.xpath("normalize-space(.//table[@id='productDetails_techSpec_section_1']//tr[last()]/td/text())").get(),
            } 

【问题讨论】:

  • 你卡在哪里了?您需要 (1) 获取一条路径; (2) 检查是否为空; (3) 如果没有,使用该路径; (4) 如果是,则使用其他。这些都是微不足道的一步,不是吗?
  • @Prune 我被卡住了,因为有些产品使用第一个 xpath,有些使用我在问题中提出的第二个 xpath。今天我放了第一个xpath,很多产品都出来了。当我去查看它时,我意识到这是使用第二个 xpath 的产品。所以我想要一种设置条件的方法,如果第一个为空,我得到第二个。
  • 那么如何判断第一个路径是否为空呢?
  • @Prune 我放了完整的代码,也许会更清楚。每页有几种产品,我访问每个产品的链接,但有时 xpath 的价格会有所不同。我是通过运行代码发现的。

标签: python web-scraping xpath scrapy


【解决方案1】:

来点非常简单的东西怎么样:

    def parse_details(self, response):
        selo = response.request.meta['selo']
        for produto in response.xpath("//div[@id='dp']"):

            # determine which field is vlr_atual
            ourprice = produto.xpath(".//span[@id='priceblock_ourprice']/text()").get()
            saleprice = produto.xpath(".//span[@id='priceblock_saleprice']/text()").get()
            if ourprice is not None:
                 vlr_atual = ourprice
            else:
                 vlr_atual = saleprice 

            yield {
                'data': datetime.datetime.now().strftime("%Y%m%d"),
                'selo': selo,
                'nome': produto.xpath("normalize-space(.//span[@id='productTitle']/text())").get(),
                'vlr_atual': vlr_atual,
                'estoque': produto.xpath("normalize-space(.//select[@name='quantity']/option[last()]/text())").get(),
                'ean': produto.xpath("normalize-space(.//table[@id='productDetails_techSpec_section_1']//tr[last()]/td/text())").get(),
            }

【讨论】:

  • 嗨,我根据您所说的进行了尝试,但没有得到我想要的答案,有些人一直为空,但还是谢谢
  • @LucasGuidi 对于某些响应,“ourprice”和“saleprice”听起来可能都丢失了?也许您可以在 for 循环中添加另一个条件,如果“ourprice”和“saleprice”都是None - 打印整个响应并调查数据。我不能这样做,因为我不熟悉 scrapy 并且不知道应该如何运行此类 - 也许您可以将缺少的代码/命令添加到问题中?
【解决方案2】:

您可以使用or operator 在两件事之间进行选择,同时偏好第一件事

>>> a="www.example.com"
>>> b="www.example2.com"
>>> a or b
'www.example.com'
>>> a=None
>>> a or b
'www.example2.com'
>>> 

这项工作的方式是,如果a"truth" 值为true,则a or b 返回a,否则返回b

这样你就可以了

product.xpath (".//span[@id='priceblock_ourprice']/text()").get() or product.xpath (".//span[@id='priceblock_saleprice']/text()").get()

编辑

你也可以把它封装成它自己的函数,像这样

def get_vlr_atual(product, default=None):
    lst_xpaths = [".//span[@id='priceblock_ourprice']/text()",
                 ".//span[@id='priceblock_saleprice']/text()"   
                ]
    for path in lst_paths:
        result = product.xpath(path).get()
        if result is not None:
            return result
    return default

这与以前基本相同,但可以轻松扩展为任意数量的 xpath,如果所有这些都失败,则返回一些方便的默认值

和简单的使用一样

...
{...
  'vlr_atual': get_vlr_atual(product),
 ...
 }
...

【讨论】:

  • 你好,谢谢你的回复,但是对我来说有点高级,我不明白我如何将它添加到代码中,你能帮我吗?
  • @LucasGuidi 你有什么困惑?这 ”...”?这些代表您的示例代码中的所有其他内容,为简洁起见,我省略了,它基本上意味着搜索您在字典中为“vlr_atual”创建该条目的位置,并将函数调用get_vlr_atual(product)的结果分配给它,并表示函数你把它放在你的代码中合适的地方
【解决方案3】:

我强烈建议您使用Item Loaders。您将能够在一个地方自动更新选定的字段。取第一个非空白值,加入几个结果等。 首先在 items.py 中使用TakeFirst 处理器定义您的Product

class ProductItem(scrapy.Item):
    
    data= scrapy.Field()
    selo = scrapy.Field()
    vlr_atual= scrapy.Field(output_processor=TakeFirst())

接下来在你的蜘蛛中使用它:

from scrapy.loader import ItemLoader
....

for produto in response.xpath("//div[@id='dp']"):
    l = ItemLoader(item=ProductItem(), selector=produto)
    l.add_value('data', datetime.datetime.now().strftime("%Y%m%d"))
    l.add_xpath("vlr_atual", ".//span[@id='priceblock_ourprice']/text()")
    l.add_xpath("vlr_atual", ".//span[@id='priceblock_saleprice']/text()")
    ...
    l.load_item()

【讨论】:

    猜你喜欢
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 2012-09-14
    • 2016-08-31
    • 1970-01-01
    • 2015-08-21
    相关资源
    最近更新 更多