【问题标题】:Calculating an XPath of a given element in CasperJS在 CasperJS 中计算给定元素的 XPath
【发布时间】:2016-04-05 20:39:08
【问题描述】:

我正在尝试使用 getElementXPath function from Firebug 在 CasperJS 中工作,但我似乎找不到合适的位置来调用它以使其工作。这是我到目前为止所拥有的,它仅适用于已经具有“id”标签的对象,但这并没有多大帮助,因为我使用 XPath 代替 id(大多数对象没有 id)

casper.then(function () {
    var Element = this.evaluate(function(){
        var elm = document.querySelector('[class="h4"]');
        return getElementXPath(elm); //Set 1
        //return elm; //Set 2
    });

    console.log('xpath: '+ Element); //Set 1
    //console.log('xpath: '+ getElementXPath(Element)); //Set 2
});

Set 1 总是输出“xpath: null”

如果元素已经有一个“id”标签,Set 2 只会输出正确的路径。 "xpath: //*[id="button"]"

Set 2 否则将输出最后一个标签,即“xpath: /a”或“xpath: /span”

这是我刚刚粘贴到我的 JS 文件顶部的 Firebug 的 getElementXPath 函数。

function getElementXPath(element)
{
    if (element && element.id)
        return '//*[@id="' + element.id + '"]';
    else
        return getElementTreeXPath(element);
};

function getElementTreeXPath(element)
{
    var paths = [];
    // Use nodeName (instead of localName) so namespace prefix is included (if any).
    for (; element && element.nodeType == Node.ELEMENT_NODE; element = element.parentNode)
    {
        var index = 0;
        var hasFollowingSiblings = false;
        for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling)
        {
            // Ignore document type declaration.
            if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
                continue;
            if (sibling.nodeName == element.nodeName)
                ++index;
        }

        for (var sibling = element.nextSibling; sibling && !hasFollowingSiblings;
            sibling = sibling.nextSibling)
        {
            if (sibling.nodeName == element.nodeName)
                hasFollowingSiblings = true;
        }
        var tagName = (element.prefix ? element.prefix + ":" : "") + element.localName;
        var pathIndex = (index || hasFollowingSiblings ? "[" + (index + 1) + "]" : "");
        paths.splice(0, 0, tagName + pathIndex);
    }
    return paths.length ? "/" + paths.join("/") : null;
};

【问题讨论】:

标签: javascript xml xpath casperjs


【解决方案1】:

当您收听"page.error" 事件时,您会看到类似

错误:ReferenceError:找不到变量:getElementXPath

这与您在页面中包含该代码的方式有关。以下完整的脚本适用于我:

var casper = require('casper').create();

// http://docs.casperjs.org/en/latest/events-filters.html#page-error
casper.on("page.error", function(msg, trace) {
    this.echo("Error: " + msg);
    // maybe make it a little fancier with the code from the PhantomJS equivalent
});

casper.start('http://example.com');

casper.then(function() {               
    this.evaluate(function(){
        window.getElementXPath = function(element)
        {
            if (element && element.id)
                return '//*[@id="' + element.id + '"]';
            else
                return getElementTreeXPath(element);
        };

        function getElementTreeXPath(element)
        {
            var paths = [];
            // Use nodeName (instead of localName) so namespace prefix is included (if any).
            for (; element && element.nodeType == Node.ELEMENT_NODE; element = element.parentNode)
            {
                var index = 0;
                var hasFollowingSiblings = false;
                for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling)
                {
                    // Ignore document type declaration.
                    if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
                        continue;
                    if (sibling.nodeName == element.nodeName)
                        ++index;
                }

                for (var sibling = element.nextSibling; sibling && !hasFollowingSiblings;
                    sibling = sibling.nextSibling)
                {
                    if (sibling.nodeName == element.nodeName)
                        hasFollowingSiblings = true;
                }
                var tagName = (element.prefix ? element.prefix + ":" : "") + element.localName;
                var pathIndex = (index || hasFollowingSiblings ? "[" + (index + 1) + "]" : "");
                paths.splice(0, 0, tagName + pathIndex);
            }
            return paths.length ? "/" + paths.join("/") : null;
        };
    });

    this.echo(this.evaluate(function(){
        return getElementXPath(document.querySelector("a"));
    }));
});

casper.run();

输出:

/html/body/div/p[2]/a

诀窍是使getElementXPath 在页面上下文的全局范围内可用。这可以通过在window.getElementXPath 上设置变量来轻松完成。

【讨论】:

  • 为什么 jquery $("a:contains('text')") 不能代替 document.querySelector("a") 为输入参数工作?
  • $("a:contains('text')") 的输出是一个 jQuery 集合而不是一个元素。您需要检查该集合是否至少包含一个元素 var al = $("a:contains('text')"); if (al.length > 0) { ... },然后检索元素 al[0]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2015-07-14
  • 2023-03-22
  • 2013-04-28
  • 2011-11-15
相关资源
最近更新 更多