You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy中Xpath获取元素无法逐条输出Item问题求助

Scrapy实现单商品对应独立Item的问题修复

问题描述

从特定EC站点提取展商订单数据,已将订单结果页URL存入CSV并在start_requests中遍历请求。每个页面含30个商品信息,尝试用XPath定位后通过ItemLoader存入Item并yield,但当前输出的每个Item包含多条商品数据,期望每个商品对应一个独立Item。

原代码:

class AllSaledataSpider(CrawlSpider):
    name = 'all_salesdata_copy2'
    allowed_domains = ['www.buyma.com']

    def start_requests(self):
         with open('/Users/morni/researchtool/AllshoppersURL.csv', 'r', encoding='utf-8-sig') as f:
            reader = csv.reader(f)
            for row in reader:
                for n in range(1, 300): 
                    url = str((row[2])[:-5]+'/sales_'+str(n)+'.html')
                    yield scrapy.Request(
                        url=url,
                        callback=self.parse_firstpage_item,
                        dont_filter=True
                        )

    def parse_firstpage_item(self, response): 
            loader = ItemLoader(item = ResearchtoolItem(), response = response)

            Conversion_date = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[3]/text()').getall()
            product_name = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[1]/a/text()').getall()
            product_URL = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[1]/a/@href').getall()

            for i in range(30):
                loader.add_value("Conversion_date", Conversion_date[i])
                loader.add_value("product_name", product_name[i])
                loader.add_value("product_URL", product_URL[i])
               
                yield loader.load_item()

当前输出:

{"product_name": ["product1", "product2"], "Conversion_date":["Conversion_date1", "Conversion_date2" ], "product_URL":["product_URL1", "product_URL2"]}

理想输出:

[{"product_name": "product1", "Conversion_date": "Conversion_date1", "product_URL": "product_URL1"},{"product_name": "product2", "Conversion_date": "Conversion_date2", "product_URL": "product_URL2"}]

问题原因

ItemLoader实例在for循环外初始化,每次循环调用add_value时,会往同一个Item对象里追加数据,而非创建新的Item。因此每次yield的Item都是累积了之前所有商品的信息。

修复方案

将ItemLoader的创建移至for循环内部,确保每次循环都生成新的loader实例,对应单个商品的Item:

class AllSaledataSpider(CrawlSpider):
    name = 'all_salesdata_copy2'
    allowed_domains = ['www.buyma.com']

    def start_requests(self):
         with open('/Users/morni/researchtool/AllshoppersURL.csv', 'r', encoding='utf-8-sig') as f:
            reader = csv.reader(f)
            for row in reader:
                for n in range(1, 300): 
                    url = str((row[2])[:-5]+'/sales_'+str(n)+'.html')
                    yield scrapy.Request(
                        url=url,
                        callback=self.parse_firstpage_item,
                        dont_filter=True
                        )

    def parse_firstpage_item(self, response): 
            Conversion_date = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[3]/text()').getall()
            product_name = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[1]/a/text()').getall()
            product_URL = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]/p[1]/a/@href').getall()

            for i in range(30):
                # 每次循环创建新的ItemLoader实例
                loader = ItemLoader(item = ResearchtoolItem(), response = response)
                loader.add_value("Conversion_date", Conversion_date[i])
                loader.add_value("product_name", product_name[i])
                loader.add_value("product_URL", product_URL[i])
               
                yield loader.load_item()

额外优化建议

  • 不要硬编码range(30),可以通过len(Conversion_date)动态获取商品数量,避免页面商品数不足30时出现索引错误:
    for i in range(len(Conversion_date)):
    
  • 直接遍历商品节点更健壮(避免XPath定位的列表长度不一致问题):
    def parse_firstpage_item(self, response): 
        # 先定位每个商品的根节点
        product_nodes = response.xpath('//*[@id="buyeritemtable"]/div/ul/li[2]')
        for node in product_nodes:
            loader = ItemLoader(item = ResearchtoolItem(), selector=node)
            loader.add_xpath("Conversion_date", './p[3]/text()')
            loader.add_xpath("product_name", './p[1]/a/text()')
            loader.add_xpath("product_URL", './p[1]/a/@href')
            yield loader.load_item()
    

这种方式直接针对每个商品节点提取数据,无需手动处理索引,可靠性更高。

内容的提问来源于stack exchange,提问作者K_MM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 04:35:36