
本文详解 selenium 网页爬虫中“只保存最后一个数据”的常见错误原因,重点说明作用域缩进问题与定位器误用,并提供结构清晰、可复用的多字典列表构建方案。
本文详解 selenium 网页爬虫中“只保存最后一个数据”的常见错误原因,重点说明作用域缩进问题与定位器误用,并提供结构清晰、可复用的多字典列表构建方案。
在使用 Selenium 抓取网页列表数据(如 Spotify 歌单)时,若最终仅得到一个字典而非完整列表,根本原因通常是代码逻辑作用域错误——尤其是变量定义和 append() 操作未正确置于循环体内。
观察原始代码:
for music in musics:
title = ... # ✅ 在循环内获取每项字段
album = ...
artist = ...
duration = ...
print(title, album, artist, duration)
new_music = { ... } # ❌ 缩进错误:此行不在 for 循环内!
songs.append(new_music) # ❌ 同样在循环外 → 只执行一次,且仅使用最后一次循环的局部变量值由于 new_music = {...} 和 songs.append(...) 缺少缩进,它们实际位于 for 循环之外,因此仅在循环结束后执行一次,此时 title、album 等变量已保留最后一次迭代的值,导致 songs 列表中仅存一个字典。
✅ 正确做法是将字典构建与追加操作严格缩进至循环内部:
from selenium import webdriver
from selenium.webdriver.common.by import By
url = 'https://open.spotify.com/playlist/37i9dQZF1DXbTop77dnX35'
driver = webdriver.Chrome() # 推荐 Chrome;Edge 亦可,需确保驱动匹配
driver.get(url)
# 使用 CSS_SELECTOR 替代错误的 By.CLASS_NAME 多类名拼接
song_elements = driver.find_elements(By.CSS_SELECTOR, ".IjYxRc5luMiDPhKhZVUH.UpiE7J6vPrJIa59qxts4")
songs = [] # 初始化空列表(建议在循环前声明)
for song in song_elements:
try:
title = song.find_element(By.CLASS_NAME, "btE2c3IKaOXZ4VNAb8WQ").text
album = song.find_element(By.CLASS_NAME, "_TH6YAXEzJtzSxhkGSqu").text
# 注意:含空格的 class 名不能用 By.CLASS_NAME —— 改用 CSS_SELECTOR
artist = song.find_element(By.CSS_SELECTOR, ".Text__TextElement-sc-if376j-0.gYdBJW.encore-text-body-small").text
duration = song.find_element(By.CLASS_NAME, "PAqIqZXvse_3h6sDVxU0").text
print(f"✅ {title} — {artist} | {album} | {duration}")
# ✅ 字典创建与追加必须在循环内
new_music = {
'title': title,
'album': album,
'artist': artist,
'duration': duration
}
songs.append(new_music)
except Exception as e:
print(f"⚠️ 解析失败(跳过此项): {e}")
continue
print(f"\n? 共抓取 {len(songs)} 首歌曲")
print(songs)? 关键改进点说明:
- 缩进即作用域:Python 依赖缩进来界定代码块,append() 必须与 for 同级缩进,才能对每次迭代生效;
- 定位器规范性:By.CLASS_NAME 仅接受单一、无空格的 class 名(如 "btn"),不可传入 "a b c" 或含空格的复合类(如 "encore-text- body-small")。原始代码中部分 selector 实际被 Selenium 内部转为 CSS 查询而“侥幸”成功,但属非标准用法,易在更新后失效。应统一改用 By.CSS_SELECTOR 处理多类名、嵌套结构等复杂场景;
- 异常防护:添加 try...except 可避免单条数据解析失败导致整个流程中断;
- 语义清晰命名:将 musics 改为 song_elements,明确其为 WebElement 对象列表,提升可读性。
? 额外建议:
- 页面加载需等待元素就绪,生产环境应配合 WebDriverWait + expected_conditions 使用,避免 find_element 报 NoSuchElementException;
- 关闭浏览器:driver.quit() 应在脚本末尾调用,防止资源泄漏;
- 数据持久化:可进一步用 json.dump(songs, open("spotify_playlist.json", "w")) 导出为 JSON 文件。
遵循以上结构与规范,即可稳定、批量地将网页列表数据转化为结构化字典列表,为后续分析或存储奠定坚实基础。


















