python爬虫----通过Node.js来执行js

python脚本中可以通过PyExecJS库来处理js代码(可参考:excejs的使用),但是性能并不高,很难满足高并发的要求

Node.js是一个Javascript运行环境(runtime)。它对Google V8引擎进行了封装,使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,能够方便地搭建响应速度快、易于扩展的网络应用,因此我们可以借助Node.js来执行js代码。

思路:

  • 创建一个js文件,用于存储我们抠出来的js代码,并且通过exports对外暴露属性或方法,或者通过module.exports对外暴露对象(包含多个属性或方法)
  • 创建一个server.js文件,通过require载入上述js文件,然后利用express框架来搭建web应用,通过定义路由来实现各种js逻辑
  • 通过命令:node server.js 来开启web应用,然后在python脚本中通过requests向应用服务器发送get/post请求获取响应数据

我们以百度翻译案例中的js为例,获取sign参数:

  • 准备工作

    • 安装Node.js
    • 使用淘宝镜像
      npm install -g cnpm --registry=https://registry.npm.taobao.org

      国内直接使用 npm 的官方镜像是非常慢,推荐使用淘宝 NPM 镜像,使用淘宝定制的 cnpm 命令行工具代替默认的 npm

    • 安装Express框架,并将其保存到依赖列表
      cnpm install express --save

      以上命令会将 Express 框架安装在当前目录的 node_modules 目录中,如果没有该目录则自动创建, node_modules 目录下会自动创建 express 目录

    • 安装body-parser模块
      cnpm install body-parser --save

      该模块用于处理 JSON, Raw, Text 和 URL 编码的数据

  • 编写baiduTranslate.js文件

    function n(r, o) {
            for (var t = 0; t < o.length - 2; t += 3) {
                var a = o.charAt(t + 2);
                a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
                a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
                r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
            }
            return r
        }
    
    function getSign(r) {
        var i = '320305.131321201';
        var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
        if (null === o) {
            var t = r.length;
            t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
        } else {
            for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
                "" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                C !== h - 1 && f.push(o[C]);
            var g = f.length;
            g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
        }
        var u = void 0
            , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
        u = null !== i ? i : (i = window[l] || "") || "";
        for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
            var A = r.charCodeAt(v);
            128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
                S[c++] = A >> 18 | 240,
                S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
                S[c++] = A >> 6 & 63 | 128),
                S[c++] = 63 & A | 128)
        }
        for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
            p += S[b],
                p = n(p, F);
        return p = n(p, D),
            p ^= s,
        0 > p && (p = (2147483647 & p) + 2147483648),
            p %= 1e6,
        p.toString() + "." + (p ^ m)
    }
    
    //可以采用以下3种方式对外暴露getSign方法
    
    //方式1:使用exports对外暴露getSign方法
    exports.getSign = getSign
    
    //方式2:使用module.exports对外暴露对象,该对象具有getSign方法
    // module.exports = {
    //     getSign:getSign
    // }
    
    //方式3:是方式2的简写方式,对于方法名和函数名相同的都可以采用简写方式,多个方法间用逗号','隔开
    // module.exports = {
    //     getSign
    // }

    该js文件中是抠出来的js代码,并且向外暴露getSign方法

  • server.js

    //引入依赖包
    
    var express = require('express');
    var bodyParser = require('body-parser');
    
    //引入自定义模块
    var baiduTranslate = require('./baiduTranslate');
    
    //创建应用实例
    var app = express();
    
    //将表单数据或者json数据转换成对象,以下只有一个会执行
    app.use(bodyParser.urlencoded({extended:true}));
    app.use(bodyParser.json());
    
    
    //创建路由
    //POST请求
    app.post('/get_sign',function (req,res) {
        //获取请求体中传递的参数
        let result = req.body;
        let content = result.content
        //调用baiduTranslate模块中的getSign方法,并传入参数
        result = baiduTranslate.getSign(content)
        res.send(result.toString());
    });
    
    //创建路由
    //GET请求
    app.get('/get_sign',function (req,res) {
        //获取查询字符串参数
        let result = req.query;
        let content = result.content;
        //调用baiduTranslate模块中的getSign方法,并传入参数
        result = baiduTranslate.getSign(content)
        res.send(result.toString());
    })
    
    //启动服务
    var server = app.listen(8888,function () {
        var host = server.address().address
        var port = server.address().port
        console.log("开启服务,访问地址为 http://%s:%s", host, port)
    })

    以后编写server.js代码,可以直接参照上述模板,只需要修改引入的(自定义模块名)以及(路由函数中的逻辑)即可

  • python脚本test.py

    #coding:utf-8
    
    import requests
    
    url = 'http://localhost:8888/get_sign'
    content = input('请输入需要翻译的内容:')
    
    sign1 = requests.post(url=url,data = {'content':content}).text
    print('通过post请求获取sign参数:{}'.format(sign1))
    sign2 = requests.get(url=url,params={'content':content}).text
    print('通过get请求获取sign参数:{}'.format(sign2))
  • 在server.js文件所在目录下,通过cmd命令行启动服务

    node server.js
  • 运行python脚本后结果展示:

    请输入需要翻译的内容:hello
    通过post请求获取sign参数:54706.276099
    通过get请求获取sign参数:54706.276099

     

posted @ 2021-10-07 02:51  eliwang  阅读(881)  评论(0编辑  收藏  举报