Skip to content

about

pyexecjs模块是用来专门调试js代码的模块。

下载:

bash
pip install pyexecjs

# 我用的是1.5.1版本的
pip install pyexecjs==1.5.1

测试:

python
# 注意,安装是 pyexecjs,但导入时,就是 execjs 了,这点需要注意
import execjs
# 有返回结果表示模块安装成功,调用本地的nodejs环境也成功了
print(execjs.get().name)  # Node.js (V8)

如果没有返回的话,检查nodejs的环境变量是否配置成功,没问题的话,尝试重启电脑。

execjs的底层执行逻辑(解决Windows平台乱码问题)

如果你运行下面的Python代码,则将会的到一个乱码的结果:

python
import execjs

# execjs.eval方法可以直接运行js代码并得到结果
js = """
    "张开_王开_李开_赵开".split("-")
"""
result = execjs.eval(js)
print(result)  # ['寮犲紑_鐜嬪紑_鏉庡紑_璧靛紑']

我们来分析下乱码的原因。

execjs模块底层执行的逻辑是,通过调用nodejs命令来执行js的代码,

用什么实现的呢?答案是使用Python的subprocess标准库的Popen做的,相当于是通过Popen默认一个终端命令node xx.js,然后获取执行结果。

但这个有问题,就是如果你的Windows系统,那么默认的字符编码是gbk,而我们执行Python代码用的utf-8编码的话,就会遇到乱码,如果读的是外部的js文件,甚至会出现报错,这就是因为Popen在执行cmd终端执行node xx.js命令时,终端的编码是gbk,最终导致的utf-8和gbk编码这两种编码不同意的问题,进而引发乱码或者报错。

那么解决办法也是有的,就是设置Popen在执行cmd终端执行node xx.js命令时,也使用utf-8的编码,这样编码保持一致,就不会出现乱码问题了。

所以下面的解决乱码的代码是固定写法:

python
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在import execjs导入代码的上面!!!!
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

# 上面解决乱码的代码执行完,再导入execjs模块,后续执行就不会出现乱码问题了。
import execjs

# execjs.eval方法可以直接运行js代码并得到结果
js = """
    "张开_王开_李开_赵开".split("-")
"""
result = execjs.eval(js)
print(result)  # ['张开_王开_李开_赵开']

常用方法

execjs.eval

execjs.eval方法可以直接运行js代码并得到结果,适用于在Python中执行简单的js代码:

python
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在import execjs导入代码的上面!!!!
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

# 上面解决乱码的代码执行完,再导入execjs模块,后续执行就不会出现乱码问题了。
import execjs

# execjs.eval方法可以直接运行js代码并得到结果
js = """
    "张开_王开_李开_赵开".split("-")
"""
result = execjs.eval(js)
print(result)  # ['张开_王开_李开_赵开']

execjs.compile

execjs.compile用来预编译即将要执行的js代码,然后得到一个预编译后的js代码对象,然后通过其他的方法执行js,所以这个execjs.compile通常和其他的方法结合使用。

call方法

当execjs.compile执行得到一个预编译后的js对象,我们就可以调用call方法执行js内部的代码,比如调用js中的某个函数。

来通过示例学习,首先我们有一个这样的demo.js文件:

javascript
function foo(a, b) {
    return a + b
}

那么,我们想要用execjs执行这个js函数,就需要用到call方法了:

python
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在import execjs导入代码的上面!!!!
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

# 上面解决乱码的代码执行完,再导入execjs模块,后续执行就不会出现乱码问题了。
import execjs

# 首先打开js文件,读取js代码
f = open('demo.js', 'r', encoding='utf8')
content = f.read()
f.close()

# 预编译js代码并得到预编译后的js对象
exe_obj = execjs.compile(content)

# 通过js对象调用call方法即可得到执行结果
result = exe_obj.call('foo', 1, 2)
print(result)  # 3
"""
call函数的语法
    call(函数名,参数1,参数2,参数n....)
"""

小技巧

处理不合法的json字符串

对于前端来说,如下示例是一个合法的对象:

javascript
{
  name: 'zhangkai',
  age: 18,
  info: { addr: '北京', phone: '1921111111' }
}

但如果你用Python从前端获取过来的是这样的数据,那Python中认为这是一串非法的json字符串,因为标准的json字符串的健也是双引号,值如果是引号的话,也是双引号,很明显上面的那段代码不符合这些规则,所以,Python无法通过json反序列化得到字典,那怎么办呢?答案是可以通过execjs来处理:

python
# -*- coding = utf-8 -*-
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在import execjs导入代码的上面!!!!
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

import execjs

# ------------ 使用 execjs.eval ------------
js = """
    {
        name: "zhangkai",
        age: 18,
        info: {
            addr: "北京",
            phone: '1921111111'
        }
    }
"""
res = execjs.eval(js)
print(type(res))  # <class 'dict'>
print(res)  # {'name': 'zhangkai', 'age': 18, 'info': {'addr': '北京', 'phone': '1921111111'}}

# ------------ 使用 execjs.call ------------
# 我们把对象加个函数补全,给它返回,然后通过call执行就行了
js = """
function fn() {
   return {
        name: "zhangkai",
        age: 18,
        info: {
            addr: "北京",
            phone: '1921111111'
        }
    }
}
"""
exe_obj = execjs.compile(js)
res = exe_obj.call('fn')
print(type(res))  # <class 'dict'>
print(res)  # {'name': 'zhangkai', 'age': 18, 'info': {'addr': '北京', 'phone': '1921111111'}}

搞定!!!