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

Scrapy CSS选择器异常:同选择器在Selenium可用但爬虫返回空列表

Scrapy直接爬取返回空结果,Selenium却能成功的原因及解决办法

核心原因

  • 目标内容由JavaScript动态渲染:Scrapy直接请求URL时,只会获取服务器返回的原始HTML,而#four-factors下的链接是页面加载后通过JS动态生成并插入DOM的。Scrapy本身不具备执行JavaScript的能力,所以原始HTML里根本没有这部分元素,自然爬取不到。
  • Selenium是模拟真实浏览器环境,会自动执行页面中的JS代码,等待内容加载完成后再获取页面源码,因此能拿到渲染后的完整DOM结构。

解决办法

1. 使用Scrapy-Splash渲染JS

Splash是专门用于渲染JavaScript的服务,能让Scrapy获取到JS执行后的页面内容:

  • 先安装依赖:pip install scrapy-splash
  • 启动Splash服务(推荐用Docker):docker run -p 8050:8050 scrapinghub/splash
  • 在Scrapy项目的settings.py中配置Splash:
SPLASH_URL = 'http://localhost:8050'
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
  • 修改爬虫代码,用SplashRequest替代默认的Request:
from scrapy_splash import SplashRequest

class CBBSpider(scrapy.Spider):
    name = "cbb_spider"
    start_urls = ['https://www.sports-reference.com/cbb/boxscores/2023-03-23-21-tennessee.html']
    
    def start_requests(self):
        for url in self.start_urls:
            # wait参数指定等待JS加载的时间(秒)
            yield SplashRequest(url, self.parse, args={'wait': 2})
    
    def parse(self, response):
        teams_lst_raw = response.css('#four-factors a::attr(href)').getall()
        print(teams_lst_raw)

2. 在Scrapy中集成Selenium

直接把Selenium的逻辑整合到爬虫里,模拟浏览器加载页面:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from scrapy.http import HtmlResponse

class CBBSpider(scrapy.Spider):
    name = "cbb_spider"
    start_urls = ['https://www.sports-reference.com/cbb/boxscores/2023-03-23-21-tennessee.html']
    
    def __init__(self):
        # 配置无头浏览器,避免弹出窗口
        chrome_options = Options()
        chrome_options.add_argument('--headless=new')
        self.driver = webdriver.Chrome(options=chrome_options)
    
    def parse(self, response):
        self.driver.get(response.url)
        # 可选:等待目标元素加载完成
        # from selenium.webdriver.support.ui import WebDriverWait
        # from selenium.webdriver.common.by import By
        # from selenium.webdriver.support import expected_conditions as EC
        # WebDriverWait(self.driver, 10).until(EC.presence_of_element_located((By.ID, 'four-factors')))
        
        # 将Selenium获取的源码转为Scrapy Response
        html_source = self.driver.page_source
        scrapy_response = HtmlResponse(url=self.driver.current_url, body=html_source, encoding='utf-8')
        teams_lst_raw = scrapy_response.css('#four-factors a::attr(href)').getall()
        print(teams_lst_raw)
    
    def closed(self, reason):
        # 爬虫结束后关闭浏览器
        self.driver.quit()

3. 直接请求后端API

打开浏览器开发者工具的「Network」面板,筛选XHR请求,找到页面加载时获取four-factors数据的API接口。直接请求该接口拿到结构化数据,这种方式不需要渲染页面,效率更高,是最优解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:53:12