下面我将从不同场景出发,为你详细介绍几种主流的方法,并提供代码示例。

核心思路
在 Python 中调用 JavaScript,本质上是在 Python 程序中“启动”一个 JavaScript 的运行环境,然后传递数据给 JS 执行,最后将 JS 的执行结果返回给 Python。
使用 PyExecJS (通用 JS 解释器)
PyExecJS 是一个非常流行的库,它提供了一个统一的接口来调用不同的 JavaScript 运行时环境(如 Node.js、PyV8、JavaScriptCore 等),它不依赖于浏览器,非常适合在服务器端执行 JS 代码。
安装
pip install PyExecJS
使用示例
PyExecJS 会自动在系统中寻找可用的 JS 运行时,如果你安装了 Node.js,它会优先使用它。
示例 1:执行简单的 JS 代码

import execjs
# 1. 创建一个 JS 运行时环境
ctx = execjs.compile("""
// 定义一个 JS 函数
function add(a, b) {
return a + b;
}
// 也可以直接执行表达式
var global_var = 'Hello from JS!';
""")
# 2. 调用 JS 函数
# 第一个参数是函数名,后面的参数是传递给函数的参数
result = ctx.call("add", 10, 20)
print(f"JS 函数 add 的返回值: {result}") # 输出: JS 函数 add 的返回值: 30
# 3. 获取 JS 全局变量
global_value = ctx.eval("global_var")
print(f"JS 全局变量的值: {global_value}") # 输出: JS 全局变量的值: Hello from JS!
示例 2:处理复杂数据类型(JSON)
JS 和 Python 之间通过 PyExecJS 传递数据时,会自动进行序列化和反序列化。
import execjs
js_code = """
function process_data(data) {
console.log("JS 收到的数据:", data);
data.count = data.items.length;
return data;
}
"""
ctx = execjs.compile(js_code)
# Python 数据
python_data = {
"user": "Alice",
"items": ["apple", "banana", "cherry"]
}
# 调用 JS 函数,并传递 Python 字典
# PyExecJS 会自动将 Python dict 转为 JS object
processed_data = ctx.call("process_data", python_data)
# JS 返回的 object 会被自动转为 Python dict
print("处理后的数据:", processed_data)
# 输出:
# JS 收到的数据: {'user': 'Alice', 'items': ['apple', 'banana', 'cherry']}
# 处理后的数据: {'user': 'Alice', 'items': ['apple', 'banana', 'cherry'], 'count': 3}
使用 node.js (通过子进程调用)
如果你的系统上安装了 Node.js,你可以直接在 Python 中通过命令行调用 Node.js 来执行一个 .js 文件,这种方法非常适合将复杂的 JS 逻辑封装在单独的文件中。
确保已安装 Node.js
在终端运行 node -v 检查是否安装。

