JavaFX和可视化信息抽取

1、阅读说明

        本篇博客是非介绍类的,即,不含有关于JavaFX的基础介绍。博客主要描述实现可视化信息抽取时,如何利用JavaFX的WebView组件。仅介绍涉及到的JavaFX的内容,至于可视化信息抽取的算法是哪个,博客不进行介绍,提供的源码中有一个可视化信息抽取的演示Demo,Demo不涉及到核心算法,是基于定制规则进行抽取的。
        博客内容是我毕业设计(基于反馈学习的半结构化信息抽取研究及应用)可能涉及到的基础技术的准备和总结,技术准备的时间较短,同时心里着急找工作(真心着急。。。),里面可能有不正确的,如有发现,请指正,同时提醒,本博客内容只是作为技术实现的可行tips,千万不要作为标准样板,关于某些问题,如果您有发现新的解决方案,请您一定要告诉我一下,非常感谢!

2、主要解决的问题

  1. 如何获取WebView渲染后网页中元素的基本信息,比如x,y坐标、字体大小、字体颜色、背景色等等;
  2. 如果用TreeView绑定DOM树,同时实现右键TreeView时,查看元素的基本信息或者高亮指定元素;
  3. 如果直接通过右键浏览器界面来高亮点击的元素;
  4. 如何获取WebView的滚动条对象、滚动条的宽度和判断滚动条的方向;
  5. 如何在拖拽窗体、最大化窗体等改变窗口大小时,获取WebView中的元素坐标位置;
  6. 对于已生成的Document文档对象,如何在Java中监听网页中对应DOM树的结构的变化;
  7. 如何对JavaFX生成的DOM对象,进行XPath操作;
  8. Java如何执行WebView渲染网页中的按钮自动点击操作,比如“下一页”自动点击下一页,“百度一下”自动进行搜索。

