如何遍历网站的dom树并获取CasperJS中的所有元素?

时间:2015-11-18 18:02:32

标签: javascript dom phantomjs casperjs dom-traversal

我是网络开发的新手,任务是找到网页上的所有元素(例如,我想在亚马逊上找到所有元素,包括页眉,页脚,导航栏等),然后获取所有这些的位置和大小。(包括高度,宽度,顶部,底部,左侧,右侧等)我尝试使用CasperJS和PhantomJS来完成它,这是我的代码:

casper.start('http://www.amazon.com/s?url=search-alias=aps&field-keywords=watches', function(){
});

var objarr = [];

casper.then(function(){
  var tmp = this.evaluate(function() {
    return document.getElementsByTagName("html")[0]; //get the html and traverse all it children
  }
  traverseDOMTree(tmp);

  for (var i = 0; i < objarr.length; i++){
        var isvalid = judge(objarr[i]); //judge whether the elemnet is null.
        console.log(i+1);
        if (isvalid && i != 0) {
          console.log(objarr[i].textContent);
        }
  }
});

function traverseDOMTree(root) //traverse function
{
  if (root)
  {
    for (var i = 0; i < root.childNodes.length; i++){
        objarr.push(root.childNodes[i]);
        traverseDOMTree(root.childNodes[i]);
    }
  }
}

function judge(obj){ 
  if (obj == null) { 
    console.log("The object is NULL");
    return false;
  }
  //If it is not null, get its location and height with width
  console.log("___________________________");
  console.log("The offsetTop is ", obj.offsetTop);
  console.log("The offsetLeft is ", obj.offsetLeft);
  console.log("The height is", obj.clientHeight);
  console.log("The width is", obj.clientWidth);
}

所以我的方法首先得到DOM树的根,即document.getElementsByTagId("html")[0]。然后我遍历它的所有子节点并将我找到的所有元素放入一个数组中。但是,这里有几个问题:

  1. 我发现的大部分元素都是空对象。
  2. 遍历功能似乎只能在同一级别上运行,不会继续遍历。
  3. CasperJS似乎不稳定,因为每次尝试跑步时都会遇到不同的问题/警告。
  4. 我已经调试并尝试了很长时间的不同方式,但我仍然无法成功。我想我需要将我的遍历函数放入casper.evaluate(),但是关于如何在网络上使用它的教程太少了。那么有没有人可以帮我找到一个可行的方法呢?

3 个答案:

答案 0 :(得分:1)

CasperJS构建于PhantomJS之上,并继承了其中一些缺点,如两个不同的上下文。您只能通过沙盒casper.evaluate()函数访问DOM(页面上下文)。它不能使用在外部定义的变量,并且您传入或传出的所有内容都必须是基元。 DOM节点不是基元。请参阅文档(page.evaluate()):

  

注意: evaluate函数的参数和返回值必须是一个简单的原始对象。经验法则:如果它可以通过JSON序列化,那就没关系了。

     

闭包,函数,DOM节点等将工作!

这意味着您必须在页面上下文中执行所有操作,因为您直接在这些DOM节点上工作。您可以在完成遍历时将结果传递出页面上下文。

或者您可以简单地移动页面上下文中的所有内容并注册到&#34; remote.message&#34;事件:

casper.on("remote.message", function(msg){
    this.echo("remote> " + msg);
});

casper.then(function(){
    this.evaluate(function() {
        var tmp = document.getElementsByTagName("html")[0]; //get the html and traverse all it children
        var objarr = [];

        traverseDOMTree(tmp);

        for (var i = 0; i < objarr.length; i++){
            var isvalid = judge(objarr[i]); //judge whether the elemnet is null.
            console.log(i+1);
            if (isvalid && i != 0) {
              console.log(objarr[i].textContent);
            }
        }

        function traverseDOMTree(root) //traverse function
        {
            if (root)
            {
                for (var i = 0; i < root.childNodes.length; i++){
                    objarr.push(root.childNodes[i]);
                    traverseDOMTree(root.childNodes[i]);
                }
            }
        }

        function judge(obj){ 
            if (obj == null) { 
                console.log("The object is NULL");
                return false;
            }
            //If it is not null, get its location and height with width
            console.log("___________________________");
            console.log("The offsetTop is ", obj.offsetTop);
            console.log("The offsetLeft is ", obj.offsetLeft);
            console.log("The height is", obj.clientHeight);
            console.log("The width is", obj.clientWidth);
            return true;
        }
    }
});

答案 1 :(得分:0)

这似乎是最简单的方法,而且我不确定你是否会以某种方式限制你如何做到这一点,但我会在普通的javascript中这样做:

var allElements = document.getElementsByTagName("*");
var element, index = 0, length = allElements.length;
for ( ; index < length; index++) {
    element = allElements[index];
    // get whatever information you want from the element
}

答案 2 :(得分:0)

最简单的方法就是获取所有元素:

document.getElementsByTagName("*");

但是如果你想用递归来实现它:

function traverse(node, elems){
  if(node){
    elems.push(node)
    var childs = node.childNodes;
    for(var i=0;i<childs.length;i++){
      traverse(childs[i],elems)
    }
  }
}

domElements = []
traverse(document.getElementsByTagName("html")[0], domElements)

console.log(domElements)