用于显示网页和返回HTML的Java GUI

时间:2013-11-18 15:31:57

标签: java swing browser javafx-2 javafx

我需要一个如下工作流程:

// load xyz.com in the browser window
// the browser is live, meaning users can interact with it
browser.load("http://www.google.com");

// return the HTML of the initially loaded page
String page = browser.getHTML();

// after some time
// user might have navigated to a new page, get HTML again
String newpage = browser.getHTML();

我很惊讶地看到Java GUI如JavaFX(http://lexandera.com/2009/01/extracting-html-from-a-webview/)和Swing有多么困难。

是否有一些简单的方法可以在Java中获得此功能?

6 个答案:

答案 0 :(得分:8)

这是一个使用JavaFX的人为例子,它将html内容打印到System.out--它不应该太复杂,无法适应创建getHtml()方法。 (我已经使用JavaFX 8进行了测试,但它也适用于JavaFX 2。)

每次加载新页面时,代码都会打印HTML内容。

注意:我借用了this answer中的printDocument代码。

public class TestFX extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        try {
            final WebView webView = new WebView();
            final WebEngine webEngine = webView.getEngine();

            Scene scene = new Scene(webView);

            stage.setScene(scene);
            stage.setWidth(1200);
            stage.setHeight(600);
            stage.show();

            webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
                @Override
                public void changed(ObservableValue<? extends State> ov, State t, State t1) {
                    if (t1 == Worker.State.SUCCEEDED) {
                        try {
                            printDocument(webEngine.getDocument(), System.out);
                        } catch (Exception e) { e.printStackTrace(); }
                    }
                }
            });

            webView.getEngine().load("http://www.google.com");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8")));
    }

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

答案 1 :(得分:4)

您将在下面找到一个SimpleBrowser组件,其中Pane包含WebView

Source code at gist.

样本用法:

SimpleBrowser browser = new SimpleBrowser()
          .useFirebug(true);    

// ^ useFirebug(true) option - will enable Firebug Lite which can be helpful for 
// | debugging - i.e. to inspect a DOM tree or to view console messages 

Scene scene = new Scene(browser);

browser.load("http://stackoverflow.com", new Runnable() {
    @Override
    public void run() {
        System.out.println(browser.getHTML());
    }
});

browser.getHTML()放在Runnable内,因为需要等待网页下载和渲染。尝试在页面加载之前调用此方法将返回一个空页面,因此将其包装到runnable中是一种简单的方法,我想出来等待页面加载。

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.scene.layout.*;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

public class SimpleBrowser extends Pane {
    protected final WebView webView = new WebView();
    protected final WebEngine webEngine = webView.getEngine();

    protected boolean useFirebug;

    public WebView getWebView() {
        return webView;
    }

    public WebEngine getEngine() {
        return webView.getEngine();
    }

    public SimpleBrowser load(String location) {
        return load(location, null);
    }

    public SimpleBrowser load(String location, final Runnable onLoad) {
        webEngine.load(location);

        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> ov, Worker.State t, Worker.State t1) {
                if (t1 == Worker.State.SUCCEEDED) {
                    if(useFirebug){
                        webEngine.executeScript("if (!document.getElementById('FirebugLite')){E = document['createElement' + 'NS'] && document.documentElement.namespaceURI;E = E ? document['createElement' + 'NS'](E, 'script') : document['createElement']('script');E['setAttribute']('id', 'FirebugLite');E['setAttribute']('src', 'https://getfirebug.com/' + 'firebug-lite.js' + '#startOpened');E['setAttribute']('FirebugLite', '4');(document['getElementsByTagName']('head')[0] || document['getElementsByTagName']('body')[0]).appendChild(E);E = new Image;E['setAttribute']('src', 'https://getfirebug.com/' + '#startOpened');}");
                    }
                    if(onLoad != null){
                        onLoad.run();
                    }
                }
            }
        });

        return this;
    }

    public String getHTML() {
        return (String)webEngine.executeScript("document.getElementsByTagName('html')[0].innerHTML");
    }

    public SimpleBrowser useFirebug(boolean useFirebug) {
        this.useFirebug = useFirebug;
        return this;
    }

    public SimpleBrowser() {
        this(false);
    }

    public SimpleBrowser(boolean useFirebug) {
        this.useFirebug = useFirebug;

        getChildren().add(webView);

        webView.prefWidthProperty().bind(widthProperty());
        webView.prefHeightProperty().bind(heightProperty());
    }
}

演示浏览器:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.stage.Stage;

public class FXBrowser {
    public static class TestOnClick extends Application {


        @Override
        public void start(Stage stage) throws Exception {
            try {
                SimpleBrowser browser = new SimpleBrowser()
                    .useFirebug(true);

                final TextField location = new TextField("http://stackoverflow.com");

                Button go = new Button("Go");

                go.setOnAction(new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent arg0) {
                        browser.load(location.getText(), new Runnable() {
                            @Override
                            public void run() {
                                System.out.println("---------------");
                                System.out.println(browser.getHTML());
                            }
                        });
                    }
                });


                HBox toolbar  = new HBox();
                toolbar.getChildren().addAll(location, go);

                toolbar.setFillHeight(true);

                VBox vBox = VBoxBuilder.create().children(toolbar, browser)
                    .fillWidth(true)
                    .build();


                Scene scene = new Scene( vBox);

                stage.setScene(scene);
                stage.setWidth(1024);
                stage.setHeight(768);
                stage.show();

                VBox.setVgrow(browser, Priority.ALWAYS);

                browser.load("http://stackoverflow.com");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

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

答案 2 :(得分:0)

没有一个简单的解决方案。事实上,甚至没有一个解决方案可以构建自己的浏览器。

关键问题是互动。如果您只想显示内容,那么JEditorPane和许多第三方库将使其成为更容易实现的目标。如果您真的需要用户与网页进行交互,请:

  • 让用户使用普通浏览器进行互动
  • 构建一个GUI,调用Web服务/网址进行交互,但显示由您决定。

在返回HTML方面,听起来好像是在尝试捕获历史记录或刷新页面。在任何一种情况下,听起来你都是错误的技术。修改原始站点,或在浏览器中使用Greasemonkey或类似的东西添加一些java脚本。

答案 3 :(得分:0)

您可能希望查看djproject。但可能你会发现JavaFX的使用更容易。

答案 4 :(得分:0)

根据我不了解您的项目的内容,这可能是天真的或愚蠢的,但您可以使用真正的浏览器并使用Selenium Webdriver进行检测。只能从另一个答案中看出这一点,即你走的是一条艰难的道路。

还有一个关于使用webdriver here提取html的问题。这是关于使用python,但webdriver也有一个java api。

答案 5 :(得分:0)

我能够获得执行的html。将html加载到JavaScript中后,我保留了Alert语句。我使用webEngine.setOnAlert方法检查警报是否已执行,然后打印html。我得到了正确的答复。下面是代码

HTML

alert("ready");

JavaFx应用程序

webEngine.setOnAlert(new EventHandler<WebEvent<String>>(){

                        @Override
                        public void handle(WebEvent<String> event) {
                            //labelWebTitle.setText(webEngine.getTitle());
                             if("ready".equals(event.getData())){
                                 //TODO: initialize
                                 System.out.println("HTML Ready");
                                 WebEngine engine = (WebEngine)event.getSource();
                                 String html = (String) engine.executeScript("document.documentElement.outerHTML");
                                 org.jsoup.nodes.Document doc = Jsoup.parse(html);
                                 Element image = doc.getElementById("canvasImage");
                                 System.out.println(image.attr("src"));
                            }
                        }

                    });