JavaScript 解释器是一个定制构建的、轻量级的 JavaScript 执行引擎,用 Python 实现,使 youtube-dl 能够执行在网站上找到的 JavaScript 代码。它的主要目的是在不需要完整浏览器或外部 JavaScript 引擎的情况下,解析视频平台(尤其是 YouTube)使用的签名保护机制。
JSInterpreter 使 YouTube 提取器能够执行负责签名解析的 JavaScript 代码。当 YouTube 提供视频 URL 时,这些 URL 通常包含必须使用嵌入在播放器代码中的 JavaScript 函数来处理的加密签名。此解释器允许 youtube-dl 分析和执行这些函数以获取有效的视频 URL。
本文档涵盖:
有关使用此解释器的 YouTube 提取器的信息,请参阅 YouTube 提取器。
JavaScript 解释器由一个轻量级的解析器和执行引擎组成,可以处理签名解析所需的 JavaScript 代码子集。它专注于执行特定的 JavaScript 函数,而不是实现完整的 JavaScript 运行时。
来源:youtube_dl/jsinterp.py402-439 youtube_dl/jsinterp.py341-359 youtube_dl/jsinterp.py423-431 youtube_dl/jsinterp.py433-536 youtube_dl/jsinterp.py537-605
JSInterpreter 类是负责解析和执行 JavaScript 代码的主要组件。它将 JavaScript 代码解析为标记和表达式,然后根据 JavaScript 语义执行它们。
关键方法
__init__(code, objects):使用 JavaScript 代码初始化解释器call_function(func_name, *args):使用给定的参数调用 JavaScript 函数extract_function(func_name, *global_stack):从 JavaScript 代码中提取可调用的 Python 函数interpret_expression(expr, local_vars, allow_recursion):解释 JavaScript 表达式interpret_statement(stmt, local_vars, allow_recursion):解释 JavaScript 语句解释器处理变量作用域、运算符、控制流以及签名解析所需的基本 JavaScript 对象。
来源:youtube_dl/jsinterp.py402-439 youtube_dl/jsinterp.py827-1089 youtube_dl/jsinterp.py1090-1178
该解释器支持签名解析所需的 JavaScript 功能子集
来源:youtube_dl/jsinterp.py104-137 youtube_dl/jsinterp.py203-230 youtube_dl/jsinterp.py250-269 youtube_dl/jsinterp.py276-313
JavaScript 解释器在 YouTube 签名解析过程中起着至关重要的作用
该过程包括
来源:youtube_dl/extractor/youtube.py28 test/test_youtube_signature.py413-417 test/test_youtube_signature.py420-424
解释器使用标记化和递归下降技术来解析 JavaScript 表达式。它将表达式分解为其组成部分(运算符、操作数、函数调用),并根据 JavaScript 语义对其进行求值。
例如,要解析像 a + b 这样的二元运算,解释器会
来源:youtube_dl/jsinterp.py693-701 youtube_dl/jsinterp.py712-770 youtube_dl/jsinterp.py827-897
解释器实现具有正确优先顺序和语义的 JavaScript 运算符。这包括算术、比较、逻辑和位运算符。
Operators are implemented with specific functions that mimic JavaScript behavior:
- Arithmetic: +, -, *, /, %, **
- Comparison: ==, ===, !=, !==, <, >, <=, >=
- Logical: &&, ||, !
- Bitwise: &, |, ^, <<, >>
每个运算符函数都根据 JavaScript 规则处理类型转换和边缘情况。
来源:youtube_dl/jsinterp.py79-101 youtube_dl/jsinterp.py104-144 youtube_dl/jsinterp.py187-198 youtube_dl/jsinterp.py276-315
解释器支持 JavaScript 控制流结构
| 控制结构 | 描述 |
|---|---|
if/else | 条件执行 |
for 循环 | 带初始化、条件和增量的迭代 |
while 循环 | 基于条件的迭代 |
switch/case | 多分支选择 |
try/catch/finally | 异常处理 |
这些是通过解析控制结构语法并在条件和流程控制的基础上执行相应的代码块来实现的。
来源: youtube_dl/jsinterp.py938-956 youtube_dl/jsinterp.py972-1004 youtube_dl/jsinterp.py1008-1035 youtube_dl/jsinterp.py1037-1060
该解释器支持以下 JavaScript 数据类型以及相应的行为
| 数据类型 | 实现 |
|---|---|
| 数字 | Python 的 float 和 int |
| 字符串 | Python 的 str |
| 布尔值 | Python 的 bool |
| 数组 | Python 的 list |
| 对象 | Python 的 dict |
| 正则表达式 | 自定义 JS_RegExp 类 |
| 日期 | 自定义 JS_Date 类 |
| 未定义 | 自定义 JS_Undefined 对象 |
| Null | Python 的 None |
像 NaN 和 Infinity 这样的特殊值也实现了相应的 JavaScript 语义。
来源: youtube_dl/jsinterp.py71-76 youtube_dl/jsinterp.py148-167 youtube_dl/jsinterp.py423-431 youtube_dl/jsinterp.py433-536 youtube_dl/jsinterp.py537-605
JSInterpreter 主要由 YoutubeIE(YouTube 信息提取器)类使用,用于解析视频 URL 中的加密签名。
该过程通常涉及
来源:youtube_dl/extractor/youtube.py28 test/test_youtube_signature.py413-417 test/test_youtube_signature.py420-424
除了标准签名外,YouTube 还使用另一种称为“n”参数或“nsig”的签名保护机制。JSInterpreter 可以处理这两种类型
| 签名类型 | 描述 | 提取函数 |
|---|---|---|
| 标准签名 | 主签名参数 | _parse_sig_js |
| n 参数 (nsig) | 二次保护 | _extract_n_function_from_code |
这两种机制都使用 JSInterpreter,但可能从播放器代码中提取不同的函数。
来源: test/test_youtube_signature.py412-424
JSInterpreter 实现了一些自定义异常类型,用于处理 JavaScript 特定的错误情况
| 异常类型 | 描述 |
|---|---|
JS_Break | 表示 JavaScript 的 break 语句 |
JS_Continue | 表示 JavaScript 的 continue 语句 |
JS_Throw | 表示 JavaScript 的 throw 语句 |
JSInterpreter.Exception | 通用的 JavaScript 解释器错误 |
这些异常有助于在执行期间维护正确的控制流,并在解释失败时提供有意义的错误消息。
来源: youtube_dl/jsinterp.py325-339 youtube_dl/jsinterp.py415-421
JSInterpreter 并非完整的 JavaScript 引擎,存在一些限制
这些限制是可以接受的,因为解释器只需要处理用于签名解析的特定 JavaScript 函数,这些函数通常很简单,不使用高级 JavaScript 功能。
来源: youtube_dl/jsinterp.py402-439
JSInterpreter 经过全面测试,以确保它能正确解析 JavaScript 代码并解析签名。有两个主要的测试套件
test_jsinterp.py: 测试核心 JavaScript 解析功能test_youtube_signature.py: 使用真实的 YouTube 播放器代码测试签名解析过程这些测试涵盖了各种 JavaScript 功能,包括运算符、控制流、数据类型和函数,以及来自实际 YouTube 播放器代码的特定签名解析场景。
来源: test/test_jsinterp.py22-655 test/test_youtube_signature.py26-348
JavaScript 解释器是 youtube-dl 的一个关键组件,它使其能够解析 YouTube 的签名保护。通过实现 JavaScript 的特定子集,它可以执行必要的代码来获取有效的视频 URL,而无需完整的浏览器或外部 JavaScript 引擎。这种方法使 youtube-dl 更具自主性和效率,同时仍能处理 YouTube 不断变化的保护机制。