【问题标题】:Render JavaScript and HTML in (any) Java Program (Access rendered DOM Tree)?在(任何)Java 程序中渲染 JavaScript 和 HTML(Access 渲染的 DOM 树)?
【发布时间】:2011-01-10 18:56:08
【问题描述】:

什么是最好的 Java 库来“完全下载任何网页并渲染内置 JavaScript,然后以编程方式访问渲染的网页(即 DOM 树!)并将 DOM 树作为“HTML -来源”?

(类似于 firebug 最终所做的事情,它呈现页面并且我可以访问完全呈现的 DOM 树,就像页面在浏览器中一样!相比之下,如果我单击“显示源”,我只会得到JavaScript 源代码。这不是我想要的。我需要访问呈现的页面...)

(对于渲染,我的意思是只渲染 DOM 树不是视觉渲染...)

这不必是一个单独的库,可以有几个库一起完成这个任务(一个会下载,一个渲染......),但由于 JavaScript 的动态特性,JavaScript 库很可能会还必须有某种下载器来完全渲染任何异步 JS...

背景:
在“过去的美好时光”中,HttpClient(Apache 库)是构建您自己的非常简单的爬虫所需的一切。 (很多像Nutch或者Heretrix这样的爬虫还是围绕着这个核心原理构建的,主要集中在标准的HTML解析上,所以我不能向他们学习) 我的问题是我需要抓取一些严重依赖 JavaScript 的网站,并且我无法使用 HttpClient 进行解析,因为我之前肯定需要执行 JavaScript...

【问题讨论】:

  • 当您说“渲染任何异步 js”时,您的意思是库需要能够“抓取”页面进行的任何异步调用吗?这将非常困难,因为您基本上是在尝试捕获在初始请求完成后更新的动态页面的内容,并且有时在用户触发事件之前不会异步拉入数据。

标签: java javascript rendering


【解决方案1】:

这有点开箱即用,但如果您计划在您可以完全控制环境的服务器上运行代码,它可能会起作用...

在您的机器上安装 Firefox(或 XulRunner,如果您想保持轻量级)。

使用 Firefox 插件系统,编写一个小插件,加载给定的 URL,等待几秒钟,然后将页面的 DOM 复制到字符串中。

从此插件中,使用 Java LiveConnect API(请参阅 http://jdk6.java.net/plugin2/liveconnect/https://developer.mozilla.org/en/LiveConnect )将该字符串推送到某些嵌入式 Java 代码中的公共静态函数,该函数可以自行执行所需的处理,也可以将其移出到一些更复杂的代码。

好处:您使用的是大多数应用程序开发人员所针对的浏览器,因此观察到的行为应该具有可比性。您还可以按照正常的升级路径升级浏览器,这样您的库就不会随着 HTML 标准的变化而过时。

缺点:您需要有权限才能在您的服务器上启动非无头应用程序。您还需要担心进程间通信的复杂性。

我之前用过插件API调用Java,还是可以实现的。如果您想要一些示例代码,您应该查看 XQuery 插件 - 它从 DOM 加载 XQuery 代码,将其传递给 Java Saxon 库进行处理,然后将结果推送回浏览器。这里有一些关于它的细节:

https://developer.mozilla.org/en/XQuery

【讨论】:

  • +1 - 类似的解决方案已经开始了一次,但不幸的是,开发在 2008 年停滞不前,显然 - 输入 Crowbar其目的是允许针对 DOM 运行 javascript 抓取工具自动化网站抓取,但避免所有语法规范化问题。 - 即使是 Java integration has been attempted with some success,但 Ben 的结论和更新也突出了一些缺点和问题。
  • 谢谢,是的,我也有这个想法。但是,如果可能的话,我希望有一个“无头”解决方案,因为该软件必须在可能没有安装 X 系统的服务器上运行......但是感谢您的详细信息和解释,如果什么都没有出现。
【解决方案2】:

您可以使用 JavaFX 2 WebEngine。下载JavaFX SDK (如果您安装了JDK7u2或更高版本,您可能已经拥有它)并尝试以下代码。

它将使用已处理的 javascript 打印 html。 您也可以取消注释中间的行以查看渲染。

public class WebLauncher extends Application {

    @Override
    public void start(Stage stage) {
        final WebView webView = new WebView();
        final WebEngine webEngine = webView.getEngine();
        webEngine.load("http://stackoverflow.com");
        //stage.setScene(new Scene(webView));
        //stage.show();

        webEngine.getLoadWorker().workDoneProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                if (newValue.intValue() == 100 /*percents*/) {
                    try {
                        org.w3c.dom.Document doc = webEngine.getDocument();
                        new XMLSerializer(System.out, new OutputFormat(doc, "UTF-8", true)).serialize(doc);
                    } catch (IOException ex) { 
                        ex.printStackTrace();
                    }
                }
            }
        });

    }

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

}

