2013年2月20日星期三

CasperJS : 基于 PhantomJS 的javascript Web Crawler 工具

换到github了:casperjs笔记

简单试了一下 CasperJS ,基于PhantomJS引擎。

可以不搞图形窗口出来就网页截图,非常方便,值得一用。

示例集合:tests/suites/casper


Windows下安装过程:
1、在http://casperjs.org/下载zip文档,解压,把 casperjs/batchbin/ 目录加入PATH环境变量
2、在http://phantomjs.org/下载zip文档,解压,把 phantomjs 目录加入PATH环境变量


目前发现的问题:

写个小demo练手,把指定歌曲批量加入百度音乐收藏:baidu_music

代码示例:0320-casperjs



以登录百度为例

//初始化

//打log

//var casper = require('casper').create({logLevel: 'debug', verbose: true});


//不下载图片,不下载flash等等,可加速网页载入

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

  pageSettings: {

        loadImages: false, // do not load images

        loadPlugins: false // do not load NPAPI plugins (Flash, Silverlight, ...)

    }

});


//指定user-agent

casper.userAgent('Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:18.0) Gecko/20130119 Firefox/18.0');


//文件处理

var fs = require('fs');


//命令行参数

var usr = casper.cli.get(0);

var passwd = casper.cli.get(1);

var cookie_file = casper.cli.get(2);


//控制台输出

console.log("login baidu" );


//打开一个页面,有时要wait 1s再点击,不然有些js没load完,点击不生效

var login_url = 'https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F';

casper.start(login_url);

casper.wait(1000, function(){

    this.click('#pass-user-login');

});


//提交一个表单

casper.thenEvaluate(function(usr,passwd) {

    document.querySelector('#TANGRAM__3__userName').setAttribute('value', usr);

    document.querySelector('#TANGRAM__3__password').setAttribute('value', passwd);

}, { 'usr' : usr, 'passwd' : passwd });

casper.wait(1000, function () {

    this.click('#TANGRAM__3__submit');

});


//把cookie写入文件

casper.wait(1000, function () {

    var cookies = JSON.stringify(phantom.cookies);

    fs.write(cookie_file, cookies, 644);

    console.log("write cookie file : " + cookie_file +"\n");

});


//执行

casper.run();

以查找百度音乐为例

//从文件读入cookie

var cookie_file = casper.cli.get(0);

var data = fs.read(cookie_file);

phantom.cookies = JSON.parse(data);


//根据xpath表达式定位dom元素

var x = require('casper').selectXPath;

//...

var artist = "周华健";

var title="风雨无阻";

casper.then(function(){

        var song_x = artist ? '//a/em[text()="' + artist + '"]//ancestor::div[@class="song-item clearfix"]' : '';

        song_x +="//span[@class='song-title']//a[@title='" + title + "']";

        var collect_x = x(song_x);

        if (this.exists(collect_x)) {

            var id = this.getElementAttribute(collect_x,'href');

            song_id = id.replace(/#.*/, '').replace(/^.*\//, '');

        }

    });




以收藏百度音乐为例


casper.then(function(){

        if(song_id==0) return;

        var collect_url = 'http://music.baidu.com/song/' + song_id;

        this.thenOpen(collect_url, function(){

            console.log("visit url : " + collect_url);

            var collect_x = x('//span[text()="收藏"]/parent::span/parent::a');
 
            if (this.exists(collect_x)) {

                console.log("click collect button : "+song_id);

                this.click(collect_x);

            }

            this.wait(1000, function() {

                var artist = this.getElementAttribute('span[class="author_list"]', 'title')

                var title = this.fetchText('span[class="name"]');

                status = this.fetchText('div[class="song-page-share clearfix"] span span');

                status = status.replace('分享','');

                console.log("song "+ artist + "《 " + title +" 》 : " + status+"\n");

            });

        });

    });


支持指定FRAME点击其中的元素

这个参考github上官方给的例子就行了 tests/suites/casper/frames.js

不像perl的Win32::IEAutomation,点击frame里面的 <a onclick="javascript: xxx();">yyy</a> 总是失败,哎。。。


特定event出现时的处理

看官方介绍 Hook in the deep using events,包括各种触发事件,例如mousemove,弹alert,page载入完毕等等


casper.on('http.status.404', function(resource) {
    this.log('Hey, this one is 404: ' + resource.url, 'warning');
});


打印变量详情

require('utils').dump(x);

载入JQquery或其他本地JS

远程DOM能用:casper.page.injectJs('/path/to/jquery.js');

casperjs run着就一直能用:
 
var casper = require('casper').create({
    clientScripts: ["includes/jquery.min.js"]
});

设置Referer
var casper = require('casper').create();

casper.start().then(function() {
    this.page.customHeaders = {
        "Referer" : "http://video.ustc.edu.cn/"
    };
});

casper.thenOpen('http://202.38.64.10/').run();