【问题标题】:Why is my Jsoup Code not Returning the Correct Elements?为什么我的 Jsoup 代码没有返回正确的元素?
【发布时间】:2020-09-24 19:27:59
【问题描述】:

我正在 Android Studio 中开发一个应用程序,但在使用 JSoup 进行网络抓取时遇到了一些问题。我已成功连接到网页并返回了一些基本元素来测试库,但现在我实际上无法获得我的应用所需的元素。

我正在尝试使用“data-at”属性获取一些元素。奇怪的是,返回了一些具有“data-at”属性的元素,但不是我要查找的元素。无论出于何种原因,我的代码都没有提取所有在网页上共享“data-at”属性的元素。

这是我正在抓取的网页的 URL: https://express.liatoyotaofcolonie.com/inventory?f=dealer.name%3ALia%20Toyota%20of%20Colonie&f=submodel%3ACamry&f=trim%3ALE&f=year%3A2020

包含网页抓取代码的方法:

@Override
    protected String doInBackground(Void... params) {
        String title = "";
        Document doc;
        Log.d(TAG, queryString.toString());
        try {
            doc = Jsoup.connect(queryString.toString()).get();
            Elements content = doc.select("[data-at]");
            for (Element e: content) {
                Log.d(TAG, e.text());
            }
        } catch (IOException e) {
            Log.e(TAG, e.toString());
        }
        return title;
    }

Logcat 中的结果

我要检索的元素

实际正在检索的元素之一

【问题讨论】:

    标签: java android android-studio web-scraping jsoup


    【解决方案1】:

    这是因为某些内容(包括您要查找的内容)是异步创建的,并且不存在于初始 DOM (Javascript ;))

    当您查看页面源代码时,您会注意到只有 17 个 data-at 出现,而​​运行 document.querySelector("[data-at]") 则返回 29 个节点。

    您可以在 JSoup 中获得的是页面的静态内容(初始 DOM)。由于您不运行所需的 JS 脚本,因此您将无法获取动态创建的内容。

    为了克服这个问题,您将不得不手动获取和解析所需资源(例如跟踪浏览器进行的 AJAX 调用)或使用无头浏览器设置。 Selenium + headless Chrome 应该足够了。

    Letter 选项将允许您抓取任何可能的 Web 应用程序,包括 SPA 应用程序,这是使用plang Jsoup 无法实现的。

    【讨论】:

    • 谢谢 Antoniosss,我明白你在说什么,这回答了我的问题。如果我再问一个问题,当您说我可以跟踪进行的 AJAX 调用时,我很确定我在 Chrome 开发工具网络选项卡下找到了该调用,其中包含我正在寻找的所有数据。您能否提供有关如何获取和解析此 AJAX 响应的建议?
    • 与初始 URL 完全相同的方式 :) Ajax 调用只不过是普通的 HTTP 请求。因此,如果浏览器可以做到,那么 JSoup(或您想使用的任何其他 http 客户端实用程序)也可以
    • 嗯!不过有一个问题……我在签出 AJAX 调用时看到的数据被 <script> 标签包围。准确地说,它是这样的:<script> window.vueAppName = 'dealer_inventory_app'; window.pageData = {{.... all the data that I want is here... }}; </script>我如何访问它?
    • 这是普通的 JS——不幸的是你必须解析它。如果您使用我建议的浏览器变体,对您来说会更容易。另一方面,由于您使用的是android,我不知道如何轻松地做到这一点。
    【解决方案2】:

    我不太清楚该怎么做,但我会再试一次......你的代码中的“问题行”是这些:

        doc = Jsoup.connect(queryString.toString()).get();
        Elements content = doc.select("[data-at]");
    

    这是您请求的 queryString - URL 指向包含相当多脚本代码的页面。当您加载浏览器并单击显示为:"View Source" 的按钮(或菜单选项)时,您看到的 HTML 并不完全相同 >HTML 被 JSoup 广播和接收。

    如果广播的 HTML 包含任何 <SCRIPT TYPE="text/javascript"> ... </SCRIPT> (并且您的问题中命名为 URL ),AND那些<SCRIPT>标签参与了页面的初始加载,那么JSoup不会知道任何关于它的... 它只解析它收到的东西,它不能处理任何动态内容。

    我知道有四种方法可以从动态网页获取 HTML 的“Post Script Loaded”版本,现在我将在此处输入它们。第一种可能是我在 Stack Overflow 上听说过的最流行的方法(在 Java 中):

    • Selenium This Answer 将展示该工具如何运行 Java 脚本。这些是一些Selenium Docs。然后是this page,这里有一个很棒的“一流”,可以使用该工具检索post-script processed HTML。同样,JSoup 无法检索通过脚本 (JS/AJAX/Angular/React) 发送到浏览器的 HTML,因为它只是一个解析器
    • Puppeteer 这需要运行一种名为 Node.js 的语言,也许从 Java 调用一个简单的 Node.js 程序可以工作,但它会是一个“两种语言”的解决方案。我从来没有用过它。这是an answer,它显示了您想要获取的内容......脚本之后的HTML。
    • WebView Android Java 程序员有一个名为 "WebView" (documented here) 的流行课程,我最近被告知(昨天......年),它将在浏览器中执行脚本,并返回 HTML。这是an answer,它显示了“JavaScript 注入”以从“WebView”实例中检索 DOM 树元素(我被告知已完成)
    • Splash 我最喜欢的工具,我想没有人听说过,但对我来说是最简单的......所以有一个 A.P.I.称为“Splash API”。这是their explanation 的“Java 脚本渲染服务”。由于我一直在使用这个...我将在下面发布一个代码 sn-p,显示“Splash Tool”如何检索 post-script processed HTML

    要运行 Splash API(仅当您有权访问 docker 加载程序时)...您启动 Splash Server 如下。这两行输入到 GCP (Google Cloud Platform) Shell 实例中,服务器直接启动,无需任何配置:

    拉图:
    $ sudo docker pull scrapinghub/splash

    启动容器:
    $ sudo docker run -it -p 8050:8050 --rm scrapinghub/splash

    在您的代码中,只需将字符串添加到您的 URL's:
    "http://localhost:8050/render.html?url="

    因此,在您的代码中,您将使用以下命令(而不是),该脚本将(更有可能)加载您未找到的所有 HTML 元素:

    String SPLASH_URL = "http://localhost:8050/render.html?url=";
    doc = Jsoup.connect(SPLASH_URL + queryString.toString()).get();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-03
      • 2019-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      相关资源
      最近更新 更多