CasperJS如何遍历一个网站的dom树,获取所有元素?

How to traverse the dom tree of a website and get all the elements in CasperJS?

我是网络开发的新手,任务是找到网页上的所有元素(例如,这里我想找到亚马逊上的所有元素,包括页眉、页脚、导航栏等),以及然后获取它们的位置和大小。(包括高度、宽度、顶部、底部、左侧、右侧等)我尝试使用 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. 时都会得到不同的 problems/warning

调试了很久,各种方法都试过了,还是不行。我想我需要把我的遍历函数放到 casper.evaluate() 中,但是网上关于如何使用它的教程太少了。那么有没有人可以帮我找到一个可行的方法来做到这一点?

这似乎是最简单的方法,我不确定你是否在某种程度上限制了你如何做到这一点,但我只是简单地做到这一点 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
}

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

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)

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

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

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

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

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;
        }
    }
});