为什么我的 Jsoup 代码没有返回正确的元素?

Why is my Jsoup Code not Returning the Correct Elements?

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

我正在尝试获取一些具有“data-at”属性的元素。奇怪的是,返回了一些具有“data-at”属性的元素,但不是我正在寻找的元素。无论出于何种原因,我的代码都没有提取 all 网页上共享“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

我要检索的元素

实际正在检索的元素之一

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

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

您在JSoup 中能够得到的是页面的静态内容(初始DOM)。您将无法获取动态创建的内容,因为您不需要 运行 必需的 JS 脚本。

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

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

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

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

这是您请求的 queryString - URL 指向包含的页面相当多的脚本代码。当您加载浏览器并单击显示以下内容的按钮(或 menu-option)时:"View Source"HTML 你看到的与 JSoup 广播和接收的 HTML 不完全相同。

如果广播的HTML中包含任何<SCRIPT TYPE="text/javascript"> ... </SCRIPT>(以及命名的URL 在你的问题中确实如此),AND 那些 <SCRIPT> 标签参与了页面的初始加载,那么 JSoup 将对此一无所知... 它仅解析接收到的内容,无法处理任何动态内容。

我知道有四种方法可以从动态 web-page,我现在就在这里打字。第一种可能是我在 Stack Overflow 上听说过的最流行的方法(在 Java 中):

  • SeleniumThis Answer will show how the tool can run Java-Script. These are some Selenium Docs. And then there is this page这里有一个很棒的“第一个class”,用于使用该工具检索 post-script processed HTML。同样,JSoup 无法检索通过脚本 (JS/AJAX/Angular/React) 发送到浏览器的 HTML,因为它 只是一个解析器 .
  • Puppeteer 这需要 运行ning 一种叫做 Node.js 的语言也许调用一个简单的 Node.js 来自 Java 的程序可以工作,但这将是一个“双语言”解决方案。我从来没有用过它。这是 an answer 显示获取,某种程度上,您想要获取什么...脚本后的 HTML。
  • WebViewAndroidJava程序员有一个流行的class叫做"WebView"documented here), that I have recently been told about (yesterday ... but it has been out for years) that will execute script in a browser, and return the HTML. Here is an answer 显示“Java脚本注入”以从“WebView”实例中检索 DOM 树元素(这是我被告知完成的方式)
  • Splash 我最喜欢的工具,我认为没有人听说过,但对我来说是最简单的...所以有一个 A.P.I .称为“Splash API”。这是“Java-Script 呈现服务”的 their explanation。自从我一直在使用这个...我将 post 一个代码片段,展示“Splash Tool”如何检索 post-script processed HTML 下面。

至 运行 Splash API(仅当您有权访问 docker loading program) ... 你启动一个 Splash Server 如下。将这两行输入到 GCP (Google Cloud Platform) Shell 实例中,服务器无需任何配置即可启动:

Pull the image:
$ sudo docker pull scrapinghub/splash

Start the container:
$ sudo docker run -it -p 8050:8050 --rm scrapinghub/splash

In your code, just prepend the String to your 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();