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

Scrapy-Selenium无法抓取商品详情、尺码模块数据如何解决

问题根因

你的代码存在5个直接导致抓取失败的错误:

  • 缩进语法错误:start_requests、parse两个方法没有缩进至ProductsSpider类内部,属于全局函数,Scrapy运行时根本不会调用你写的这部分逻辑,实际执行的是Spider父类的默认方法。
  • 浏览器实例冲突:你在start_requests里手动初始化了独立的Chrome driver,和scrapy-selenium中间件维护的driver是完全隔离的两个实例。你在自己开的driver里做的等待加载、关闭cookie横幅操作,scrapy-selenium发请求用的driver完全感知不到,相当于白做。
  • 等待时长不足:你给详情页SeleniumRequest设置的wait_time=1过短,商品详情表格、尺码选择模块都是延迟加载的动态内容,1秒时间不足以完成渲染。
  • 请求逻辑混乱:你在手动初始化的driver逻辑最后调用了return super().start_requests(),这个方法会默认请求未定义的start_urls,和前面yield的详情页请求混在一起,执行流程完全错乱。
  • 选择器缺失+反爬识别:你在parse方法里写的XPath只覆盖了标题、价格、商品描述三个字段,根本没有编写对应商品详情表格、尺码选择模块的提取规则;另外scrapy-selenium默认的浏览器参数没有做反爬规避,很容易被站点识别为爬虫,返回不完整的渲染结果。

修正方案
  1. 所有类方法保持正确缩进,删掉手动初始化driver、手动调用super().start_requests()的冗余逻辑,所有浏览器操作统一通过scrapy-selenium维护的driver实例处理,不要同时开两套浏览器。
  2. 统一配置Chrome启动参数:设置固定窗口大小、启用新版无头模式、禁用自动化检测特征,避免被站点反爬识别。
  3. 替换固定时长的time.sleep()为显式等待,等目标元素加载完成后再做操作,既保证渲染完成,又不浪费无意义的等待时间。
  4. 补充商品详情表格、尺码选择模块对应的XPath提取规则,等尺码模块加载完成后再提取页面内容。

修正后可运行代码
import scrapy
from scrapy_selenium import SeleniumRequest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

class ProductsSpider(scrapy.Spider):
    name = 'products'
    allowed_domains = ['www.breuninger.com']

    custom_settings = {
        'SELENIUM_DRIVER_NAME': 'chrome',
        'SELENIUM_DRIVER_EXECUTABLE_PATH': ChromeDriverManager().install(),
        'SELENIUM_DRIVER_ARGUMENTS': [
            '--headless=new',
            '--window-size=1920,1080',
            '--disable-blink-features=AutomationControlled',
            '--no-sandbox',
            '--disable-dev-shm-usage'
        ],
        'DOWNLOADER_MIDDLEWARES': {
            'scrapy_selenium.SeleniumMiddleware': 800
        }
    }

    def start_requests(self):
        list_url = "https://www.breuninger.com/de/damen/luxus/bekleidung-jacken-maentel/"
        yield SeleniumRequest(
            url=list_url,
            callback=self.parse_list,
            wait_time=10,
            wait_until=EC.presence_of_element_located((By.XPATH, "//suchen-produktliste[@id='produktliste']//suchen-produkt//a"))
        )

    def parse_list(self, response):
        driver = response.request.meta['driver']
        wait = WebDriverWait(driver, 10)
        
        # 关闭cookie同意横幅
        try:
            banner_btn = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[@class='banner-actions-container']/button")))
            banner_btn.click()
        except:
            pass
        
        # 滚动页面触发商品列表懒加载
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        wait.until(EC.presence_of_all_elements_located((By.XPATH, "//suchen-produktliste[@id='produktliste']/section/div/suchen-produkt/div/a")))
        product_links = response.xpath("//suchen-produktliste[@id='produktliste']/section/div/suchen-produkt/div/a/@href").getall()

        for href in product_links:
            yield SeleniumRequest(
                url=response.urljoin(href),
                callback=self.parse_detail,
                wait_time=15,
                # 显式等待尺码模块加载完成,确保动态区块渲染完毕
                wait_until=EC.presence_of_element_located((By.XPATH, "//div[contains(@class, 'size-selector')]//button"))
            )

    def parse_detail(self, response):
        item = {
            'Bold-title': response.xpath("(//span[@itemprop='name'])[1]/text()").get(),
            'Price': response.xpath("//div[@itemprop='offers']/span/text()").get(),
            'Beschreibung': response.xpath("//div[@class='bewerten-textformat--produktdetails-detail']/div/ul/li/text()").getall()
        }

        # 提取表格形式的商品详情
        detail_table = {}
        table_rows = response.xpath("//div[contains(@class, 'product-attributes')]//tr")
        for row in table_rows:
            key = row.xpath("./th/text()").get(default='').strip()
            value = row.xpath("./td//text()").get(default='').strip()
            if key and value:
                detail_table[key] = value
        item['product_detail_table'] = detail_table

        # 提取尺码选择模块数据
        size_list = []
        size_buttons = response.xpath("//div[contains(@class, 'size-selector')]//button")
        for btn in size_buttons:
            size_val = btn.xpath(".//span[contains(@class, 'size-label')]/text()").get(default='').strip()
            is_available = 'disabled' not in btn.xpath("./@class").get(default='')
            size_list.append({
                'size': size_val,
                'in_stock': is_available
            })
        item['size_selector'] = size_list

        yield item

额外说明
  • 不要混用手动初始化的Selenium driver和scrapy-selenium的内置driver,两套实例的cookie、页面状态完全不互通,是你之前抓取失败的核心原因。
  • Chrome浏览器请使用--headless=new新版无头模式,旧版无头模式极易被电商站点反爬识别,返回不完整内容。
  • 如果页面还有未加载的动态内容,可以在解析前加一段滚动逻辑,触发懒加载元素渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 05:54:25