计数 DOM 个 CasperJS 评估失败的元素

Count DOM elements with CasperJS' evaluate failed

我刚刚遇到 CasperJS 的问题。

我需要计算 table 行,因为有很多 table 包含相同的信息结构(比如说用户 table) 所以我做了一些 casperjs 评估这样的代码

var table_rows1 = casper.evaluate(function(it){ return jQuery("#dResult > div:nth-child("+1+") > div > div:nth-child(4) > div:nth-child("+it+") > div:nth-child(1) > span > div").length; }, it);

它是迭代器,它会递增直到达到table个元素长度。

所以假设我们有 3 个 table,所以它将是 1,2,3 对于它 = 1,没有问题发生,它打印出正确的 table[1] 行数。 但是对于下一个,2,3,它只为 table 行号打印 1。 怎么会变得这么奇怪?

这是我的 CasperJS 片段:

function getNumber(it){
     window.__utils__.echo("it :"+it);
     var query = "#dResult > div:nth-child("+1+") > div > div:nth-child(4) > div:nth-child("+it+") > div:nth-child(1) > span > div";
     return jQuery(query).length;
}
var table_rows1 = casper.evaluate(getNumber, 1);
var table_rows2 = casper.evaluate(getNumber, 2);
var table_rows3 = casper.evaluate(getNumber, 3);

this.echo("table rows #1 :"+table_rows1);
this.echo("table rows #2 :"+table_rows2);
this.echo("table rows #3 :"+table_rows3);

这是我需要抓取的 html...

这是 1 个 table 的,有很多 html 个这样的标签

<div class="padd-b-rates">
        <div id="showRateWSMA0511000015CL096-CL124">
            <div class="bd-rate-in">
                <div class="rth1"><b>Room Category </b></div>
                <div class="rth2"><b>Breakfast</b></div>
                <div class="rth3"><b>Total Stay</b></div>
                <div class="rth4"><b>Room Status</b></div>
                <div class="clear"></div>
            </div>
            <span id="RateWSMA0511000015CL096-CL124">
    <div class="bd-rate-row">
        <div class="rtd1"><span class="rmname-rsht-rate">DELUXE (NRF)</span><i></i></div>
        <div class="rtd2"><span>Breakfast</span><i></i></div>
        <div class="rtd3"><span><a href="javascript:sHC.ShowPrice('WSMA0511000015','WSMA140400017', 'BB','CL096-CL124');">2,174,005.00 IDR</a></span><i></i></div>
        <div class="rtd4"><span class="btn-rsht-rate" onclick="sHC.jumpToPaxdetail(this);" hotelcode="WSMA0511000015" suppliercode="CL096-CL124" droomcatg="WSMA140400017-BB" roomstatus="Y" id="bookWSMA0511000015WSMA140400017-BB-CL096-CL124"><img border="0" src="/b2b/images/result-hotels/btnAV-v3.gif"></span></div>
        <div class="clear"></div>
    </div>

    <div class="bd-rate-row">
        <div class="rtd1"><span class="rmname-rsht-rate">EXECUTIVE (NRF)</span><i></i></div>
        <div class="rtd2"><span>Breakfast</span><i></i></div>
        <div class="rtd3"><span><a href="javascript:sHC.ShowPrice('WSMA0511000015','WSMA140400018', 'BB','CL096-CL124');">2,505,557.00 IDR</a></span><i></i></div>
        <div class="rtd4"><span class="btn-rsht-rate" onclick="sHC.jumpToPaxdetail(this);" hotelcode="WSMA0511000015" suppliercode="CL096-CL124" droomcatg="WSMA140400018-BB" roomstatus="Y" id="bookWSMA0511000015WSMA140400018-BB-CL096-CL124"><img border="0" src="/b2b/images/result-hotels/btnAV-v3.gif"></span></div>
        <div class="clear"></div>
    </div>

    <div class="bd-rate-row">
        <div class="rtd1"><span class="rmname-rsht-rate">DELUXE</span><i></i></div>
        <div class="rtd2"><span>Room Only</span><i></i></div>
        <div class="rtd3"><span><a href="javascript:sHC.ShowPrice('WSMA0511000015','WSMA05110034', 'RO','CL096-CL124');">2,743,860.00 IDR</a></span><i></i></div>
        <div class="rtd4"><span class="btn-rsht-rate" onclick="sHC.jumpToPaxdetail(this);" hotelcode="WSMA0511000015" suppliercode="CL096-CL124" droomcatg="WSMA05110034-RO" roomstatus="Y" id="bookWSMA0511000015WSMA05110034-RO-CL096-CL124"><img border="0" src="/b2b/images/result-hotels/btnAV-v3.gif"></span></div>
        <div class="clear"></div>
    </div>

    <div class="bd-rate-row">
        <div class="rtd1"><span class="rmname-rsht-rate">DELUXE</span><i></i></div>
        <div class="rtd2"><span>Breakfast</span><i></i></div>
        <div class="rtd3"><span><a href="javascript:sHC.ShowPrice('WSMA0511000015','WSMA05110034', 'BB','CL096-CL124');">2,847,470.00 IDR</a></span><i></i></div>
        <div class="rtd4"><span class="btn-rsht-rate" onclick="sHC.jumpToPaxdetail(this);" hotelcode="WSMA0511000015" suppliercode="CL096-CL124" droomcatg="WSMA05110034-BB" roomstatus="Y" id="bookWSMA0511000015WSMA05110034-BB-CL096-CL124"><img border="0" src="/b2b/images/result-hotels/btnAV-v3.gif"></span></div>
        <div class="clear"></div>
    </div>
