跨语言调用JS

跨语言代码调用的需求普遍存在,例如:对于爬虫项目,浏览器端执行的生成动态签名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 环境,对于浏览器内置对象windowlocation都找不到定义,会报错。所以无法执行模拟浏览器交互行为的代码,以上只是验证跨语言调用是行得通的。具体需求需要具体分析,如果要模拟浏览器行为,不得不使用类似PhantomJS的 HeadLess 软浏览器利器。