获取JavaFX WebEngine解释文档

时间:2014-10-25 12:29:46

标签: javafx domdocument javafx-webengine

对我来说,在WebEngine对象上调用getDocument()方法只返回从服务器检索到的源,而不执行JavaScript(仍有元素)。如果您使用"查看来源"这是您会看到的那种来源。在Chrome中。如何在已运行JavaScript的情况下检索已解释的源?

public Browser() {
    WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();
    webEngine.load("*******************************");

    webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
        @Override
        public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
            if (newState == State.SUCCEEDED) {
                Document doc = webEngine.getDocument();
                printDocument(doc);
            }
        }
    });
}

4 个答案:

答案 0 :(得分:1)

这对我来说是预期的。在此示例中,div包含一个文本节点,其文本由Javascript函数设置:

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class WebViewOnLoadExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        WebView webView = new WebView();
        webView.getEngine()
            .getLoadWorker()
            .stateProperty()
            .addListener((obs, oldState, newState) -> {
                if (newState == Worker.State.SUCCEEDED) {
                    Document doc = webView.getEngine().getDocument();
                    showNodeContent(doc, 0);
                }
            });
        BorderPane root = new BorderPane(webView);
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();

        webView.getEngine().loadContent("<html>"
                +"<head><script>"
                +"function setText() {"
                +"  document.getElementById(\"target\").appendChild(document.createTextNode(\"Hello World\"));"
                +"}"
                +"</script></head>"
                +"<body onload='setText()'>"
                +"<div id='target'></div></body></html>");
    }

    private void showNodeContent(Node n, int depth) {
        for (int i=0; i<depth; i++) {
            System.out.print(" ");
        }
        System.out.println(n.getNodeName()+":"+n.getNodeValue());
        NodeList children = n.getChildNodes() ;
        for (int i=0; i<children.getLength(); i++) {
            showNodeContent(children.item(i), depth+1);
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

答案 1 :(得分:1)

您遇到的问题如下:在JavaScript运行完成之前,LoadWorker的状态设置为SUCCEEDED。 JavaScript 确实实际上正在运行(如@ James_D&#39;回复中所示),但完成后没有回调信号。 AFAIK,没有可靠的方法来检测WebEngine何时执行JS。

你可以做的解决方法是在状态更改为SUCCEEDED之后播放PauseTransition,这可能会被滥用来像JavaFX线程上的sleep一样(JS在后台线程中执行)也会加载Document,所以JS不会暂停)。但是,休眠(等待JS完成)本质上违反了JavaFX的核心原则从不来阻止UI线程。最重要的是,等待一段时间并不能保证JS在该时间段过去之前完成执行。

我遇到了同样的问题而我找不到合适的解决方案。如果你这样做,请告诉我!

答案 2 :(得分:0)

我不确定我的问题是否正确,但如果您正在寻找方法,请打印正在加载的网络的可见内容,从DocumentElement获取Document {1}}允许您深入了解其结构并过滤所需内容。

此方法将打印所需标签的内容:

private void printElement(Element el, int level){
    NodeList childNodes = el.getChildNodes();
    for(int j=0; j<level; j++) System.out.print("-");
    System.out.print("tag: "+el.getNodeName());
    if(el.getNodeName().equals("A")){
        System.out.print(", content: "+el.getTextContent());
    } 
    System.out.println("");
    for(int i=0; i<childNodes.getLength(); i++){
        Node item = childNodes.item(i);
        if(item instanceof Element){
            printElement((Element)item, level++);
        }
    }
}

所以,一旦您加载了网址,只需将其命名为:

if(newState==State.SUCCEEDED){
    Document doc = webEngine.getDocument();
    Element el = doc.getDocumentElement();
    printElement(el,0);
}

这将打印所有带有缩进级别的DOM标记,对于指定的标记,它也会打印内容。在这种情况下,使用标签&#34; A&#34;它会打印所有链接的内容。

我不确定这是否有帮助。请另外澄清您的问题。

答案 3 :(得分:0)

正如Warkst指出:
在JavaScript运行完成之前,LoadWorker的状态设置为SUCCEEDED。

你能做的是:
从JavaScript回调Java

public class JavaApplication {
   public void exit() {
      Platform.exit();
   }
}
...
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new JavaApplication());

然后,您可以从HTML页面引用对象和方法:

<a href="" onclick="app.exit()">Click here to exit application</a>

或放在HTML的末尾:

...

<script>
// self executing function here
(function() {
   app.exit();
})();
</script>

</body>
</html>

见这里:http://docs.oracle.com/javafx/2/api/javafx/scene/web/WebEngine.html