跨语言代码调用的需求普遍存在,例如:对于爬虫项目,浏览器端执行的生成动态签名JS
黑盒函数(用于在服务器端对伪造请求拦截,如淘宝的 HTTP 服务),因动态生成签名的函数被严重混淆很难翻译成开发爬虫的Python
代码或者Go
代码,这时候就需要使用开发语言调用从浏览器中提取的进行签名的JS
函数。Python 有 PyExecJS
,作为桥梁可以在 Node.js、PyV8、PhantomJS 等底层环境上执行 JS 代码;Java
语言有ScriptEngin
API 可执行多种语言,
String regular="function func(args1,args2){...}";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
engine.eval(regular);
Invocable invoke = (Invocable) engine;
String result = (String) invoke.invokeFunction("func",
args1,args2)System.out.println(result);
Go
语言有 github.com/dop251/goja
三方库,可以实现类似功能。
package main
import (
"fmt"
"github.com/dop251/goja"
)
//申明js脚本函数
const script = `
location = {href : ""}
function token(){return location;}
`
//定义代理接口
var getToken func() string
//自动初始化
func init(sc string) {
vm := goja.New()
_, err := vm.RunString(script)
if err != nil {
fmt.Println("JS报错了",err)
return
}
err = vm.ExportTo(vm.Get("token"), &getToken)
if err != nil {
fmt.Println("Js函数代理到 Go 函数失败",err)
return
}
}
func main(){
fmt.Println("Let's Go...")
v := getToken()
fmt.Println(v)
}
需要注意的是goja
库不是所有的浏览器端可执行的 JS 代码都被支持的,类似于 Node.js 环境,对于浏览器内置对象window
、location
都找不到定义,会报错。所以无法执行模拟浏览器交互行为的代码,以上只是验证跨语言调用是行得通的。具体需求需要具体分析,如果要模拟浏览器行为,不得不使用类似PhantomJS
的 HeadLess 软浏览器利器。