有没有办法用 HtmlUnit 触发滚动事件,或者根本不可能?

Is there a way to trigger scroll event with HtmlUnit or is it not possible at all?

提问人:DjCode 提问时间:5/6/2014 更新时间:6/21/2018 访问量:2223

问:

我目前正在学习 HtmlUnit 以抓取网站。一切都很顺利,直到我遇到一个动态页面(例如,我正在使用 Pinterest 网站),当用户向下滚动时,它会在该页面上即时添加元素。

我已经尝试了几种应该在真实浏览器中触发滚动的方法(我将在下面展示它们)。 在继续之前,我想提一下,我已经设置了以下配置:

    webclient.setJavaScriptEnabled(true);
    webclient.setAjaxController(new NicelyResynchronizingAjaxController());

假设我想在 Pinterest 上获得我所有的关注者。我导航到该页面,现在由于您第一次只有 24 个,我想向下滚动,触发对服务器的 Ajax 调用并检索下一组关注者的事件。

1)纯javascript或jQuery代码触发窗口滚动。

    ScriptResult sr = followersPage.executeJavaScript("window.scrollBy(0,1000)");
    // One version in jQuery
    // ScriptResult sr = followersPage.executeJavaScript("$(window).scrollTop(0,1000);");
    // also tried with the body, html, with animation
    // ScriptResult sr = followersPage.executeJavaScript("$("html, body").animate({ scrollTop: $(document).height() }, 1000);");
    webclient.waitForBackgroundJavaScript(10000);
    followersPage = (HtmlPage)sr.getNewPage();

=> 当我检查到顶部的距离时,它等于 0,结果页面与原始页面相同。在 Eclipse 中调试时,当我跨过执行 javascript 的行时,它会直接转到下一行,没有任何延迟。如果我编写任何其他javascript,例如:

     ScriptResult sr = followersPage.executeJavaScript("$(div.GridItems).html('new content')");

您可以注意到调试器在该行上挂起半秒钟,这意味着 JavaScript 已执行。

2)将焦点从一个跟随锚点更改为另一个跟随锚点(我选择锚点是因为当您单击TAB键时,它会按焦点顺序使用):

    HtmlDivision gridItems = followersPage.getFirstByXPath("//div[contains(concat(' ',@class,' '),' GridItems ')]");
    List<HtmlDivision> els = (List<HtmlDivision>) gridItems.getByXPath("//div[@class='item ']");
    List<HtmlDivision> items = (List<HtmlDivision>) gridItems.getByXPath("//div[@class='item ']");
    for (HtmlDivision item : items) {
        HtmlAnchor a = item.getFirstByXPath("//a[@class='userWrapper']");
        a.focus();
        webClient.waitForBackgroundJavaScript(1000);
    }
    followersPage = (HtmlPage) webClient.getCurrentWindow().getEnclosedPage();

同样,没有发生滚动。结果页面与原始页面相同

3) 创建一个按钮,在窗口上触发滚动事件:

    HtmlButton scrollButton = (HtmlButton) followersPage.createElement("button");
    scrollButton.setAttribute("type", "button");
    scrollButton.setAttribute("onclick", "window.scrollTo(0,document.body.scrollHeight);");
    gridItems.appendChild(scrollButton);
    followersPage = scrollButton.click();

不幸的是,它没有奏效。

我尝试了许多其他方法,但直到现在都没有积极的结果。

我阅读了很多关于该主题的相关文章,也在这里的stackoverflow上。而且似乎没有人设法使用 HtmlUnit 使滚动工作,因为大多数问题仍未得到解答。这就是为什么我想知道该功能是否曾经起作用。

有人设法滚动页面(简单页面,没有ajax)吗? 是否有人设法滚动页面,触发某些ajax调用的事件?

JavaScript ajax 滚动 htmlunit pinterest

评论

0赞 bharatpatel 9/29/2014
我也有同样的问题,你找到什么解决方案了吗?

答:

0赞 qfrank 6/21/2018 #1

我建议你在这种情况下使用 casperjs 而不是 htmlunit,我试过了 使用 HtmlUnit 打开 Pinterest 并得到

runtimeError: message=[Property 0 not found.] sourceName=[https://s.pinimg.com/webapp/js/vendor-react-d20f99c48b5d58e4821c.js] line=[1] lineSource=[null] lineOffset=[0]

所以看起来 htmlunit 对 js 没有很好的支持,即使是最新版本 2.31.。

下面是一个使用 casperjs 的演示代码:

var utils = require('utils')
var fs = require('fs')
var system = require('system')

var casper = require('casper').create({
    verbose: true,
    logLevel: 'debug',
    localToRemoteUrlAccessEnabled: true,
    webSecurityEnabled: false,
    plainTextAllContent: false,
    viewportSize: {
        width: 1440,
        height: 800
    },
    onError: function(casper, msg, backtrace) {
        utils.dump(backtrace)
    }
});

var cookie = fs.read('cookie.txt').trim() 

casper.on('started', function() {

    this.page.onError = function(msg, trace) {
        casper.echo('Error => ' + msg + '\nError trace => ')
        utils.dump(trace)
    }

    this.page.customHeaders = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "zh-CN,en;q=0.5",
        "Accept-Encoding": "gzip, deflate",
        "Connection": "keep-alive",
        "Pragma": "no-cache",
        "Cookie": cookie
    }


});

casper.start('https://www.pinterest.com', function() {

    this.then(function() {
        this.waitForSelector('div[class="_wx _2h"]', function() {
            this.echo("waitForSelector 'div[class=_wx _2h]' is done")
            this.scrollTo(0, 1000);
            this.wait(5000, function() {
                this.scrollTo(0, 2000);
            })
        })

    })

});

将上述代码保存到名为 demo.js 的文件中,然后使用以下命令启动 CasperJS

casperjs --engine=slimerjs demo.js

然后,您将看到Firefox浏览器在视觉上启动并正常工作!