js2py ( Released: Apr 2, 2021 )

Github: https://github.com/PiotrDabkowski/Js2Py

官网:http://piter.io/projects/js2py

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In [1]: import js2py

# 执行单行语句
In [3]: js2py.eval_js("console.log('abcd')")
'abcd'

In [8]: context = js2py.EvalJs({}, enable_require=True)
In [9]: context.execute("console.log(123)")
'123'


# 返回js函数
In [5]: add_fun = js2py.eval_js("function add(a, b) {return a + b};")
In [6]: add_fun
Out[6]: 'function add(a, b) { [python code] }'
In [7]: add_fun(1, 2)
Out[7]: 3


# js函数调用
In [18]: js_code = '''
...: var a = 10
...: function f(x) {return x*x}
...: '''

In [19]: context = js2py.EvalJs({})
In [20]: context.execute(js_code)
In [21]: context.f(22)
Out[21]: 484

进阶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 在js代码中引进python对象
In [12]: context = js2py.EvalJs({'python_sum': sum})
In [13]: context.eval('python_sum(new Array(1,4,2,7))')
Out[13]: 14

In [15]: context = js2py.EvalJs({"data": {"name": "cxs"}})
In [16]: context.eval('console.log(data)')
{'name': 'cxs'}

# js语句转换
In [31]: py_code = js2py.translate_js('var abc = 5')

In [32]: print(py_code)
'''
from js2py.pyjs import *
# setting scope
var = Scope( JS_BUILTINS )
set_global_object(var)

# Code follows:
var.registers(['abc'])
var.put('abc', Js(5.0))
'''


# js文件转换
In [23]: !type cxs.js
'''
function calcute(x, y){
return (x + y) * (x - y)
}
'''
In [24]: js2py.translate_file('cxs.js', 'cxs.py')

In [25]: !type cxs.py
'''
__all__ = ['cxs']

# Don't look below, you will not understand this Python code :) I don't.

from js2py.pyjs import *
# setting scope
var = Scope( JS_BUILTINS )
set_global_object(var)

# Code follows:
var.registers(['calcute'])
@Js
def PyJsHoisted_calcute_(x, y, this, arguments, var=var):
var = Scope({'x':x, 'y':y, 'this':this, 'arguments':arguments}, var)
var.registers(['x', 'y'])
return ((var.get('x')+var.get('y'))*(var.get('x')-var.get('y')))
PyJsHoisted_calcute_.func_name = 'calcute'
var.put('calcute', PyJsHoisted_calcute_)
pass
pass


# Add lib to the module scope
cxs = var.to_python()
'''

# 这样其他地方需要引入的话,直接 from cxs import calcute

execjs (Released: Jan 18, 2018)

This library is no longer maintananced. Bugs are not be fixed (even if they are trivial or essential).

We suggest to use other library or to make a fork.

Github: https://github.com/doloopwhile/PyExecJS

Pypi: https://pypi.org/project/pyexecjs/

查看环境

1
2
3
4
5
6
7
8
9
10
11
12
13
In [39]: execjs.get().name
Out[39]: 'Node.js (V8)'

# 默认环境
In [40]: default = execjs.get()
In [41]: default.eval("1 + 2")
Out[41]: 3

# 指定环境
In [42]: import execjs.runtime_names
In [43]: node = execjs.get(execjs.runtime_names.Node)
In [44]: node.eval("1 + 2")
Out[44]: 3

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [34]: import execjs

# 执行js语句
In [35]: execjs.eval("'red yellow blue'.split(' ')")
Out[35]: ['red', 'yellow', 'blue']

# 编译js语句
In [36]: ctx = execjs.compile(
"""
function add(x, y) {
return x + y;
}
"""
)
# 函数调用
In [37]: ctx.call("add", 1, 2)
Out[37]: 3

subprocess调用node进程

获取 console.log() 结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import subprocess

process = subprocess.run("node abc.js", stdout=subprocess.PIPE)
_result = process.stdout
result = _result.decode().strip() # result即为console.log()输出

'''
封装成函数,方便复用
'''
def subprocess_node(js_file: str, *args):
if args:
js_cmd = f'node "{js_file}" {" ".join(args)}'
else:
js_cmd = f'node "{js_file}"'
传递参数

来举个梨子,比较容易理解

1
2
3
4
5
// 测试.js
var arguments = process.argv.splice(2);
console.log(arguments);
console.log('所传入的key是:', arguments[0]);
console.log('所传入的value是:', arguments[1]);

运行命令

1
2
3
4
5
6
node 测试.js abc cxs 13

输出:
[ 'name', 'cxs', '13' ]
所传入的key是: name
所传入的value是: cxs

如果是 var arguments = process.argv.splice(1) 的话,则arguments是文件路径

[ ‘C:\Users\Desktop\new-hello-world\ipython脚本测试\第一关\测试.js’ ]

2022.06.17 补充

在python代码中导入js模块

1
2
3
4
5
6
7
8
In [47]: CryptoJS = js2py.require("crypto-js")

# 可以直接使用js的语法
In [49]: CryptoJS.SHA1("cxs").toString(CryptoJS.enc.Hex)
Out[49]: '39dc2f3e923ca5e6ab67a60b7b951dddabcc055b'

In [50]: CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse("cxs"))
Out[50]: 'Y3hz'

就版本的js2py可能会报错:AssertionError: Could not link required node_modules

这里有相关的issue,https://github.com/PiotrDabkowski/Js2Py/issues/125

其实就是修改node_import.py文件的部分代码