about
pyexecjs模块是用来专门调试js代码的模块。
下载:
pip install pyexecjs
# 我用的是1.5.1版本的
pip install pyexecjs==1.5.1
测试:
# 注意,安装是 pyexecjs,但导入时,就是 execjs 了,这点需要注意
import execjs
# 有返回结果表示模块安装成功,调用本地的nodejs环境也成功了
print(execjs.get().name) # Node.js (V8)
如果没有返回的话,检查nodejs的环境变量是否配置成功,没问题的话,尝试重启电脑。
execjs的底层执行逻辑(解决Windows平台乱码问题)
如果你运行下面的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的编码,这样编码保持一致,就不会出现乱码问题了。
所以下面的解决乱码的代码是固定写法:
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在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代码:
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在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
文件:
function foo(a, b) {
return a + b
}
那么,我们想要用execjs执行这个js函数,就需要用到call方法了:
# 下面三行代码是固定写法,用来解决乱码问题
# 注意!!注意!!注意!!!,这三行代码必须写在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字符串
对于前端来说,如下示例是一个合法的对象:
{
name: 'zhangkai',
age: 18,
info: { addr: '北京', phone: '1921111111' }
}
但如果你用Python从前端获取过来的是这样的数据,那Python中认为这是一串非法的json字符串,因为标准的json字符串的健也是双引号,值如果是引号的话,也是双引号,很明显上面的那段代码不符合这些规则,所以,Python无法通过json反序列化得到字典,那怎么办呢?答案是可以通过execjs来处理:
# -*- 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'}}
搞定!!!