百度的[echarts](http://echarts.baidu.com/)不错,推荐。
此外,阿里也开源了一个js库,专门画图:http://tbedp.github.io/datavjs/
example里的chinamap有几个中国地图的例子,很不错。
注意要放到web server下,通过url才能正常访问,直接文件夹解压不行。
2013年6月24日星期一
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载入完毕等等
打印变量详情
require('utils').dump(x);
载入JQquery或其他本地JS
远程DOM能用:casper.page.injectJs('/path/to/jquery.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();
简单试了一下 CasperJS ,基于PhantomJS引擎。
可以不搞图形窗口出来就网页截图,非常方便,值得一用。
示例集合:tests/suites/casper
Windows下安装过程:
1、在http://casperjs.org/下载zip文档,解压,把 casperjs/batchbin/ 目录加入PATH环境变量
2、在http://phantomjs.org/下载zip文档,解压,把 phantomjs 目录加入PATH环境变量
目前发现的问题:
- 网页内容比较长的时候,windows下有时会crash掉
- post到https的表单不成功(加ignore-ssl-errors就好了),windows下参考 https://github.com/n1k0/casperjs/issues/49#issuecomment-23147718
写个小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();
2011年9月12日星期一
笔记:JavaScript 高级程序设计 第2版 (Nicholas C.Zakas)
如果将document.domain设置为wrox.com之后,就不能再将其设置回p2p.wrox.com,否则将会导致错误。
使用innerText/innerHTML/outerText/outerHTML替换子节点可能会导致浏览器的内存问题,尤其是在IE中。最好先手工移除被删除子树中的事件处理程序及javascript对象属性。
addEventListener,最好将事件处理程序添加到事件流的冒泡阶段,可以最大限度的兼容浏览器。
添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。
CSRF 未被授权的系统伪装自己,让服务器认为它是合法的,从而获取某个资源。可选的方案:1)SSL连接;2)每次请求均附验证码。无效的方案:1)用POST而非GET;2)检查来源URL;3)验证cookie。
如果某个域的资源并没有允许访问,javascript就不应该能够请求该域中的资源。js默认只能访问包含它的页面的同一个域下的资源。
跨域请求和响应中不应携带cookie,且要确保未经授权无法访问相应资源。
访问内部资源时用相对url,访问远程资源时用绝对url。
json解析很快,但是eval()比较危险,需要对传给eval的参数进行检查,避免恶意内容XSS的攻击。
同源策略:相同的域,相同的端口,相同的协议
cookie数据并非存储在一个安全环境中,其中包含的任何数据都可以被他人访问。
不要在客户端机器用javascript存储敏感数据,因为数据缓存并不加密。
避免创建多个全局变量和函数,使用命名空间。
最小化现场更新,即,最小化对用户的显示进行更新,可以使用文档碎片createDocumentFragment。
HTML跨文档消息传递,用于支持不同域名的文档通信;不允许对另一个文档的DOM和相关信息直接访问,但允许发送和接收包含数据的消息。
使用innerText/innerHTML/outerText/outerHTML替换子节点可能会导致浏览器的内存问题,尤其是在IE中。最好先手工移除被删除子树中的事件处理程序及javascript对象属性。
addEventListener,最好将事件处理程序添加到事件流的冒泡阶段,可以最大限度的兼容浏览器。
添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。
CSRF 未被授权的系统伪装自己,让服务器认为它是合法的,从而获取某个资源。可选的方案:1)SSL连接;2)每次请求均附验证码。无效的方案:1)用POST而非GET;2)检查来源URL;3)验证cookie。
如果某个域的资源并没有允许访问,javascript就不应该能够请求该域中的资源。js默认只能访问包含它的页面的同一个域下的资源。
跨域请求和响应中不应携带cookie,且要确保未经授权无法访问相应资源。
访问内部资源时用相对url,访问远程资源时用绝对url。
json解析很快,但是eval()比较危险,需要对传给eval的参数进行检查,避免恶意内容XSS的攻击。
同源策略:相同的域,相同的端口,相同的协议
cookie数据并非存储在一个安全环境中,其中包含的任何数据都可以被他人访问。
不要在客户端机器用javascript存储敏感数据,因为数据缓存并不加密。
避免创建多个全局变量和函数,使用命名空间。
最小化现场更新,即,最小化对用户的显示进行更新,可以使用文档碎片createDocumentFragment。
HTML跨文档消息传递,用于支持不同域名的文档通信;不允许对另一个文档的DOM和相关信息直接访问,但允许发送和接收包含数据的消息。
2011年8月3日星期三
笔记:JavaScript 权威指南
chapter 1 - 10
变量没有块级作用域,在函数中任意位置定义的变量,在整个函数体都可用
函数使用变量时,先从局部作用域开始找,然后才是全局作用域
typeof(null) 返回的是object,而不是undefined
void舍弃运算数的值,返回undefined
抛出异常 if(x<0) throw new Error(“x must not be negative”); 后javascript解释器会跳转到最近的异常处理器(一直往上找,如果没找到就作为错误处理)
try/catch/finally块,finally一定会执行,就算try中间要跳走,也要等finally执行了再说
object.property 这个属性名是标识符,静态对象硬编码,比较像C++中的静态对象
object[“property”] 这个属性名是字符串值,可以动态指定,相当于关联数组
slice函数返回指定数组的一个片段,splice函数用于插入或删除数组元素
search函数返回第一个匹配的位置
replace函数是正则替换
match函数是正则匹配
exec函数是每次调用执行一次匹配尝试,index往前走
test是尝试匹配一次,返回true/false
chapter 11
function定义的函数使用词法作用域
var x = “global”;
function f() {
var x = “local”;
function g() { alert(x); }
g();
}
f(); //打印出local
Function() 创建的函数不使用词法作用域,而是当作顶级作用域编译
var y = “global”;
function constructFunction() {
var y = “local”;
return new Function(“return y”);
}
alert(constructFunction()()); //打出global
chapter 12
html解析器遇到script时,必须停止解析文档,等待script执行。如果script指定defer属性,表示这块script不生成任何文档输出,浏览器可以继续解析html文档,推迟执行script
脚本执行过程是浏览器进行HTML解析的一部分,如果一个脚本在<head>出现,那么该文档的<body>就还没有被定义,也就是说文档主体还没有被创建,脚本不能对它作操作
onload是当文档或框架被完全装载时调用的,onunload是在刚要卸载页面之前执行的(浏览器要显示新页面了)
reload()重新载入当前页面,replace()替换当前页面(history会失效)
如果一个frame设置了name,例如<frame name=”test_frame” src=”test.html”>,则兄弟框架可以用parent.test_frame引用之
document.write()动态生成文档
cookie的secure属性为真时,表示只有在https和安全协议连在一起时被传输
变量没有块级作用域,在函数中任意位置定义的变量,在整个函数体都可用
函数使用变量时,先从局部作用域开始找,然后才是全局作用域
typeof(null) 返回的是object,而不是undefined
void舍弃运算数的值,返回undefined
抛出异常 if(x<0) throw new Error(“x must not be negative”); 后javascript解释器会跳转到最近的异常处理器(一直往上找,如果没找到就作为错误处理)
try/catch/finally块,finally一定会执行,就算try中间要跳走,也要等finally执行了再说
object.property 这个属性名是标识符,静态对象硬编码,比较像C++中的静态对象
object[“property”] 这个属性名是字符串值,可以动态指定,相当于关联数组
slice函数返回指定数组的一个片段,splice函数用于插入或删除数组元素
search函数返回第一个匹配的位置
replace函数是正则替换
match函数是正则匹配
exec函数是每次调用执行一次匹配尝试,index往前走
test是尝试匹配一次,返回true/false
chapter 11
function定义的函数使用词法作用域
var x = “global”;
function f() {
var x = “local”;
function g() { alert(x); }
g();
}
f(); //打印出local
Function() 创建的函数不使用词法作用域,而是当作顶级作用域编译
var y = “global”;
function constructFunction() {
var y = “local”;
return new Function(“return y”);
}
alert(constructFunction()()); //打出global
chapter 12
html解析器遇到script时,必须停止解析文档,等待script执行。如果script指定defer属性,表示这块script不生成任何文档输出,浏览器可以继续解析html文档,推迟执行script
脚本执行过程是浏览器进行HTML解析的一部分,如果一个脚本在<head>出现,那么该文档的<body>就还没有被定义,也就是说文档主体还没有被创建,脚本不能对它作操作
onload是当文档或框架被完全装载时调用的,onunload是在刚要卸载页面之前执行的(浏览器要显示新页面了)
reload()重新载入当前页面,replace()替换当前页面(history会失效)
如果一个frame设置了name,例如<frame name=”test_frame” src=”test.html”>,则兄弟框架可以用parent.test_frame引用之
document.write()动态生成文档
cookie的secure属性为真时,表示只有在https和安全协议连在一起时被传输
2010年1月29日星期五
Simply JavaScript : Chapter 3
把当前页面改为黑底白字:
var body = document.getElementsByTagName("body")[0]; body.style.backgroundColor = "#000000"; body.style.color = "#FFFFFF";
2010年1月17日星期日
Simply JavaScript : Chapter 2
函数参数列表:
debate("affirmative", "negative"); function debate() { var affirmative = arguments[0]; var negative = arguments[1]; }
新建一个对象:
var Robot = new Object(); Robot.metal = "Titanium"; Robot.killAllHumans = function() { alert("Exterminate!"); }; Robot.killAllHumans(); //或者 var Robot = { metal: "Titanium", killAllHumans: function() { alert("Exterminate!"); } };
2009年6月30日星期二
vim : JavaScript 配置
代码整理:
jsbeautify.vim
语法:
JavaScript syntax : Better JavaScrirpt syntax support
缩进:
Javascript Indentation : Indentation for Javascript
vim-javascript
检查:
安装JavaScript Lint程序,使用javaScriptLint.vim插件,配置参考 Integrating JavaScript lint with vim
代码压缩解压:
packer(js),jsPacker.pl(Perl)
jsbeautify.vim
语法:
JavaScript syntax : Better JavaScrirpt syntax support
缩进:
Javascript Indentation : Indentation for Javascript
vim-javascript
检查:
安装JavaScript Lint程序,使用javaScriptLint.vim插件,配置参考 Integrating JavaScript lint with vim
代码压缩解压:
packer(js),jsPacker.pl(Perl)
jsPacker.pl -i some.js -o some-pack.js -e 10 -fs
订阅:
博文 (Atom)