3

对我来说,在 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

3 回答 3

2

这对我来说按预期工作。在此示例中,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);
    }
}
于 2014-10-26T01:28:09.607 回答
1

您面临的问题如下:LoadWorker' 的状态设置为SUCCEEDED在 JavaScript 完成运行之前。JavaScript实际上确实在运行(如@James_D 的回复所示),但是当它完成时没有回调来发出信号。AFAIK,没有可靠的方法来检测 WebEngine 何时完成执行 JS。

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

我遇到了同样的问题,我还没有找到一个像样的解决方案。如果你这样做,请告诉我!

于 2015-03-09T15:54:27.213 回答
0

我不确定我的问题是否正确,但是如果您正在寻找一种方法来打印您正在加载的网络的可见内容,那么获取DocumentElementfromDocument将允许您深入了解其结构并过滤您需要的内容.

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

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++);
        }
    }
}

因此,一旦您加载了 URL,只需调用它:

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

这将打印所有 DOM 标签及其缩进级别,并且对于指定的标签,它还将打印内容。在这种情况下,使用标签“A”它将打印所有链接的内容。

我不确定这是否会有所帮助。否则请澄清您的问题。

于 2014-10-25T13:57:58.773 回答