【讨论】:

  • 您好,感谢您的回答。但我没有设法加载一些网站。例如。我无法加载maps.google.com/maps/…。它永远不会达到 100%,它会挂在 0 处。另外,我如何确保所有内容都已加载?
  • 你需要加载场景,否则它将无法工作
  • 您也可以使用 JFrame 使 web 引擎在 launch(args) 之外工作。所以公共类 WebLauncher 扩展了 JFrame。您将需要避免 Selenium 驱动程序,它们很糟糕(泄漏、挂起、线程或处理时抛出异常,以及各种废话)。此外,您将需要 rpc 到 WebEngine 服务器,因为存在大量泄漏。如果您的网站通常不需要最新的 SSL 并且连接失败对您来说没问题,那么 Scrapy 使用将近 10 年的 Qt4.8 来使用他们的新 JS 服务器来执行此操作。我建议不时重新启动引擎并传递 cookie。 JDK 9 应该会修复。
  • 关于以上内容的更多信息,我在github.com/asevans48/JScrape 有一个示例程序。随意分叉它并帮助任何 Goat 项目或 jXXX 项目。我正在对第一部分(Http 组件部分)进行最后润色,然后将我的 Java FX 研究与 rabbitMQ RPC 和 JSON 结合起来,用于每个请求的 http 参数。
【解决方案3】:

Selenium 库通常用于测试,但确实可以让您远程控制大多数标准浏览器(IE、Firefox 等)以及无头、无浏览器模式(使用 HtmlUnit)。因为它旨在通过页面抓取进行 UI 验证,所以它很可能满足您的目的。

根据我的经验,它有时会遇到非常慢的 JavaScript,但仔细使用“等待”命令可以获得相当可靠的结果。

它还有一个好处是您可以实际驱动页面,而不仅仅是抓取它。这意味着,如果您在获得所需数据之前在页面上执行一些操作(单击搜索按钮,单击下一步,现在抓取),那么您可以将其编码到流程中。

我不知道您是否能够从 Selenium 以可导航的形式获取完整的 DOM,但它确实为页面的各个部分提供了 XPath 检索,这就是你通常需要一个抓取应用程序。

【讨论】:

  • 谢谢! Selenium 看起来很有希望,但如果我想无头运行它,我可以直接使用 HtmlUnit。到目前为止,我在使用 HtmlUnit 时遇到了一些问题。尤其是在性能方面。我将仔细研究 Selenium。
【解决方案4】:

您可以在有或没有 Grails 的情况下使用 Java、Groovy。然后使用 Webdriver、Selenium、Spock 和 Geb,这些用于测试目的,但这些库对您的情况很有用。 您可以实现一个不会打开新窗口而只是这些浏览器运行时的爬虫。

【讨论】:

  • Geb 看起来很有希望,我会更深入地研究它。谢谢!
  • 是的,我应该指定 Geb 包含以上所有内容 :) 这确实是一种很棒的新测试方法。
【解决方案5】:

【讨论】:

    【解决方案6】:

    你可以试试 JExplorer。 欲了解更多信息,请参阅http://www.teamdev.com/downloads/jexplorer/docs/JExplorer-PGuide.html

    你也可以试试 Cobra,见http://lobobrowser.org/cobra.jsp

    【讨论】:

      【解决方案7】:

      我没有尝试过这个项目,但我已经看到了几个 node.js 的实现,其中包括 javascript dom 操作。

      https://github.com/tmpvar/jsdom

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-07-08
        • 1970-01-01
        • 2013-02-02
        • 1970-01-01
        • 2019-05-10
        • 2020-11-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多