【问题标题】:Selenium get HTML (or JSON) response from WebDriverSelenium 从 WebDriver 获取 HTML(或 JSON)响应
【发布时间】:2014-10-06 17:28:22
【问题描述】:

我有以下代码,但它不工作

public static String getHTMLResponse(String url){
   String body = (String) js.executeScript("$.ajax({url:\""+ url + "\", success:function(result){ return result;}});");
    return body;
}

由于某种原因,它总是返回 null。

有没有人尝试从 webdriver 中的 ajax 获得 CURL 响应?我以前在 java 中这样做过,但我不断收到证书错误,只是想要更可靠的东西。

提前谢谢!

【问题讨论】:

    标签: java ajax json selenium selenium-webdriver


    【解决方案1】:

    好的,所以 Jason Smiley 发布了一个解决方案,但没有解释问题是什么以及解决方案的工作原理。

    第一个问题是传递给executeScript 的脚本没有返回任何内容,句号。 executeScript 所做的是将传递给它的脚本包装在 function () { ... } 中。所以$.ajax(...) 形式的东西会在浏览器中这样执行:

    function () {
        $.ajax(...);
    }
    

    这显然不会返回任何东西,就像如果脚本是 2 + 2 它不会返回 4 因为它会执行为:

    function () {
        2 + 2;
    }
    

    传递给executeScript 的脚本必须是return 2 + 2

    但是,在这里,仅添加此 return 并不能解决问题。还有一个问题是$.ajax 是一个异步函数。当$.ajax 执行时,它立即返回。传递给它的函数被存储以供将来执行。如果$.ajax 立即返回,那么它返回的值可能不可能是任何提供给它的函数的返回值,因为这些函数还没有执行。相反,传递给$.ajax 的函数会执行,无论它们提供给return 的任何内容都无法通过您的 代码检索。您唯一能做的就是在函数本身内部使用您关心的值或将其传递给另一个函数。

    解决方案是使用为异步执行而设计的executeAsyncScript。此函数与executeScript 类似,但添加了一个回调参数,该参数应在脚本完成执行时调用,并且应使用您希望executeAsyncScript 返回的值来调用它。

    请注意,绝对没有必要放弃$.ajax。以下应该有效:

    public static String getHTMLResponse(String url){
        String body = (String) js.executeAsyncScript(
            "var url = arguments[0];" + 
            "var callback = arguments[1];" +
            "$.ajax({url: url, success: callback});", 
            url);
        return body;
    }
    

    请注意,我已设置此代码,以便 url 作为参数传递,而不是连接到脚本中。我发现这比串联更干净。如果需要对此进行解释,arguments 是 JavaScript 虚拟机自动提供的对象。它保存给函数的参数列表。

    无论是使用$.ajax还是直接使用XMLHttpRequest,原理都是一样的。

    【讨论】:

    • 谢谢路易斯!我没有在票证中提到这一点,但实际上我有一些 OP 脚本的变体。我可以说没有任何东西被退回,我想我不知道为什么没有任何东西被退回。例如,为什么“成功:回调”有效,而不是“成功:返回参数 [1]”或“成功:函数(){返回参数 [1]}”。很确定其中一个没有编译,但我不记得哪个大声笑
    【解决方案2】:

    前端开发人员给了我脚本!

       public static String getHTMLResponse(String url){
          String body = (String) js.executeAsyncScript(
                "var callback = arguments[arguments.length - 1];" +
                        "var xhr = new XMLHttpRequest();" +
                        "xhr.open('GET', '"+ url + "', true);" +
                        "xhr.onreadystatechange = function() {" +
                        "  if (xhr.readyState == 4) {" +
                        "    callback(xhr.responseText);" +
                        "  }" +
                        "};" +
                        "xhr.send();");
          return body;
      }
    

    【讨论】:

    • 实际上不再是 - 我不得不改变它。将添加一个新的答案
    【解决方案3】:

    从长远来看,上面的代码并没有为我工作。我不记得为什么它不起作用(因为已经有一段时间了),但这是我的新答案:

    /**
     * CURLs the page passed in for the HTML response. Uses AJAX so base domain must match the url.
     *
     * Special exception for MkItem requests
     *
     * @param url   - URL to CURL
     * @param debug - Pass in true for debug output.
     * @return HTML result as a string.
     * @throws IOException
     */
    public static String getHTMLResponse(String url, boolean debug) throws IOException {
        if(debug){System.out.println("Making request to:\n\n" + url);}
        String body = "";
    
        try{
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
    
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
    
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }
            };
    
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    
            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
    
            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        }catch (Exception e){
            Assert.fail("Exception thrown trying to perform GET request. " + e.getMessage());
        }
        URLConnection con;
    
        //If not a secure page, use cURL
            /*if(!url.contains("https://")){*/
            try{
                URL temp = new URL(url);
                con = temp.openConnection();
                InputStream in = con.getInputStream();
                String encoding = con.getContentEncoding();
                encoding = encoding == null ? "UTF-8" : encoding;
                body = IOUtils.toString(in, encoding);
            } catch (MalformedURLException e){
                Assert.fail("URL wasn't passed in correctly - " + e.getMessage());
            } catch (IOException e){
                throw e;
            }
    
        if(debug){ System.out.println("Body:\n"+ body); }
    
        Assert.assertNotNull("Body returned null for " + url, body);
    
        return body;
    }
    

    【讨论】:

    • 注意,我现在只是关闭安全证书检查。减少与 HTTP 和 HTTPS 功能相关的麻烦。
    • 这对您原来的问题有何回答?您在问题中没有提到任何关于 ssl 的内容。
    猜你喜欢
    • 2015-06-13
    • 1970-01-01
    • 2018-02-03
    • 2022-06-28
    • 2011-09-24
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 2012-05-25
    相关资源
    最近更新 更多