</span>
        </div>
        <div class="bd-rate-bottom">
            <div class="rsht-cxl" id="CancelPolicyWSMA0511000015CL096-CL124" onclick="sHC.rCancel('WSMA0511000015CL096-CL124','CL096-CL124');" title="Click for view cancellation policy">
                <textarea id="PolicyWSMA0511000015CL096-CL124" style="display:none"></textarea>
                Cancellation Policy         </div>
            <div class="rsht-promotion" id="FOCWSMA0511000015CL096-CL124" onmouseover="sHC.popupHotelFOC(this, 'WSMA0511000015CL096-CL124','CL096-CL124');" detail="" style="display:none;">(Special Promotion)</div>
            <div class="rsht-message" id="lyHotelMessageWSMA0511000015CL096-CL124"><blink><b><font color="red">Hotel Message</font> : </b></blink> <span id="HotelMessageWSMA0511000015CL096-CL124" style="word-wrap:break-word;">Complimentary WIFI internet access</span></div>
            <div class="clear"></div>
        </div>
    </div>

如果还有另一个像这样的table结构,求值函数只是return 1甚至0... 那么这个案例的问题是什么?

这就是我在检查元素 chrome 浏览器

中进行 jQuery dom 计数时得到的结果
jQuery("#dResult > div:nth-child("+1+") > div > div:nth-child(4) > div:nth-child("+1+") > div:nth-child(1) > span > div").length;

8

jQuery("#dResult > div:nth-child("+1+") > div > div:nth-child(4) > div:nth-child("+2+") > div:nth-child(1) > span > div").length;

15

您的选择器看起来不错。可能发生了很多事情...

正在等待

站点未完全加载(动态 site/SPA),这意味着您试图过早访问这些元素。例如,您可以等待第一个元素出现,然后访问所有元素:

casper.waitFor(function check(){
    return this.evaluate(getNumber, 1) > 0;
}, function then(){
    var table_rows1 = this.evaluate(getNumber, 1);
    var table_rows2 = this.evaluate(getNumber, 2);
    ...
});

使用 XPath

PhantomJS 有一个 :nth-child() 选择器的错误,它只出现在特定的星座中。您可以尝试为此使用 XPath 表达式。

function getNumber(it){
     var query = "//*[@id='dResult']/*["+1+"]/div/*[4]/*["+it+"]/*[1]/span/div";
     return __utils__.getElementsByXPath(query).length;
}

我使用*[x]而不是div[x]的原因是因为XPath在根据位置查询时会考虑元素名称,但CSS选择器不会。

不同的移动页面

有时服务器会根据用户代理字符串或视口提供不同的页面。 PhantomJS 的默认视口大小为 400x300。可能页面被页面 JavaScript.

动态更改了
  • 检查屏幕截图 (casper.capture()) 页面看起来是否与 Chrome 中的相同。
  • 使用 casper.debugHTML() 转储页面源并将其与 Chrome 版本进行比较。

一般问题

页面可能还有其他问题。查找各种事件处理程序的错误。请注册参加 resource.errorpage.errorremote.messagecasper.page.onResourceTimeout 活动 (Example)。