3、尚未完全解决的问题

  • 网页随着滚动条滚动加载时,如何快速让网页滚动至网页底部,使其加载完全(因为滚动条不止滚动一次,即到底部以后,有可能还需要继续滚动)
  • WebView对象怎么具体识别水平滚动条和垂直滚动条(因为编程过程中,发现WebView有多个ScrollBar对象,有时候多达10多个,如何区分哪两个是有效的,暂时不会)
  • WebView.onScrollProperty().addListener((ChangeListener<? super EventHandler<? super ScrollEvent>>),这个addListener函数如何添加参数,因为<? super EventHandler<? super ScrollEvent>>是嵌套类型的,实现时,总是提示错误,当时解决了,撤销以后,隔天又忘了。

本文涉及到的JavaFX对应的JDK版本是JDK1.7

4、关于JavaFX的基本概念

        关于JavaFX的基本概念,比如,JavaFX UI组件的使用、布局相关、Web组件相关等等,可参考JAVAFX中文资料。这个网页相当于Oracle官方文档的翻译,里面有基础知识介绍,以及相关实现代码,非常推荐。对应英文版入口JavaFX: Getting Started with JavaFXJava Platform, Standard Edition (Java SE) 8相关资料(含JavaFX)JavaFX 2.0的API文档
       JavaFX是和DOM模型以及CSS紧密相结合的。尤其是WebView,获取渲染后的网页内容,一般都是通过执行JavaScript获取的。所以,学习或者利用JavaFX解决相关问题时,一定不要局限于窗体程序思维,一定要记住JavaFX和JavaScript的交互性。我刚开始接触JavaFX,就因为这个,想很多问题时就太死板,浪费很多时间。
    JavaFX事件模型是DOM2事件模型,DOM2事件模型有一个典型的特性,就是事件从“顶层开始捕获,直至目标元素,然后事件相应处理从目标元素冒泡到顶层”(推荐文档:JAVAFX-事件),如下图:

DOM2事件模型
图片引用来自:http://www.csdn123.com/html/topnews201408/5/11405.htm

    之所以要强调DOM2模型,是因为这个特性对于绑定有层次关系的元素结点时,不需要每个结点都进行绑定,只需要绑定根结点就可以了。比如,TreeView是一个典型的层次树形结构,给这个TreeView中的每个TreeItem绑定触发收起事件(collapsed event)时的特殊处理操作时,不需要每一个TreeItem都需要调用addEventHandler函数,而只需要对TreeView的root的TreeItem进行绑定就可以了,在事件里面通过(TreeItem)event.getTarget()来获取被点击的TreeItem或者通过event.getTreeItem()直接获取。参考代码片段如下,完整代码,请看最下面附件。

treeItemParent.addEventHandler(TreeItem.<DOMBox> branchCollapsedEvent(),
        new EventHandler<TreeItem.TreeModificationEvent<DOMBox>>() {
            @Override
            public void handle(TreeItem.TreeModificationEvent<DOMBox> event) {

                TreeItem<DOMBox> tCurrent = event.getTreeItem();
                DOMBox domBox = (DOMBox) tCurrent.getValue();
                if (!ElementTools.isSelfClose(domBox.getTagName())) {
                    String strHtml = domBox.getSelfHtml() + "...</" + domBox.getTagName() + ">";
                    domBox.setSelfHtml(strHtml);
                    TreeItem<DOMBox> tNext = tCurrent.nextSibling();
                    tNext.getParent().getChildren().remove(tNext);
                }
            }
        });

    上述代码片段是实现html树结点展开后的收起功能,如下图:

展开后 -> 收起后

    treeItemParent就是TreeView的根TreeItem。DOMBox是TreeItem关联的数据类型,可以String等任意类型,TreeView在显示TreeItem时,是调用TreeItem关联的数据的toString()函数,本样例就是DOMBox的toString()函数,所以你可以对toString()进行重载来显示自己需要展示的东西
    强调JavaFX和CSS的交互性,是因为可以通过样式表查找元素,或者通过修改样式表来改变原始文档的展示效果。下述代码片段是通过CSS来查找ScrollBar的:

    /**
     * Returns the vertical scrollbar of the webview.
     *
     * @param webView webview
     * @return vertical scrollbar of the webview or {@code null} if no vertical
     * scrollbar exists
     */
    private ScrollBar getVScrollBar(WebView webView) {

        Set<Node> scrolls = webView.lookupAll(".scroll-bar");
        for (Node scrollNode : scrolls) {

            if (ScrollBar.class.isInstance(scrollNode)) {
                ScrollBar scroll = (ScrollBar) scrollNode;
                if (scroll.getOrientation() == Orientation.VERTICAL) {
                    return scroll;
                }
            }
        }
        return null;
    }

    通过WebView的lookup或者lookupAll函数来进行查找相关元素。
    以下是遍历元素结点样式表的代码片段,以ScrollBar为例。

List<CssMetaData<? extends Styleable, ?>> css = scroll.getCssMetaData();
for (int i = 0; i < css.size(); i++) {
   
    CssMetaData<? extends Styleable, ?> oneAttr = css.get(i);
    System.out.print(oneAttr.getProperty() + ":" + ((CssMetaData<ScrollBar, ScrollBar>) oneAttr).getStyleableProperty(scroll).getValue() + "\t");
}
System.out.println(); 

    scroll是ScrollBar对象,其他具有getCssMetaData函数的对象均可如上述进行结点遍历,比如WebView对象。关于JavaFX控件的样式表,可以参考官方文档 JavaFX CSS Reference Guide
    关于JavaFX的布局元素的介绍,除了JAVAFX中文资料中的介绍,再推荐一篇文章,个人感觉很有帮助:JavaFX 2.0 Resizing of UI Controls

5、问题具体解决方案

强烈推荐Stack OverFlow,我的解决方案好像都是在其中看的代码片段知道的。

5.1 如何获取WebView渲染后网页中元素的基本信息,比如x,y坐标、字体大小、字体颜色、背景色等等

    因为毕业设计的信息抽取是基于可视化模块后,进行抽取的,主要是采用VIPS算法进行Page Segment,就是对网页进行分块。VIPS算法进行分块时,需要用到元素的字体大小、背景色、坐标位置等等信息,VIPS的Github上有Java版具体实现vips_java,不过这个版本基于CSSBox实现的,CSSBox不能解析JavaScript,只能渲染纯Html+CSS的网页,所以有限制,所以才采用JavaFX对网页进行渲染解析,同时不得不使用JavaFX获取元素的这些基本信息。
    最初的想法是以为JavaFX会有单独存储CSS DOM的结构,不过最终查阅了一些文档,发现很有有说通过底层API访问CSS DOM的(最初都快疯了,以为需要阅读JavaFX的源码,然后改源码呢。。。),在查找的过程中,有人提及通过执行JavaScript代码来获取相应的属性,这才给了一个思路,而且以后的很多问题解决方案,也自然而然的往这方面考虑了。在将具体怎么获取元素的基本信息之前,先说一下在查找中发现的一个有趣的事情,是关于CSS的style的。就是样式表的种类:

  1. 浏览器默认样式,就是浏览器自身所带的样式表,因为添加样式时,你不可能将所有样式都添加进去,比如h1默认展示的样式,就是浏览器自身的。这个概念之前还真没有注意。
  2. .css文件中的样式
  3. 网页中style结点中定义的样式
  4. 标签内嵌的样式,就是元素中style属性中定义的样式

    JavaFX一般提供的接口获取的是第四种,即“标签内嵌的样式”,这个功能是满足不了我的需求的,所以需要借助JavaScript来获取渲染后的所有样式。
    通过JavaScript获取字体颜色等信息,可以使用document.defaultView.getComputedStyle来获取具体元素的信息,关于getComputedStyle的具体使用,可以百度,有很多相关介绍。以下是部分代码片段:

    // 计算对应元素的属性
    public DOMBox getDOMBoxByNode(WebEngine wEngine, Element e){
        JSObject obj_defaultView = (JSObject)webEngine.executeScript("document.defaultView");
        JSObject obj_ComputedStyle = (JSObject)obj_defaultView.call("getComputedStyle", e,null);
        JSObject obj = (JSObject)e;
        String tag_name = e.getTagName().toLowerCase();
        String strTemp = obj_Com
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值