使用示例
步骤 1:创建一个 JavaScript 文件 my_script.js
// my_script.js
function calculateFactorial(n) {
if (n === 0 || n === 1) {
return 1;
}
return n * calculateFactorial(n - 1);
}
// 从命令行参数获取输入
const input = parseInt(process.argv[2], 10);
const result = calculateFactorial(input);
// 将结果以 JSON 格式输出到标准输出,方便 Python 读取
console.log(JSON.stringify({ result: result }));
步骤 2:在 Python 中调用这个脚本
import subprocess
import json
# 要计算的阶乘的数字
number = 5
# 使用 subprocess 调用 node 命令
# 注意路径,node 不在系统 PATH 中,需要提供完整路径
try:
# subprocess.run 会执行命令并等待它完成
result = subprocess.run(
["node", "my_script.js", str(number)], # 命令和参数
capture_output=True, # 捕获标准输出和标准错误
text=True, # 将输出解码为文本
check=True # 如果命令返回非零状态码,则抛出异常
)
# 从标准输出中读取结果
js_output = result.stdout.strip()
print(f"JS 脚本的原始输出: {js_output}")
# 解析 JSON 输出
data = json.loads(js_output)
factorial_result = data["result"]
print(f"{number} 的阶乘是: {factorial_result}")
except FileNotFoundError:
print("错误: 未找到 'node' 命令,请确保 Node.js 已安装并添加到系统 PATH 中。")
except subprocess.CalledProcessError as e:
print(f"执行 JS 脚本时出错: {e.stderr}")
使用 Selenium / Playwright (浏览器自动化)
当你需要在一个真实的浏览器环境中执行 JavaScript 时(操作 DOM、访问 window 对象、触发页面事件等),应该使用 Selenium 或 Playwright,这种方法模拟了用户的真实操作。
安装
# Selenium pip install selenium # Playwright (推荐) pip install playwright playwright install # 安装浏览器驱动
使用示例 (以 Playwright 为例)
Playwright 的 API 更现代化,性能也更好。
from playwright.sync_api import sync_playwright
def run_js_in_browser():
with sync_playwright() as p:
# 启动一个浏览器实例 (chromium, firefox, webkit)
browser = p.chromium.launch()
page = browser.new_page()
# 访问一个网页
page.goto("https://www.example.com")
# 在浏览器页面的上下文中执行 JavaScript
# 1. 获取页面的标题
title = page.evaluate("document.title")
print(f"页面标题 (通过 JS 获取): {title}")
# 2. 执行一个复杂的 JS 函数,并传递参数
js_code = """
(arg) => {
const h1 = document.querySelector('h1');
if (h1) {
h1.style.color = 'blue';
h1.textContent = arg;
return h1.textContent;
}
return 'No h1 found';
}
"""
new_text = page.evaluate(js_code, "Hello from Python!")
print(f"JS 修改 h1 标签后的内容: {new_text}")
# 3. 获取页面上所有链接的数量
link_count = page.evaluate("document.links.length")
print(f"页面上的链接数量: {link_count}")
browser.close()
run_js_in_browser()
使用 PyV8 或 PyMiniRacer (嵌入式 V8 引擎)
这些库将 Google 的 V8 JavaScript 引擎直接嵌入到 Python 中,性能非常高,启动速度快,但它们通常比 PyExecJS 难以安装,并且可能不支持最新的 JS 特性。
- PyMiniRacer: 在 Ruby 中非常流行,Python 也有移植。
- PyV8: 较老的项目,维护可能不活跃。
PyMiniRacer 安装示例:
# 可能需要先安装一些系统依赖 # macOS: brew install v8 # Ubuntu: sudo apt-get install v8-314-libnode1 v8-314-dev pip install PyMiniRacer
使用示例:
from mini_racer import MiniRacer
ctx = MiniRacer.JSContext()
# 执行 JS 代码
ctx.eval("var x = 10; var y = 20;")
result = ctx.eval("x + y;")
print(f"PyMiniRacer 计算结果: {result}") # 输出: 30
# 调用函数
js_code = """
(function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
})
"""
fib = ctx.eval(js_code)
print(f"斐波那契数列第 10 项: {fib(10)}") # 输出: 55
总结与对比
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| PyExecJS | 通用 JS 代码执行,不依赖浏览器。 | 简单易用,支持多种后端运行时。 | 性能不如嵌入式引擎,依赖外部环境(如 Node.js)。 |
| Node.js 子进程 | 执行独立的、复杂的 JS 脚本文件。 | 解耦性好,JS 代码可维护性高。 | 进程间通信有开销,不适合频繁调用。 |
| Selenium/Playwright | 需要在真实浏览器环境中执行 JS(如操作 DOM、处理页面事件)。 | 功能最强大,能模拟真实用户交互。 | 重量级,启动慢,主要用于自动化测试和爬虫。 |
| PyMiniRacer/PyV8 | 对性能要求极高,需要嵌入式 JS 环境。 | 性能最好,启动快。 | 安装可能复杂,JS 特性支持可能不是最新的。 |
如何选择?
- 只是简单执行一段 JS 函数或表达式:首选
PyExecJS,最简单。 - JS 逻辑非常复杂,或者是一个现成的 Node.js 项目:使用 Node.js 子进程 调用
.js文件。 - 你的 JS 需要和网页交互(爬虫、自动化测试):必须使用 Selenium 或 Playwright。
- 你的应用对性能有极致要求,且不介意复杂的安装:可以考虑
PyMiniRacer。
