JavaFX2.0のWebEngineを使ってサイトのリンク一覧を取得する

JavaFX2.0では、WebKitのラッパが含まれるようになったわけですが、当然WebKitのHTMLパーサーが解析したDOMを操作することもできます。
ということで、サイト中のaタグを取得してみました。こんな感じでリンクが取れてます。サイトの画面表示はおこなってません。

http://www.oracle.com/
Sign In/Register for Account
http://www.oracle.com/webapps/redirect/signon?nexturl=http://www.oracle.com/technetwork/java/index.html
Help
→/us/corporate/contact/about-your-account-070507.html
United States
→#
Brazil
http://www.oracle.com/technology/global/lad-pt/index.html
China
→/technetwork/cn/index.html
Japan
http://www.oracle.com/technetwork/jp/index.html



ただ、JavaFXのアプリケーションスレッドで動かす必要があったり、読み込み後のonLoadなどのJavaScriptが動いてしまったり、HTML解析用途としては便利ではありません。
とはいえ、WebKit水準の解析ができるので、特に日本語の文字化けに強くてありがたいかもしれません。


JavaFXのWebEngineを、こういったHTML解析に使うという要望は多くなっていくと思うので、そのうち使いやすくなるのかも。


ソースです。クラスパスにjfxrt.jarを含めて、64bit Windowsの場合でも32bit JDKで動かす必要があります。
TmpFxLauncher.launchは、そのうち不要になるというようなことが、JavaFXのサンプルのコメントに書いてありました。
WebEngineを使う処理はPlatform.runLaterでJavaFXのスレッドで動かす必要があるみたいです。
あと、処理が終わったときに Platform.exitしないと、JavaFXのスレッドが残りっぱなしになります。Platform.exitでは、メインスレッドも終わってしまうので注意です。

package javafxapplication;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.async.Task;
import javafx.async.TaskEvent;
import javafx.event.EventHandler;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class LinkList{

    public static void main(String[] args) {
        //この処理はそのうち不要になるらしい
        TmpFxLauncher.launch();

        //WebEngineはJavaFXのスレッドで動かす必要がある。
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
        
                final WebEngine engine = new WebEngine("http://www.oracle.com/technetwork/java/index.html");

                Task<Void> task = engine.getLoadTask();
                task.setOnDone(new EventHandler<TaskEvent>() {
                    @Override
                    public void handle(TaskEvent event) {
                        NodeList titles = engine.getDocument().getElementsByTagName("a");
                        for(int i = 0; i < titles.getLength(); ++i){
                            Node item = titles.item(i);
                            //リンクテキストを取得
                            String caption = item.getTextContent();
                            if(caption == null) caption = "";
                            caption = caption.trim().replaceAll("\\s+", " ");
                            //リンク先を取得
                            String link = item.getAttributes().getNamedItem("href").getTextContent();
                            //表示
                            System.out.printf("%s%n →%s%n", caption, link);
                            
                        }
                        //JavaFXスレッドごと終了させる
                        Platform.exit();
                    }
                }); 
            }
        });
    }
    
    public static class TmpFxLauncher extends Application {
        @Override public void start(Stage primaryStage) {
        }

        private static void launch() {
            Application.launch(null);
        }
    }        
}