前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python调用JavaScript代码

Python调用JavaScript代码

作者头像
小歪
发布2018-10-23 10:41:25
1.5K0
发布2018-10-23 10:41:25
举报

在写爬虫经常会遇到很多JS代码,比如说某些参数加密,可以只用用Python来翻译,但是有时候代码不容易阅读(JS渣渣),所以这里直接去找一条捷径,直接用Python的第三方库去调用JS代码。

这里用到的是 execjs

安装

虽然这个库导入名是import execjs,但是安装名却不是。安装方式如下:

代码语言:javascript
复制
$ pip install PyExecJS

使用

官方的例子

代码语言:javascript
复制
>>> 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代码:

代码语言:javascript
复制
def compile(source, cwd=None):
    return get().compile(source, cwd)

编译代码:

代码语言:javascript
复制
def _compile(self, source, cwd=None):
    return self.Context(self, source, cwd=cwd, tempfile=self._tempfile)

然后call来执行:

代码语言:javascript
复制
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

实例

代码语言:javascript
复制
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,我目前不清楚如何去翻译,所以直接偷懒:

代码语言:javascript
复制
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大佬可以试试翻译一波。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python爬虫与算法进阶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • 使用
  • 实例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档