You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python Selenium获取浏览器获取YouTube媒体包时的调用栈

可以通过Selenium实现,需结合Chrome DevTools Protocol(CDP)

Selenium原生日志API无法直接获取网络请求对应的JavaScript调用栈,需要借助Chrome DevTools Protocol(CDP)来实现。以下是具体方案:

核心思路

  • 用Selenium 4+内置的CDP接口,启用浏览器的Network和Runtime调试域
  • 监听Network.requestWillBeSent事件,捕获YouTube媒体包请求(通常是.m4s、.webm格式的分片文件)
  • 在媒体请求触发时,调用CDP的Runtime.getStackTrace获取当前JavaScript调用栈

示例代码

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import time

# 初始化Chrome浏览器
service = Service("/usr/local/bin/chromedriver")
driver = webdriver.Chrome(service=service)

# 启用Network和Runtime调试域
driver.execute_cdp_cmd("Network.enable", {})
driver.execute_cdp_cmd("Runtime.enable", {})

# 存储捕获到的调用栈
media_call_stacks = []

def capture_call_stack(request_data):
    # 过滤YouTube媒体分片请求
    if ".m4s" in request_data["request"]["url"] or ".webm" in request_data["request"]["url"]:
        # 获取当前调用栈
        stack_trace = driver.execute_cdp_cmd("Runtime.getStackTrace", {})
        media_call_stacks.append({
            "request_url": request_data["request"]["url"],
            "call_stack": stack_trace["callFrames"]
        })
        # 打印当前请求的调用栈
        print(f"捕获媒体请求: {request_data['request']['url']}")
        print("调用栈:")
        for frame in stack_trace["callFrames"]:
            func_name = frame["functionName"] if frame["functionName"] else "匿名函数"
            print(f"  - {func_name} (文件: {frame['url'].split('/')[-1]} 行号: {frame['lineNumber']})")

# 监听网络请求发送事件
driver.add_cdp_listener("Network.requestWillBeSent", capture_call_stack)

# 打开目标YouTube视频页面
driver.get("https://www.youtube.com/watch?v=vlzCi0x9uJw")

# 等待媒体请求触发(可根据实际情况调整时长)
time.sleep(10)

# 输出所有捕获的调用栈汇总
print("\n=== 所有媒体请求调用栈汇总 ===")
for item in media_call_stacks:
    print(f"\n请求URL: {item['request_url']}")
    print("调用栈详情:")
    for frame in item["call_stack"]:
        func_name = frame["functionName"] if frame["functionName"] else "匿名函数"
        print(f"  {func_name} | 文件: {frame['url'].split('/')[-1]} | 行号: {frame['lineNumber']}")

driver.quit()

关键说明

  • 请求过滤:通过URL后缀.m4s/.webm识别媒体分片,可根据实际需求调整过滤规则
  • 调用栈解析:Runtime.getStackTrace返回的callFrames数组包含每个调用帧的函数名、文件路径、行号等信息
  • 版本要求:必须使用Selenium 4及以上版本,Selenium 3对CDP支持有限
  • 等待优化:示例中用time.sleep等待请求触发,实际场景可结合显式等待(如等待视频播放按钮加载完成)提升效率

精准调试替代方案:断点触发

如果需要在特定媒体加载函数触发时捕获调用栈,可通过CDP设置断点:

# 在指定脚本的特定行设置断点
driver.execute_cdp_cmd("Debugger.setBreakpointByUrl", {
    "url": "https://www.youtube.com/youtubei/v1/player/streamingData?key=...",
    "lineNumber": 456
})

# 监听断点命中事件
def on_breakpoint_hit(breakpoint_data):
    print("\n断点命中,调用栈:")
    for frame in breakpoint_data["callFrames"]:
        func_name = frame["functionName"] if frame["functionName"] else "匿名函数"
        print(f"  - {func_name}")

driver.add_cdp_listener("Debugger.paused", on_breakpoint_hit)

该方法需要提前定位媒体加载相关的JS文件和行号,适合深度调试场景。

内容的提问来源于stack exchange,提问作者Satvik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:19:24