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
相关产品推荐
相关产品推荐

