使用Selenium爬取Youtube时driver.page_source长度异常变化问题
问题背景
开发Youtube爬虫时,使用Selenium获取driver.page_source并传入BeautifulSoup解析,发现多次获取的page_source长度无规律变化,相关代码及输出如下:
代码片段
elif 'src' in seq: print('video-src') print(seq['src']) soup = bs(driver.page_source, "html.parser") print('driver.page_source length='+str(len(driver.page_source))) f = open('test.txt','w',encoding='UTF-8') f.write(driver.page_source) f.close() print('driver.page_source length='+str(len(driver.page_source))) tag = '<span dir="auto" class="style-scope yt-formatted-string">' find_start = driver.page_source.find(tag+'댓글') print('driver.page_source length='+str(len(driver.page_source))) tag_value = driver.page_source[find_start:find_start+200] print('driver.page_source length='+str(len(driver.page_source))) p = re.compile('\>([\d,]+)\<') m = p.search(tag_value) if m: print(m.group(1)) video[item['name']] = m.group(1) else: print('error') print(tag_value)
输出结果
driver.page_source length=4103114 driver.page_source length=4102392 driver.page_source length=4102392 driver.page_source length=4103129
可能的原因
页面动态内容实时更新:Youtube是高度动态的单页应用,页面会通过异步请求持续更新内容——比如评论数的实时变化、推荐卡片的加载/替换、广告元素的动态渲染、甚至页面状态提示的显示/隐藏。每次调用
driver.page_source都会获取当前时刻的DOM快照,不同时刻的DOM内容自然存在差异,导致长度变化。多次调用
driver.page_source未复用变量:你的代码中每次打印长度、写入文件、查找字符串时,都是直接调用driver.page_source,而非先将其存入变量复用。这意味着每次调用都会重新获取最新的DOM状态,而Youtube页面在这极短的时间内可能已经发生了细微更新,从而导致长度不一致。前端JS动态修改DOM:Youtube的前端JS会频繁修改DOM结构,比如为元素添加/移除样式类、调整文本节点的空格或格式、动态加载组件等。这些修改可能不会改变页面的视觉表现,但会导致HTML源码的长度发生变化。
页面加载状态未稳定:代码中没有等待页面完全加载稳定就开始获取
page_source。即使页面初始渲染完成,仍可能有后续的异步请求在加载资源或更新内容,此时获取的page_source处于“未完成”状态,后续再次获取时页面已更新,长度自然不同。
快速解决建议
将driver.page_source一次性存入变量,后续所有操作都基于该变量,避免多次实时获取:
elif 'src' in seq: print('video-src') print(seq['src']) # 一次性获取并复用page_source page_source = driver.page_source soup = bs(page_source, "html.parser") print('driver.page_source length='+str(len(page_source))) f = open('test.txt','w',encoding='UTF-8') f.write(page_source) f.close() print('driver.page_source length='+str(len(page_source))) tag = '<span dir="auto" class="style-scope yt-formatted-string">' find_start = page_source.find(tag+'댓글') print('driver.page_source length='+str(len(page_source))) tag_value = page_source[find_start:find_start+200] print('driver.page_source length='+str(len(page_source))) p = re.compile('\>([\d,]+)\<') m = p.search(tag_value) if m: print(m.group(1)) video[item['name']] = m.group(1) else: print('error') print(tag_value)
另外,可通过WebDriverWait等待目标元素(比如评论数元素)加载完成后再获取page_source,确保页面状态稳定:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待评论数元素出现,最多等待10秒 WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.XPATH, "//span[contains(text(), '댓글')]/following-sibling::span")) ) # 再获取page_source page_source = driver.page_source
内容的提问来源于stack exchange,提问作者EUN WOO LEE

