Scrapy结合Splash爬取时多产品数据存入单个Item问题求助
解决Scrapy+Splash爬取时所有产品数据存入单个Item的问题
我看了你的代码和网站HTML结构,问题的核心是你没有正确定位到单个产品的节点,而是循环了整个父容器,导致每次创建Item时都从整个页面抓取所有产品的对应数据,最终所有数据都堆在了一个Item里;而用extract_first()时,因为循环只执行一次,所以只会拿到第一个产品的数据。
问题出在这两处:
- 你当前的
product_list是抓取整个<div class="products">容器的HTML字符串(用了extract()),这个容器只有一个,所以循环只会跑一次。 - 提取字段时用的是
response.xpath(),这是基于整个页面的XPath,会把所有产品的对应数据都抓出来,自然就合并到一个Item里了。
修改后的代码
class Spider(CrawlSpider): name = "test" start_urls = ["http://example.com/results"] rules = ( Rule(LinkExtractor(restrict_xpaths=('//div[contains(@class, "products")]')), callback="parse", follow=False), ) def start_requests(self): for url in self.start_urls: yield SplashRequest(url, callback=self.parse, endpoint='render.html', args={'wait':25.5}) def parse(self, response): # 定位到每个独立的产品div节点,注意不要用extract(),保留Selector对象 product_list = response.xpath('//div[contains(@class, "products")]/div[contains(@class, "product")]') # 循环每个产品节点 for product in product_list: item = TestItem() # 用相对XPath(开头加.)从当前产品节点内提取数据 item['CompanyName'] = product.xpath('.//span[@class="product-card__name"]/text()').extract_first(default='') item['Revenue'] = product.xpath('.//span[@class="product-card-revenue-r"]/text()').extract_first(default='').strip() item['Tag'] = product.xpath('.//span[@class="product-card__tagline"]/text()').extract_first(default='') yield item
关键修改点说明:
- 定位单个产品节点:把
product_list的XPath改成//div[contains(@class, "products")]/div[contains(@class, "product")],直接抓取每个产品的<div class="product">节点,并且不要用extract(),这样每个product都是一个Selector对象,保留了节点上下文。 - 使用相对XPath:提取字段时用
product.xpath('.//xxx'),开头的.表示从当前product节点内部开始查找,而不是整个页面,这样就能精准获取单个产品的对应数据。 - 添加default参数:
extract_first(default='')可以避免因为某个字段缺失导致返回None,让数据更规整。
这样修改后,每个产品就会对应一个独立的Item,输出自然就是一行一个产品的数据了。
内容的提问来源于stack exchange,提问作者Alex16237
相关产品推荐
相关产品推荐

