美文网首页我爱编程
Java爬虫(四)-- java 调用js函数 模拟页面js密码

Java爬虫(四)-- java 调用js函数 模拟页面js密码

作者: Richard_易 | 来源:发表于2018-03-01 16:57 被阅读0次

    前言

    前面一章讲的是模拟登录,留了一个模拟密码加密还没讲。

    因为这一过程的调试探索还是蛮多内容的,我更倾向于记录自己整个探索的过程,而不是把工具拿出来讲一下用法,所以单独拿一章来讲。

    调试过程

    首先,既然要模拟js的加密过程,当然是要调试前端代码,从定位到起加密作用的js代码上面。

    F12浏览器调试时,source目录下可以看到当前的浏览器的一些静态文件,包括页面,css,js等文件,一开始先定位到点击登录按钮之后,肯定会执行的js代码,然后在那个上面打断点。

    像我要爬取的网站,会根据你所使用的浏览器使用不同的加密算法,所以要通过调试,知道它到底是怎么加密的。

    打了断点之后,我成功找到了加密的代码,

    image

    可以看到起加密作用的就是ciper.Enrypt()方法。把鼠标放在上面,点击如图所示出现的悬浮小窗里面的Enrypt(a,b),就跳到对应的js文件里面。

    这里就有一个很神奇的东西了,跳到的js文件并不在我source目录中,而是一个VM+"一串数字"的js中。

    查询了去Stack Overflow上面查了之后,看到了如下回答

    [VM] (scriptId) has no special meaning. It's a dummy name to help us to distinguish code which are not directly tied to a file name, such as code created using eval and friends.
    
    VM是虚拟机(Virtual Machine)的缩写,后面的数字是代码的编号ID,主要是为了区别原网页的js与其他来源的js(比如eval创建的, ajax获取的等)
    

    也就是说这个加密的js是动态加载出来的。

    定位到js之后,接下去就是怎么模拟了。

    ScriptEngine

    加密算法,可以说是非常复杂,所以不可能用java语言去模拟。就想着能不能在jvm上运行js的文件,这么一搜,还真有。

    java中的javax.script,它开始存在于JDK1.6,它可以解析通用的表达式,如三目,还可以利用js函数语法,创造一个就像java的函数一样存在于内存中随时可以被调用的函数,更可以将js中的对象直接转换成java对象。

    到了java8 之后 叫做 Nashorn JavaScript 引擎。扩展了很多功能。

    只不过这里面我们只使用它加载js文件,调用js中函数的功能,其他功能有兴趣的可以自己去了解一下。

    先介绍下基础用法

    在Java中直接调用js代码

    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;
    import javax.script.ScriptException;
    /**  * 直接调用js代码  */
    public class ScriptEngineTest {
        public static void main(String[] args) {
            ScriptEngineManager manager = new ScriptEngineManager();
            ScriptEngine engine = manager.getEngineByName("javascript");
              try {
                engine.eval("var a=3; var b=4;print (a+b);");
              } catch (ScriptException e) {
                  e.printStackTrace();
              }
          }
    }
    

    Java中调用js文件中的function,传入调用参数,并获取返回值

    // demo.js
    function count(a, b) {   
         c = a * b;   
         return c;   
    }  
    

    在Java代码中读取js文件,并参数两个参数,然后回去返回值

     import java.io.FileReader;    
     import javax.script.Invocable;  
     import javax.script.ScriptEngine;  
     import javax.script.ScriptEngineManager;    
    
     public class ScriptEngineTest {     
         public static void main(String[] args) throws Exception {     
            ScriptEngineManager manager = new ScriptEngineManager();     
            ScriptEngine engine = manager.getEngineByName("javascript");      
             String jsFileName = "demo.js";    
             // 读取js文件     
            FileReader reader = new FileReader(jsFileName);     
            // 执行指定脚本    
             engine.eval(reader);     
            if(engine instanceof Invocable) {     
                 Invocable invoke = (Invocable)engine;      
                // 调用count方法,并传入两个参数     
                 Double c = (Double)invoke.invokeFunction("merge", 2, 3);     
                 System.out.println("c = " + c);     
            }     
        reader.close();   
     }   
    } 
    

    实战

    了解了前面的基础知识和简单热身后,我这个问题就简单了。我浏览器上调试显示的js拷贝出来新建了一个js文件,放到resource目录下,用ScriptEngine去加载,把明文密码和公钥当做变量传进去调用js 中的function,这就好像是黑箱,我不需要知道里面的加密互相调用是怎么样。

    这里有一个坑注意一下:ScriptEngine执行js代码或者js文件的时候,被调用的代码中如果引用了浏览器中存在的对象,就会报错。比如alertnavigator之类的。

    ReferenceError: "xxx" is not defined
    

    原因显而易见,这个对象在你的脚本引擎中没有定义。

    我在解决这个问题的时候,先是看了一下有哪些对象,这些对象具体起了什么作用。

    看了之后发现,都是起着兼容性的作用,不同浏览器版本就会用不同的变量值或者说调用不同的加密方法。我就直接删去了里面兼容性判断部分的代码,给一些变量值指定了定值。最后就起到了同样的效果。

    相关文章

      网友评论

        本文标题:Java爬虫(四)-- java 调用js函数 模拟页面js密码

        本文链接:https://www.haomeiwen.com/subject/gpqnxftx.html