Selenium Webdriver 的使用java执行js代码 解决 ScriptEngine不支持浏览器内置对象window,document的问题
问题场景:
使用java 掉用js代码,发现 ScriptEngine不支持浏览器内置对象window,document的问题;
问题一:为什么要 用java掉用js代码?
比如在 抓取(爬取)对方网站时,需要破解一些js逻辑代码合作加密算法,但是js混淆了,不能直接翻译出对应的逻辑,或者翻译的代价太高;
那么 不如 直接 使用js文件,模拟调用;这是 就会 使用到 java调用js的场景;
java 有支持调用js的解析引擎,示例代码如下:
/*** 获取java 提供的 ScriptEngine 脚本执行引擎 信息* @throws IOException*/@Testpublic void showScriptEngine() throws IOException {ScriptEngineManager manager = new ScriptEngineManager();List<ScriptEngineFactory> factories = manager.getEngineFactories();for (ScriptEngineFactory f : factories) {System.out.println(f.getEngineName());System.out.println(f.getEngineVersion());System.out.println(f.getLanguageName());System.out.println(f.getLanguageVersion());System.out.println(f.getExtensions());System.out.println(f.getMimeTypes());System.out.println(f.getNames());}}/*** java调用js 解析执行js脚本(js文件)代码* 场景:* 1,使用js特有的优势* 2,js特有的一些加密方式,并且js代码进行混淆了,转换为java方式 代价比较高的情况下* @throws Exception*/@Testpublic void testjava2js() throws Exception {ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("javascript");// 如果需要引用 js外部文件,可以通过流把js文件(jquery.js)读到一个String变量/*String jsFileName = "C:\\jquery.min.js"; // 读取js文件FileReader reader = new FileReader(jsFileName); // 执行指定脚本engine.eval(reader);*/String script = "function add(op1,op2){return op1+op2};var res1=2,res=10; "; //定义函数并调用engine.eval(script);Invocable invoke = (Invocable) engine; // 调用方法,并传入两个参数// 方式1 通过对象调用方法, 获取结果Object c = invoke.invokeFunction("add", 1,2);System.out.println(c);// 方式2 执行js脚本调用方法, 获取结果engine.eval("var res = add(2,3);");// 获取新定义的变量,会覆盖原有同名变量Object o = engine.get("res");System.out.println(o);// 获取 原有脚本/脚本文件 中的 变量Object o2 = engine.get("res1");System.out.println(o2);// 测试 浏览器 内置对象 是否支持try {engine.eval("alert(2);");} catch (Exception e) {System.out.println(e.getMessage());}try {engine.eval("document.write(2);");} catch (Exception e) {System.out.println(e.getMessage());}try {engine.eval("var innerHeight=window.innerHeight");} catch (Exception e) {System.out.println(e.getMessage());}try {engine.eval("var userAgent=navigator.userAgent");} catch (Exception e) {System.out.println(e.getMessage());}// ...so, ScriptEngine 不支持 浏览器内置对象;nodejs 也一样不支持 浏览器内置对象}
问题,这里有个问题,如果js代码中 有获取 浏览器 内置对象的 地方,比如 window.location, navigator.userAgent等,
那么ScriptEngine 解析的时候 就会 提示:
ReferenceError: "alert" is not defined in <eval> at line number 1
ReferenceError: "document" is not defined in <eval> at line number 1
ReferenceError: "window" is not defined in <eval> at line number 1
ReferenceError: "navigator" is not defined in <eval> at line number 1
那么 怎么 让 解析的时候 让ScriptEngine 支持 浏览器内置对象列?
首先 ScriptEngine 本身 不带 浏览器内核,那么就需要去 找其他 解析引擎;
其次 尝试 看了nodejs的文档,传说中 nodejs使用的v8引擎,应该支持吧,
const v8 = require('v8');
const vm = require('vm');
尝试了一下 发现 并不支持。他也是 后台的模式,和java的ScriptEngine 一致,只支持解析 非浏览器内核的js逻辑代码;
也对,毕竟 后台执行的js逻辑代码 怎么会 需要 获取浏览器对象列?
只能说我这个场景 太特殊了;
ok,此时 两个办法:
1,找到一个 java可以调用的 浏览器内核,模拟 js在浏览器中执行,并获取 执行之后的结果。
2,老老实实 读 js代码,读懂后 找到 java的逻辑实现方式。
分工一下 两个方式 同时开始。
小插曲:
为什么 不可以 把js代码放在jsp 或者html中,通过http的方式调用 获取返回的结果?
首先 把js代码放在jsp 或者html中,获取执行结果。
jsp是在 服务器端就执行好了,js代码是浏览器中执行的;
http访问的是服务器,中间没有经过浏览器,就是说 页面中jsp的代码 执行了,但是js代码是不会有机会执行。
其次:http访问jsp或者html 返回的是服务器编译执行后的 结果代码,而这些 页面代码 在通过浏览器 执行后,呈现给用户;
用户才看到的是 华丽的页面;
所以这里 不清楚 web编程 和 html js css 解析渲染时机的 同学要注意了。
所以 把js代码 挂在 web容器中 再访问 是不能解决这个问题,因为 中间 同样没有浏览器内核。
虽然 以为在浏览器 访问 web地址 可以看到 结果;但是 用java http 后台访问 是不行滴。
我来继续寻找,浏览器内核的解决方式。
这时想起了 web自动化测试的方案,曾经看到测试的同事 用java编写 web自动化测试的脚本;
可以通过 java代码打开浏览器进行 元素定位,数值校验,逻辑登陆 结果校验。。
百度了一下:WEB 自动化测试工具 看到了 selenium web自动化测试工具套
可以看看 这个文章 ,搭建环境示例 :http://blog.csdn.net/kash_chen007/article/details/40586067
逻辑是这样的:
java 通过 selenium 工具套件,结合 本地的 浏览器驱动 与 本地的 浏览器 进行交互,来 模拟操作;
达到的效果是:
java 通过 selenium 可以打开 chrome/firefox/IE等浏览器 (装不同的驱动,打开不同的浏览器)
java 通过 selenium 打开浏览器 输入网址,获取 浏览器解析之后的 结果。
还可以通过 元素定位 ,元素解析的方式,获取指定区域的 数据。
好了 ;
原理问题解决了,废话少说 ,上代码:
方式1,显示调用;
方式2,后台执行,用于部署到正式环境(这个方式不需要依赖驱动包和本地浏览器,有jar包即可)
/*** 方式1;使用 ChromeDriver 显式调用 浏览器* 当然这里 也可以用firefox IE等其他 浏览器和diver,下载不同的浏览器和驱动即可* java 通过 selenium 工具套-->打开本地浏览器-->输入html文件地址(支持远程和本地)-->执行html中的脚本代码-->获取结果* 这里 获取的结果 不是 html代码,而是 在浏览器解析完html js代码之后展示的信息(这里可能不太好理解,一会我画个图 单独描述下,html js jsp执行的时机问题)* 详细描述:* java通过 selenium 工具套 ,让js脚本在浏览器内核中执行,然后 获取返回结果* 这样就解决了 java ScriptEngine 不支持浏览器内置对象的问题* 如此一样js代码 与实际web运行的环境一样执行* @throws Exception*/@Testpublic void testSelenium0() throws Exception {// 第一步:因为是 使用chromediver所以 需要先安装chrome浏览器,chromediver// 这个博客介绍的很详细,地址:https://www.testwo.com/blog/6931// 第二步:设置环境变量System.setProperty("webdriver.chrome.driver","C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe");ChromeDriver webDriver = new ChromeDriver();long start = System.currentTimeMillis();// 第三步:设置访问地址//----// 这里和浏览器 地址栏目 可以输入的 地址一样 支持 远程地址 和 本地地址//webDriver.get("http://www.51jdy.cn");//webDriver.get("http://localhost:8080/web/Noname2.html?pwd=98912&username=halou");webDriver.get("file:///Users/guangtaozhai/Documents/workspace/web/WebContent/Noname2.html?pwd=98912&username=halou");// 第四步:获取输出信息;html中的js代码执行后 在body中document.write()或者 赋值给body或者div// 元素定位 获取 <html> 中<body> 下面的 内容WebElement webElement = webDriver.findElement(By.xpath("/html/body"));System.out.println(webElement.getText());System.out.println("耗时:"+(System.currentTimeMillis()-start));///---webDriver.close();}/*** 方式2:隐式调用(java 后台调用浏览器/selenium/webdriver)* 因为 方式1 会打开本地浏览器,这样一是速度慢,二是 不满足后台执行的方式 比如 部署在linux服务器上以后* 方式2 通过 selenium 提供的 HtmlUnitDriver 进行后台调用;执行效率大幅上升* @throws Exception*/@Testpublic void testSelenium1() throws Exception {// 使用HtmlUnitDriver 是不需要 安装 浏览器 和 驱动支持HtmlUnitDriver webDriver = new HtmlUnitDriver();webDriver.setJavascriptEnabled(true); // 设置支持 js脚本解析 ,是不是跟 安卓的 webview设置很像?long start = System.currentTimeMillis();//---- // 这里和浏览器 地址栏目 可以输入的 地址一样 支持 远程地址 和 本地地址//webDriver.get("http://www.51jdy.cn");//webDriver.get("http://localhost:8080/web/Noname2.html?pwd=98912&username=halou");webDriver.get("file:///Users/guangtaozhai/Documents/workspace/java2js/WebContent/Noname2.html?pwd=98912&username=halou");WebElement webElement = webDriver.findElement(By.xpath("/html/body"));System.out.println(webElement.getText() );System.out.println(System.currentTimeMillis()-start);///---webDriver.close();}
注意:
在实际开发的时候 最好 单独 起一个项目,发布成服务的方式;
1,单独项目 避免jar包冲突,在实际 开发的时候 我遇到了这个问题,企图通过maven 解决 也没有搞定。
2,发布成独立服务 避免了 性能问题 影响其他业务代码,这个 还是比较 耗费资源的。
项目测试代码git地址:https://git.oschina.net/s9/jdy-test
项目关键字:
java调用js
ScriptEngine
ScriptEngine不支持浏览器内置对象window,document等
selenium
Selenium Webdriver
web自动化测试
java打开浏览器执行并获取结果
java调用浏览器内核执行js
ChromeDriver
HtmlUnitDriver
java后台调用浏览器内核
web爬虫
selenium remote
Caused by: java.lang.ClassNotFoundException: org.openqa.selenium.remote.SessionNotFoundException
Selenium Webdriver 的使用java执行js代码 解决 ScriptEngine不支持浏览器内置对象window,document的问题相关推荐
- java零碎要点013---JAVA执行js_java执行JavaScript_java执行js引擎不能识别document浏览器内置对象解决办法
执行方法很简单,简单记录一下: 在做项目中有时候需要用到Java调用js文件执行相应的方法 JAVA技术交流QQ群:170933152 在JDK1.6添加了新的ScriptEngine类,允许用户直 ...
- jsp 将页面中的值导入java中_JavaWeb - JSP:概述和语法,内置对象,JavaBean 组件,MVC 设计模式
JSP 的概述 概念 JSP 是 Java Server Pages 的简称,跟 Servlet 一样可以动态生成 HTML 响应, JSP 文件命名为 xxx.jsp. 与 Servlet 不同,J ...
- js浏览器内置对象和js内置对象
浏览器内置 1.Location 对象 hash :返回一个URL的锚部分 host 返回一个URL的主机名和端口 hostname 返回URL的主机名 href 返回完整的URL pathname ...
- js引擎执行js代码的过程
js引擎执行js代码的过程 html解析 浏览器下载网页时,浏览器内核解析html.当遇到script标签时,下载js代码并将js代码以流的形式传递给js引擎让js引擎进行js代码的解析. 语义语法分 ...
- JS的对象与内置对象详细介绍
感谢内容提供者:金牛区吴迪软件开发工作室 文章目录 前言 一.基本对象Object: 二.内置对象之Array: 三.内置对象之Math: 四.内置对象之Number: 五.内置对象之String: ...
- 爬虫之selenium控制浏览器执行js代码
爬虫之selenium控制浏览器执行js代码 selenium可以让浏览器执行我们规定的js代码,运行下列代码查看运行效果 import time from selenium import webdr ...
- Python爬虫之selenium对标签页切换、切换frame标签、cookie处理、执行js代码、开启无界面、以及使用代理ip和替换user-agent等方法
一.selenium对标签页切换.切换frame标签.cookie处理.执行js代码.开启无界面.以及使用代理ip和替换user-agent等方法 (一).selenium标签页的切换 当seleni ...
- 什么?java中居然可以执行js代码了?真是不知者不怪
今天在书上看的,java中可以直接调用js的函数了,言外之意就是java已经支持外部的脚本语言了(在运行期解释执行的),查了查,jdk从1.6之后开始支持的,1.6之前不可以. 为什么Java这种编译 ...
- Java脚本引擎执行js代码以及动态编译
Java脚本引擎执行js代码 一.概述 JAVA脚本引擎是从JDK6.0之后添加的新功能. 使得 Java 应用程序可以通过一套固定的接口与各种脚本引擎交互,从 而达到在 Java 平台上调用各种脚本 ...
最新文章
- 使用正则表达式进行高效的测试
- freemarker了解
- mysql 文件描述符_MySQL没有发布临时文件描述符
- cent os重置mysql,linux mysql 能登陆不能修改用户(cent os 6.2)解决思路
- Java堆转储:您可以完成任务吗?
- 基于无线通信技术的智能公交系统设计
- win10安装RabbitMQ
- dao.php,DAO.php · Dodd/Training Lab - Gitee.com
- 微型计算机由5大部分,微机原理答案 (5)
- 二分法:木棒切割问题
- 教职工使用计算机管理制度,教师配置笔记本电脑管理办法
- 完整安装sqlserver always on集群
- 基于springboot的社区核酸检测统计管理系统
- numpy复习总结,为深度学习打下基础
- 宝塔面板安全入口登录问题
- 编个故事,骗700元的稿费真容易啊!
- transferTo和transferFrom
- ReportViewer动态加载报表文件
- AUI_Js脚本_Jira多选下拉列表前端样式优化
- Android开机流程