Selenium爬取YouTube频道:滚动、去重及精确日期提取问题
解决Selenium爬取YouTube频道视频的三大问题:滚动加载、去重、精确日期提取
一、修复滚动加载停滞(仅加载30个视频)
YouTube视频列表采用动态懒加载机制,单纯滚动到底部可能无法触发后续加载,可通过以下方法解决:
- 循环滚动+显式等待:每次滚动至当前页面底部后,等待新视频元素加载完成,避免固定sleep带来的不稳定。示例代码:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By last_height = driver.execute_script("return document.documentElement.scrollHeight") video_count = 0 while True: # 滚动至页面底部 driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight);") # 等待新视频加载(最多10秒) WebDriverWait(driver, 10).until( lambda d: len(d.find_elements(By.ID, "video-title")) > video_count ) video_count = len(driver.find_elements(By.ID, "video-title")) # 检查是否已加载全部内容(连续2次滚动后数量不变则停止) new_height = driver.execute_script("return document.documentElement.scrollHeight") if new_height == last_height: break last_height = new_height - 处理"加载更多"按钮:部分频道会显示"加载更多"按钮而非自动滚动加载,需判断按钮是否存在并点击:
try: load_more_btn = WebDriverWait(driver, 5).until( EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), '加载更多')]")) ) load_more_btn.click() except: pass # 无按钮则继续滚动逻辑
二、消除重复数据
重复数据源于滚动时重复抓取已加载元素,核心思路是通过唯一标识去重:
- 用视频ID做去重标识:每个YouTube视频都有唯一ID,可从元素的
data-video-id属性提取,维护集合存储已抓取ID:processed_video_ids = set() videos = [] for video_element in driver.find_elements(By.XPATH, "//ytd-grid-video-renderer"): video_id = video_element.get_attribute("data-video-id") if video_id not in processed_video_ids: processed_video_ids.add(video_id) # 提取其他信息 video_title = video_element.find_element(By.ID, "video-title").text video_url = video_element.find_element(By.ID, "video-title").get_attribute("href") videos.append({"id": video_id, "title": video_title, "url": video_url}) - 增量抓取新元素:每次滚动后,只抓取新增的视频元素,避免重复遍历全部列表:
prev_count = 0 while True: # 滚动后等待加载 current_videos = driver.find_elements(By.XPATH, "//ytd-grid-video-renderer") new_videos = current_videos[prev_count:] # 处理new_videos... prev_count = len(current_videos) # 判断是否停止滚动...
三、提取精确发布日期
主页显示的是相对日期(如"3个月前"),精确日期需进入视频详情页提取:
- 进入详情页提取日期:可直接读取页面元数据(无需展开描述),或展开描述后提取文本日期:
from datetime import datetime def get_precise_date(video_url): # 在新窗口打开详情页 driver.execute_script("window.open(arguments[0]);", video_url) driver.switch_to.window(driver.window_handles[1]) # 方法1:读取页面元数据(高效无需交互) date_str = driver.execute_script("return document.querySelector('meta[itemprop=\"datePublished\"]').content") precise_date = datetime.fromisoformat(date_str.replace("Z", "+00:00")) # 方法2:展开描述后提取文本日期(适合需要"6 Sept 2023"格式的场景) # try: # show_more_btn = WebDriverWait(driver, 5).until( # EC.element_to_be_clickable((By.XPATH, "//tp-yt-paper-button[@id='expand']")) # ) # show_more_btn.click() # date_text = driver.find_element(By.XPATH, "//div[@id='info-strings']//yt-formatted-string").text # precise_date = datetime.strptime(date_text, "%d %b %Y") # except: # pass driver.close() driver.switch_to.window(driver.window_handles[0]) return precise_date - 日期范围筛选:YouTube视频按发布时间倒序排列,抓取到早于2021年9月10日的视频时可提前终止爬取:
start_date = datetime(2021, 9, 10) end_date = datetime(2023, 9, 10) for video in videos: video_date = get_precise_date(video["url"]) if start_date <= video_date <= end_date: video["date"] = video_date.strftime("%d %b %Y") else: # 早于起始日期,停止后续爬取 break
内容的提问来源于stack exchange,提问作者Leo Rigasaki
相关产品推荐
相关产品推荐

