【问题标题】:How To Fix: HtmlUnit GetElementById Returns Null如何修复:HtmlUnit GetElementById 返回 Null
【发布时间】:2019-01-03 20:53:23
【问题描述】:

我正在编写一个网络爬虫,并试图在搜索框中输入搜索词。但是,当我尝试按 ID 访问搜索框时,我似乎得到了空值。我只是在学习 HtmlUnit,所以我可能会遗漏一些非常明显的东西,但我自己还不能识别出来。

这是网站的代码:

<html xmlns="http://www.w3.org/1999/xhtml" xml:1ang="en" class="no-touch">
    <head>-</head>
    <body lang="en" class="garageBrand" emailcookiename="grgemailca" loyaltycookiename="grgloyaltyca">
        <div id="fb-root" class="fb_reset">-</div>
        <noscript>...</noscript>
        <script>...</script>
        <div id="container">
            <div id="avsDialog" sty1e="disp1ay: none; position: absolute; top: 0; right: 0;"></div>
            <input type="hidden" value="en" id="displayLanguage">
            <input type="hidden" value="garageSiteCA" id="currSiteId">
            <input type="hidden" value="en_CA" id="currLocale">
            <div id="contentarea">
                <div id="header" class="nonHeaderScroll">
                <div id="topnav">...</div>
                <div class="socialSearch">
                <div id="searchMenu">
                    <form action="//www.garageclothing.com/ca/search/search.jsp" method="GET">
                        <input type="hidden" name="N" value="0">
                        <input type="hidden" name="Dy" value="1">
                        <input type="hidden" name="Nty" value="1">
                        <input type="hidden" name="Ntk" value="All">
                        <input type="hidden" name="Ntx" value="mode matchall">
                        <input id="searchText" maxlength="40" type="text" name="Ntt" class="textInput" placeholder="Search..." autocomplete="off">
                        <input class="mainSearchButton" type="image" src="//images.gdicdn.com/img/magnifying-glass.png?version=375" name="search">
                    </form>
                </div>

这是我的代码:

import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import com.gargoylesoftware.htmlunit.html.HtmlInput;

import java.io.IOException;


public class Main {

public static void main(String[] args) {

    WebClient client = new WebClient();
    client.getOptions().setJavaScriptEnabled(true);
    client.getOptions().setCssEnabled(false);
    client.getOptions().setUseInsecureSSL(true);

    try {
        HtmlPage page = client.getPage("https://www.garageclothing.com/ca");

        // Check for popup.
        if(page.getElementById("cboxClose") != null) {
            page = page.getElementById("cboxClose").click();
        }

        // Debugging line that returns null:
        System.out.println(page.getElementById("searchText"));
        // What I would like to do:
      /*HtmlInput searchInput = (HtmlInput) page.getElementById("searchText");
        searchInput.setValueAttribute("red scarf");
        HtmlSubmitInput submitBtn = page.getElementByName("search");
        page = submitBtn.click();

        System.out.println(page.asXml());*/

    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

【问题讨论】:

    标签: java web-scraping htmlunit


    【解决方案1】:

    即使页面看起来很简单,但这个页面(就像许多购物门户一样)非常复杂,并且基于大量的 JavaScript(不仅对于页面本身,而且对于所有这些讨厌的跟踪器来观察用户)。如果您想了解有关此页面的更多信息,我建议使用像 Charles 这样的网络代理来捕获整个流量。

    现在回到你的问题... 因为 HtmlUnit javascript 支持(基于 Rhino)并不完美,你会遇到一些 javascript 错误。为了不停留在js错误,你必须配置客户端

    webClient.getOptions().setThrowExceptionOnScriptError(false);
    

    下一步是获取页面。由于所有的 js 东西,这也不是那么简单。看起来js的东西也替换了最初通过获取url返回的页面。因此,您必须执行三个步骤

    • 获取页面
    • 等待一段时间让 js 做一些工作
    • 从当前窗口获取当前页面

    现在您可以找到搜索字段;在其中输入一些搜索,最后按下搜索按钮。然后你必须再次执行三个步骤才能获取当前内容。

    希望对您有所帮助....

    public static void main(String[] args) throws IOException {
        String url = "https://www.garageclothing.com/ca";
    
        try (final WebClient webClient = new WebClient()) {
            // do not stop at js errors
            webClient.getOptions().setThrowExceptionOnScriptError(false);
    
            webClient.getPage(url);
            webClient.waitForBackgroundJavaScript(10000);
    
            HtmlPage page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();
            HtmlInput searchInput = (HtmlInput) page.getElementById("searchText");
            searchInput.type("red scarf");
    
            HtmlElement submitBtn = (HtmlElement) page.getElementByName("search");
            submitBtn.click();
            webClient.waitForBackgroundJavaScript(10000);
    
            page = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();
            // System.out.println("------------------------------------------------");
            // System.out.println(page.asXml());
    
            System.out.println("------------------------------------------------");
            final DomNodeList<DomNode> divs = page.querySelectorAll(".divProdPriceSale");
            for (DomNode div : divs) {
                System.out.println(div.asText());
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您应该检查您传递给WebClient 的URL 是您在使用的网络浏览器中查看的那个。

      我访问了您在代码中使用的链接 (https://www.garageclothing.com),但我得到的页面不是您所期望的。它要求我选择一个国家(美国或加拿大),然后在我单击任何选项后,它会将我带到您期望的页面。

      尝试将 URL 更改为“https://www.garageclothing.com/us/”或“https://www.garageclothing.com/ca/

      【讨论】:

      • 感谢您的回复!抱歉,我实际上没有更新我的答案,因为这是我意识到并且目前正在使用的东西。尽管它仍然不适用于更新的 URL。 (我使用的是 /ca 版本)
      • @cosmicluna,看起来页面的内容是由在初始页面加载时执行的一些 Javascript 加载的。在调试时,我注意到页面抛出了一些“真正的浏览器”显然可以处理的 Javascript 错误。我认为您应该为此打开一个 HtmlUnit 问题(Github),以便 api 开发人员可以帮助您
      • 好的,我会这样做的!如果你不介意我问,你是如何调试的?我还没有找到任何有效的方法来可视化 HtmlUnit 幕后实际发生的事情。
      猜你喜欢
      • 1970-01-01
      • 2011-05-18
      • 2023-03-26
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      相关资源
      最近更新 更多