我在CasperJS中使用XPath有什么问题?

时间:2014-02-02 19:01:08

标签: javascript dom xpath phantomjs casperjs

我想在link中获取日期信息,所以我正在使用CasperJS。我分析了日期的XPath:

//*[@id="contentblock"]/td/table[3]/tbody/tr[position()>=3]/td[1]/div

我的casperJS脚本如下:

var casper = require('casper').create({
    clientScripts: ["includes/jquery-1.10.2.min.js"]
});
var x = require('casper').selectXPath;

var myear = casper.cli.get(0);
var mmon  = casper.cli.get(1);
var stk_no = casper.cli.get(2);

casper.start('http://www.twse.com.tw/en/trading/exchange/STOCK_DAY/STOCK_DAYMAIN.php', function() {
    this.fill("form[name='date_form']", {
        'myear' : myear,
        'mmon'  : mmon,
        'STK_NO': stk_no
    },true);
});


casper.waitForUrl(/Report/,function() {
    var xPathRes = document.evaluate ( '//*[@id="contentblock"]/td/table[3]/tbody/tr[position()>=3]/td[1]/div', document, null, 0, null);
    this.echo(xPathRes);
    var nodes = xPathRes.iterateNext();
    this.echo(nodes);
    while (nodes)
    {
        this.echo(nodes);
        this.echo(nodes.innerHTML);
        nodes=xPathRes.iterateNext();
    }
});

casper.run();

使用命令行

casperjs mytest.js 2014 1 9921

我的剧本给了我回复:

[object XPathResult]
null

似乎xPathRes.iterateNext()返回null,这意味着没有匹配的xpath。我不确定我的XPath和脚本有什么问题。有人能给我一些关于这个问题的暗示吗?

我尝试过XPath:

var xPathRes = document.evaluate('//*', document, null, 0, null);
this.echo(xPathRes);
var nodes = xPathRes.iterateNext();
this.echo(nodes);
while (nodes)
{
    this.echo(nodes.tagName);
    nodes=xPathRes.iterateNext();
}

,结果是

[object XPathResult]
[object HTMLHtmlElement]
HTML
HEAD
BODY

我认为它会给出html中的每个元素。

另一次尝试:

var xPathRes = document.evaluate('//*[@id="contentblock"]', document, null, 0, null);
this.echo(xPathRes);
var nodes = xPathRes.iterateNext();
this.echo(nodes);
while (nodes)
{
    this.echo(nodes.tagName);
    nodes=xPathRes.iterateNext();
}

,结果是

[object XPathResult]
null

似乎它与任何东西都不匹配。这很奇怪,因为如果我用

转储html,那么 id = contentblock 的元素确实存在
this.debugHTML();

下面使用CasperJS API的代码有效。但是使用document.evaluate失败了。这很奇怪。我不知道该如何调试它。

var x = require('casper').selectXPath;
casper.waitForUrl(/Report/,function() {
    this.test.assertExists(x('//*[@id="contentblock"]/td/table[3]'), 'the element exists');
    this.echo(this.getHTML( x('//*[@id="contentblock"]/td/table[3]/tbody/tr[3]/td[1]/div') ,true));
});

1 个答案:

答案 0 :(得分:2)

PhantomJS有两个不同的背景。由于CasperJS建立在PhantomJS之上,因此它具有相同的限制。您只能从页面/ DOM上下文访问DOM。 casper.evaluate()提供了此访问权限,但您传入其中的函数是沙盒化的,如PhantomJS documentation中所示。

您无法在document.evaluate之外调用casper.evaluate(),因为document在页面上下文之外没有任何意义。我不知道为什么document甚至存在于casper环境中,因为它没有做任何事情。实际上,外部上下文有一个虚拟页面,它只包含<html><head></head><body></body></html>,它解释了你看到的有限结果。

如果将其包装在casper.evaluate中,则不能再将DOM元素传递给casper上下文,因为只能传入和传出原始对象。如果您想访问这些元素,可以使用casper.getElementsInfo,具体取决于您要对其进行操作。

casper.waitForUrl(/Report/,function() {
    var xPathRes = this.getElementsInfo('//*[@id="contentblock"]/td/table[3]/tbody/tr[position()>=3]/td[1]/div');
    xPathRes.forEach(function(element, index) {
        this.echo(element);
        this.echo(element.html);
    });
});

您也可以在页面上下文中执行您的操作,但是您必须记住您可以从页面中进行何种表示。

casper.waitForUrl(/Report/,function() {
    var elements = this.evaluate(function(){
        var xPathRes = document.evaluate ( '//*[@id="contentblock"]/td/table[3]/tbody/tr[position()>=3]/td[1]/div', document, null, 0, null);
        var collectHTML = [];
        var nodes = xPathRes.iterateNext();
        while (nodes)
        {
            collectHTML.push(nodes.innerHTML);
            nodes = xPathRes.iterateNext();
        }
        return collectHTML;
    });
    this.echo(JSON.stringify(elements));
});