在寫爬蟲經常會遇到很多JS代碼,比如說某些參數加密,可以只用用Python來翻譯,但是有時候代碼不容易閱讀(JS渣渣),所以這裏直接去找一條捷徑,直接用Python的第三方庫去調用JS代碼。
這裏用到的是 execjs
安裝
雖然這個庫導入名是import execjs
,但是安裝名卻不是。安裝方式如下:
$ pip install PyExecJS
使用
官方的例子
>>> import execjs >>> execjs.eval("'red yellow blue'.split(' ')")['red', 'yellow', 'blue'] >>> ctx = execjs.compile("""... function add(x, y) {... return x + y;... }... """) >>> ctx.call("add", 1, 2) 3
用法很簡單,execjs.compile
後面就是JS源碼,然後使用ctx.call
來調用,參數就是JS中定義的函數名,同時可以傳遞參數。
作者也有說到:
PyExecJS的優點是您不需要處理JavaScript環境。 特別是,它可以在Windows環境中運行,無需安裝額外的庫。 PyExecJS的一個缺點是性能。 PyExecJS通過文本傳遞JavaScript運行時,速度很慢。 另一個缺點是它不完全支持運行時特定功能。
看了下源碼,執行過程大概是這樣。
首先用compile
來編譯JS代碼:
def compile(source, cwd=None): return get().compile(source, cwd)
編譯代碼:
def _compile(self, source, cwd=None): return self.Context(self, source, cwd=cwd, tempfile=self._tempfile)
然後call
來執行:
def call(self, name, *args): '''Call a JavaScript function in context. name -- Name of funtion object to call args -- Arguments for the funtion object ''' if not self.is_available(): raise execjs.RuntimeUnavailableError return self._call(name, *args)###def _call(self, identifier, *args): args = json.dumps(args) return self._eval("{identifier}.apply(this, {args})".format(identifier=identifier, args=args))###def _eval(self, source): if not source.strip(): data = "''" else: data = "'('+" + json.dumps(source, ensure_ascii=True) + "+')'" code = 'return eval({data})'.format(data=data) return self.exec_(code)###def _compile(self, source): runner_source = self._runtime._runner_source replacements = { '#{source}': lambda: source, '#{encoded_source}': lambda: json.dumps( "(function(){ " + encode_unicode_codepoints(source) + " })()" ), '#{json2_source}': _json2._json2_source, } pattern = "|".join(re.escape(k) for k in replacements) runner_source = re.sub(pattern, lambda m: replacements[m.group(0)](), runner_source) return runner_source
實例
function generateUUID() { var d = (new Date).getTime() , a = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(a) { var r = (d + 16 * Math.random()) % 16 | 0; return d = Math.floor(d / 16), ("x" == a ? r : 7 & r | 8).toString(16) }); return a}
例如有上面這段JS,我目前不清楚如何去翻譯,所以直接偷懶:
def generate_uuid(): js = """ function generateUUID() { var d = (new Date).getTime() , a = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(a) { var r = (d + 16 * Math.random()) % 16 | 0; return d = Math.floor(d / 16), ("x" == a ? r : 7 & r | 8).toString(16) }); return a } """ ctx = execjs.compile(js) return ctx.call("generateUUID")
JS大佬可以試試翻譯一波。