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 */ @Test public 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 */ @Test public 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
*/
@Test
public 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
*/
@Test
public 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 掉用js程式碼,發現 ScriptEngine不支援瀏覽器內建物件window,document的問題; 問題一:為什麼要 用java掉用js程式碼? 比如在 抓取(爬取)對方網站時,需要破解一些js邏輯程式碼合作加密演算法,但是js混淆了
在selenium(webdriver)中執行js
程式碼 JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript(String script, object...
JS封閉函式、閉包、內建物件
1、全域性變數:在函式之外定義的變數,為整個頁面公用,函式的內部外部都可以訪問。 2、區域性變數:在函式內部定義的變數,只能在定義該變數的函式內部訪問,外部無法訪問。函式內部訪問變數時,先在內部查詢是否有此變數,如果有,就使用內部,如果沒有,就去外部查詢 二、封閉函式 封閉函
selenium執行js程式碼,滑動頁面滾動條
1.滾動頁面底部 js="var q=document.getElementById('id').scrollTop=10000" driver.execute_script(js) 2.滾到頁面頂部 js="var q=document.
系統休眠或瀏覽器不是當前活動狀態,不執行js的解決思路
color pan 瀏覽器 原生開發 可用 繼續 gettime != inter 手機端原生開發,當前頁面從系統中被喚起會有相應的事件觸發。但webapp確無法獲取。 基於瀏覽器自身規則,在系統休眠或著瀏覽器不處於當前活動狀態是,js是不執行的。 那麽如果想讓頁面能及時更
回車鍵 執行js程式碼 {鍵盤事件}
onkeypress=function(event){ if(event.keyCode == 13){ $('#btn').click(); } }; 完整 程式碼 <!doctype html>
firefox瀏覽器下href執行js程式碼
firefox瀏覽器裡,標籤a的href執行js程式碼時不能執行臺複雜的語句,只能執行單語句程式碼。即href="javascript: func1();func2();",此時可能會出錯。 href="javascript:funct1()"可以正確執行。如果非要執行復雜的
java執行bat程式碼
java執行bat程式碼.txt public static void runbat(String path,String filename) { String cmd = "cmd /c start"+path+"/"+filename; //String cmd = "cmd
怎麼在chrome的位址列中執行js程式碼
crtl+shift+j chorme自帶的開發人員工具 console+log可以直接輸出指令碼程式碼 javascript:alert("js")或者confirm("js");可以直接打印出
建立並執行Java執行時程式碼的三種方式
1 概述 在Java中,建立執行緒執行時程式碼有三種方式。 第一種:繼承Thread類,覆寫其run方法,這種方式我們在之間的案例中已經見過。 第二種:實現Runnable介面,實現run方法,Thread類也實現了Runable介面。 第三種:實現Call
幾種自動執行js程式碼的方式
最近在看jquery,發現他居然能自動執行js程式碼,於是就查了下,收集了幾種常用的實現方法 jquery的方法 使用場景:任何需要執行的js特效 $(document).ready(fu
Selenium2(WebDriver)中執行JavaScript程式碼
在用selenium編寫web頁面的自動化測試程式碼時,可能需要執行一些JavaScript程式碼,selenium本身就支援執行js,我們在程式碼中可以使用executeScript、executeAsyncScript這兩個方法來執行JS。 exec
JS_實現頁面載入完再執行JS程式碼
1 在body中用onload: <body onload="myfunction()"> 2 在指令碼中用window.onload: <script type="text/javascript"> function myfun() { alert("this window
python+selenium對網頁執行js指令碼報錯“$ is not defined”
背景 在python裡用selenium模擬瀏覽器的時候需要傳送一個POST請求,我用的是webdriver的execute_script方法,對頁面執行下面的js程式碼來獲取資料 $.post(........) 然後執行的時候報錯 “$ is no
javac編譯成功,用java執行class檔案出現“找不到或無法載入主類” 的問題解決起來很簡單
avac編譯成功,用java執行class檔案出現“找不到或無法載入主類” 的問題所在很簡單 學習android,順便又學習下java. 入門就遇到這樣的問題,環境變數按網上說的配好了,直接java 和 javac都有提示出來,說明沒問題了, 做了一個簡
原生JS實現DOM載入完成馬上執行JS程式碼
用原生JS我們經常使用window.onload事件來載入頁面。但是window.onload是在頁面元素都載入完畢後才執行,如果頁面內有大的圖片的話,會在頁面展現後好久時間後才執行。所以有時我們需要在DOM載入時馬上執行一些函式。jQuery提供了document.rea
WebView 無法執行js程式碼
下午在研究webView 與js之間的呼叫,於是到w3school上找了一個html的頁面。 html頁面: <html> <head> <script type="text/javascript"> function show
17-Python執行JS程式碼--PyExecJS、PyV8、Js2Py
一、Python執行JS程式碼--PyExecJS、PyV8、Js2Py 1.1、PyExecJS PyExecJS的優點是您不需要照顧JavaScript環境。特別是,它可以在Windows環境中執行,而無需安裝額外的庫。PyExecJS的缺點之一是效能。PyExecJS通過文字傳達JavaScript
win10配置java環境變數,解決javac不是內部或外部命令等問題
昨天重灌了win10系統,發現以前配好的java環境變數和tomcat環境變數全都清空了,在重新配置的時候總是出現問題,即在cmd命令視窗下,輸入java,顯示正常,輸入java -version 也是顯示正常,唯獨輸入javac,顯示“javac不是內部或外部命令,布拉布拉
解決laravel執行資料庫遷移檔案修改不支援enum型別的方法
報錯如下: In AbstractPlatform.php line 423: Unknown database type enum requested, Doctrine\DBAL\Platforms\MySQL57Platform may not support it.