Python 爬虫 | 抓取油管频道所有视频标题(Selenium 方法)

162 阅读4分钟

最近在学习新领域,想分析油管频道的视频,就想到写 Python 爬虫。目前我只爬取所有视频的标题。

实现方式:不用 RSS、官方 API 或 yt-dlp,直接从网页 HTML 获取视频标题并生成 CSV。

  • 基于 RSSHub 爬取更简单,但 RSS 只返回 50 个结果,不够用。
  • 官方 API 比较麻烦,这次使用量较小,不打算用。
  • yt-dlp 网上推荐很多,我尝试后发现不太适合我这次的需求,后续需要再学习。

爬虫实现相对容易是因为油管平台开放包容,反爬力度较小。正如油管对 RSS 一直很友好,感谢油管平台以及优秀内容创作者!我这里展示的脚本仅用于个人学习和技术交流,非商业目的。

背景与使用场景

在分析一个频道时,可能希望快速获取所有视频的标题,例如:

  • 做内容统计或主题分析
  • 构建视频列表、生成数据 CSV
  • 快速了解某个创作者的输出风格

油管视频页面截图.png (以小 lin 说频道为例)

可行方案 — Selenium 模拟浏览器

Selenium 是 Python 中常用的浏览器自动化工具,可以模拟用户操作,适合抓取需要滚动加载的网页内容。

pip install selenium

实现步骤

  1. 打开频道视频页
  2. 模拟滚动到底部,加载所有视频
  3. 获取页面标题
  4. 保存为 CSV

思路:

  • ytd-grid-video-renderer 已更新为 ytd-rich-grid-media,兼容 2025 年最新布局
  • 视频需要滚动并等待 DOM 渲染,等待时间延长到 15 秒
  • 滚动加载全部视频
  • CSV 使用 UTF-8 BOM 保存,中文不会乱码
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import csv
import time

channel_id = "xiao_lin_shuo" # 设置频道名称
channel_url = f"https://www.youtube.com/@{channel_id}/videos"
output_file = "youtube_titles.csv"

options = Options()
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--log-level=3")
driver = webdriver.Chrome(options=options)

driver.get(channel_url)

# 等待至少一个视频加载出来
wait = WebDriverWait(driver, 15)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "ytd-rich-grid-media")))

# 滚动到底部,加载所有视频
last_height = driver.execute_script("return document.documentElement.scrollHeight")
while True:
    driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);")
    time.sleep(2)  # 等待新视频加载
    new_height = driver.execute_script("return document.documentElement.scrollHeight")
    if new_height == last_height:
        break
    last_height = new_height

# 获取视频标题
titles_elements = driver.find_elements(By.CSS_SELECTOR, "ytd-rich-grid-media #video-title")
titles = [t.text.strip() for t in titles_elements if t.text.strip()]

# 保存 CSV(UTF-8 BOM 避免中文乱码)
with open(output_file, "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["Title"])
    for t in titles:
        writer.writerow([t])

print(f"共抓取 {len(titles)} 个视频标题,已保存到 {output_file}")
driver.quit()

运行输出

共抓取 141 个视频标题,已保存到 youtube_titles.csv

期间遇到的问题

分享一些实践经验:

  • 基于 RSSHub 爬取只能返回前 50 个,不容易扩展修改,因此直接换方法
  • yt-dlp 在解析视频流时不断输出警告(SABR streaming、ffmpeg 未安装),而我们只想抓标题,不下载视频
  • 只用简单 requests 方法,翻页请求返回 410 Gone,因为 YouTube 已废弃 /browse_ajax 接口,旧方法无法继续获取 continuation token
  • 现在唯一可行的方法是模拟浏览器行为加载完整页面,因此选择了 Selenium 版本

附加 RSSHub 方法

虽然 RSSHub 方法只能返回最新的 50 个结果,但实现简单,也分享给大家:

import csv
import requests
import xml.etree.ElementTree as ET

channel_id = "xiao_lin_shuo"  # 设置频道名
rss_url = f"https://rsshub.app/youtube/user/@{channel_id}"
output_file = "youtube_titles.csv"

# 获取 RSS 数据
response = requests.get(rss_url)
response.raise_for_status()

# 解析 XML
root = ET.fromstring(response.content)

# 提取视频标题
titles = [item.find("title").text for item in root.findall(".//item") if item.find("title") is not None]

# 写入 CSV
with open(output_file, "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerow(["Title"])
    for title in titles:
        writer.writerow([title])

print(f"✅ 已保存 {len(titles)} 个视频标题到 {output_file}")

运行输出

✅ 已保存 50 个视频标题到 youtube_titles.csv


这次的 Selenium 实现版本只是刚好够用,还有许多改进空间,比如没有异步加速、爬取中没有计时输出、只爬取视频标题等等。之后有需要再改进。

最后再次感谢油管平台以及优秀内容创作者,在越来越封闭的网络生态下仍坚持互联互通!

接下来,我会分享更多帮助个人学习工作的轻量级脚本工具