初识PyExecJS

基于已成功逆向后的JS代码,可以直接生成对应的加密参数,而PyExecJS则是可以在Python脚本中执行对应JS脚本并返回结果。

PyExecJS可以指定不同的解析环境,这里推荐使用Node.js

安装、配置PyExecJS

安装

pip install pyexecjs

指定解释环境

os.environ["NODE_PATH"] = os.getcwd()+"/node_modules"

将解释环境绑定为本地NODE包

print(execjs.get().name)

验证是否为Node,结果:

Node.js (V8)

调用DEMO

import execjs
import os

os.environ["NODE_PATH"] = os.getcwd() + "/node_modules"


def get_it(text: str) -> dict:
with open('./yd.js') as f:
js_code = f.read()

js = execjs.compile(js_code) # 这里同样可以使用cwd参数指定解释环境
return js.call('getIt', text)


print(get_it('你好'))

实际应用

根据之前文章:有道翻译API逆向

代码如下:

import execjs
import os
import requests

os.environ["NODE_PATH"] = os.getcwd() + "/node_modules"


def get_it(text: str) -> dict:
with open('./yd.js') as f:
js_code = f.read()

js = execjs.compile(js_code) # 这里同样可以使用cwd参数指定解释环境
return js.call('getIt', text)


def translate(text: str) -> str:
api = 'https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'

header = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Content-Length": "252",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "OUTFOX_SEARCH_USER_ID=-1592407075@10.112.57.88; OUTFOX_SEARCH_USER_ID_NCOO=2043557013.325027;",
"Host": "fanyi.youdao.com",
"Origin": "https://fanyi.youdao.com",
"Pragma": "no-cache",
"Referer": "https://fanyi.youdao.com/",
"sec-ch-ua": "\"Microsoft Edge\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.56",
"X-Requested-With": "XMLHttpRequest"
}

form = {
"i": text,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTlME"
}
result = get_it(text)
header['Cookie'] += f'___rl__test__cookies={result["lts"]}'
form.update(result)

res = requests.post(url=api, data=form, headers=header)
res_json = res.json()
try:
return res_json['translateResult'][0][0]['tgt']
except KeyError:
return res_json


if __name__ == '__main__':
print(translate('你好'))

输出结果:

hello

可能出现的问题

出现UnicodeEncodeError: 'gbk' codec...问题

在Python安装目录中Lib下找到subprocess.py文件然后通过搜索encoding方式找到类Popen,修改其__init__方法的encoding参数默认值为utf-8(原默认为None)即可。

def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=True,
shell=False, cwd=None, env=None, universal_newlines=None,
startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False,
pass_fds=(), *, user=None, group=None, extra_groups=None,
encoding='utf-8', errors=None, text=None, umask=-1, pipesize=-1):
"""Create new Popen instance."""