使用google chrome抓取数据:抓取全国的高中

KEY WORDS : Chrome插件 数据抓取


1.数据源

正在做一个网站,需要全国的中学数据,中学数据比较全的应该是人人网了,简单搜索发现 http://xuexiao.eol.cn/ 也有比较全的数据,并且还有地址信息,所以决定不从人人网抓取了。

2.抓取数据的思路

作为一名「优秀」的前端工程师,当然使用 javascrpt 来抓取啦,浏览器提供了便捷的 API,处理 DOM 信息比写后端程序方便太多了。

查看「中国教育信息」黄页——黄页这种叫法好像是很多年前的事情了,可以看到三部分,挨个遍历下去,并处理分页抓取学校名称就可以了。

数据源

思路如下:

  1. 获取左边的省份列表
  2. 处理该省份的城市
  3. 然后挨个分页抓取就行了

3部分对应的主要代码如下(网站已经提供了 jQuery 了):

//1. function getAllProv(){
  return ["北京", "上海", "天津", "四川", "安徽", "江苏", "浙江", "辽宁", "山西", "福建", "广东", "广西", "海南", "河南", "湖南", "陕西", "湖北", "江西", "河北", "山东", "重庆", "青海", "吉林", "云南", "贵州", "甘肃", "宁夏", "新疆", "西藏", "内蒙古", "黑龙江"];
}
//2. function setCurrentCitiesOfProv(prov){
  return $.map($(".quyu_list a"),function(a){
                               var query = a.getAttribute('href');
                               var val = getQueryStringParameter(query,"local2");
                               return decodeURI(val.replace('_local2',''));
                             });
}
//3. function savePageData(){
  var prov = getCurrentProv();
  var city = getCurrentCityOfProv(prov);
  var schools = $('.right_box');
  var rows = [];
  $.map(schools,function(school){
    var name = $('h2',school).text().trim();
    var detail = $('h3',school).text().trim();
    var parts = detail.split(/\s+/);

    var row = {};
    row.name = name;
    // row.prov = decodeURI(prov);
    row.city = city;

    $.each(parts,function(i,item){
      var o = {
          "地址":"address",
          "邮编":"mailno",
          "电话":"phone"
      };
      var ab = item.split(':');
      var key = o[ab[0]];
      row[key] = ab[1];
    });
    rows.push(row);
  })
  saveStore(rows);// 存储本页的数据
}
注意,上面的脚本只表示了三个步骤,不能直接运行

3.将脚本封装为 Chrome 插件

单个页面的逻辑已经处理完毕了,怎么让浏览器自动抓取下去呢?答案很简单:将脚本变为 chrome 的一个插件,每次 http://xuexiao.eol.cn/ 这个站点的页面载入后,都执行上面写好的脚本就行了,每页的学校数据处理完毕后,脚本自动改变 url,刷新获取下页的数据。

实现一个 chrome 插件,使用 userscript 的方式是最简单的,安装好插件后,插件载入一个脚本,之行上面描述的三步逻辑,并且自动刷新到下面一页。这里比较关键的一个步骤是存储所有的省份、城市,并计算出下页的的 url 。具体请看后面附的完整代码。

那么具体怎么实现呢?

  1. 创建一个 manifest.json,这个是 chrome userscript 的声明文件
  2. 创建一个 contentscript.js (名字随意,但是在 manifest.json 中要对应),这个脚本的作用仅仅是一个脚本加载器,载入 script.js 执行页面数据抓取逻辑。为什么要这样做呢?因为contentscript.js的之行环境和真是页面的执行环境是隔离的,也就是说contentscript.js的一个变量和页面中的变量可以独立存在,它们属于两个世界,这样做的好处在于,比如你可以独立的运行不同版本的jQuery,而不冲突。 javascript 虽独立运行,但是 dom 接口却是共享的,比如 document.createElement(‘script’) 创建一个脚本并插入到 dom 中,可以实现网页面载入一个脚本的目的, 可以将插件中的 script.js 插入运行中的文档中,每次页面载入都会执行 script.js 。
  3. 创建一个 script.js (名字随意,但是在 manifest.json 中要对应),用于处理真正的数据抓取逻辑。script.js 会将得到的数据存入 localStorage 中,那么所有载入的页面就可以共享这个数据了。

由于写文章的时候,数据抓取工作还没有完成,就不附上抓取的数据了,页面每秒中才刷新一次,并且只有一个页面在跑,比较慢。要数据的请联系我。

4.插件代码

https://github.com/WeweTom/chrome-extension-data-picker

使用google 地图做路线规划

KEY WORDS : google 地图 , 路书 , 地图旅游路线攻略


google的地图服务非常强大,这次就用它来做旅游路线攻略
Google Maps Engine

通常我们使用的是google maps https://maps.google.com.hk/ 这个服务,但是其实google
还有另一个地图服务,用于满足自定义地图的需求,这个服务就是 Google Maps Engine 。

这个服务有两个版本,免费版本只能创建两个图层,更多介绍可看 [1]

这个服务应该是今年3月份左右才推出的 [2],谷歌此前曾推出一个类似的地图定制工具My Maps

制作你自己的地图

A. 进入google地图,https://maps.google.com.hk,点击"制作地图

map

B. 可以创建一个地图,或者选择之前已经建好的地图

map

C. 点击地图标题,给你的地图命名

map

D. 点击”添加图层“
Google Maps Engine免费版本只提供两个图层,外加一个搜索结果层。
地图上可以放置有点和路线,点就是想去的地方,比如说西湖十景,就是十个点,十个标注。

这样创建两个图层,像下面这样,两个图层可以取个名字

map

map

E. 添加你你的兴趣点,比如景点、吃饭的地儿

a. 这些点可以是地图上默认就识别的,通过搜索框就可以搜索出来,搜索出来的点可以添加到地图

map

map

map

b. 或者你自己标注的点,方法是点上左上那个标注,然后在地图上点击

map

这样,标注好所有你想去的点了,每个点可以设置不同的颜色 , 黄色的是起点表示杭州火车东站,像下面这样:

map

F. 将点连接起来——路线规划

如何高效的将所有的点都去一遍呢,这个时候你需要规划路线

a. 点击路线图标

map

b. 添加起点(注意可以从你之前添加的点中选取地点)

map

map

c. 添加目的地(我发现了,mapengine 现在中文支持还不够好,需要给你的地点加个英文前缀,当是标号吧)

map

d. 添加多个目的地 (这里有限制,加上起点总共不能超过10个点,所以要节约着用,应该选取几个关键的连接点)

map

e. 把所有的地点都连上

map

G. 在手机上安装google map engine,打开”我的地图“,就可以看到自己规划好的路线了

外出手机在手,心中有路,从此不再迷惘

[完]

[1] http://www.williamlong.info/archives/3643.html

[2] http://www.williamlong.info/archives/3420.html

nodejs 中调用java

java由于其历史悠久,有很多有用的jar包,nodejs作为比较新的平台,相比之下还是有所欠
缺的。本篇文章介绍如何在nodejs中调用java程序,这样既能用你熟悉的js语言,又能享用
java的成熟工具。

下面以nodejs中调用 yuicompressor.jar 这个jar包进行压缩的示例来说明node调用java的
完整过程——尽管yuicompressor.jar已经很大程度上被uglifyjs代替了。

类似的,这个例子也可以调用 google 的压缩工具 compiler.jar

windows 环境中 nodejs 调用 java

  1. 确保你已经正确的安装了java,你可以通过下面的代码来检查是否安装成功
java -version

若看到类似下面的截图,表示安装成功了
Alt Text

  1. 用nodejs封装cmdline下的命令

下载yuicompressor.jar ,建立一个测试文件test.js,内容随便写点什么

在windows命令行中,压缩这个js的命令是:

java -jar yuicompressor.jar test.js

上面的命令实际上完整的是(windows有个cmd.exe来完成实际的工作)

cmd /c java -jar yuicompressor.jar test.js

nodejs提供了spawn工具来执行外部程序命令,详见 nodejs文档

完整的代码如下

var spawn = require('child_process').spawn;


exe(["/c","java","-jar","yuicompressor.jar","test.js"]);
// 相当于在命令行下执行 cmd /c java -jar yuicompressor.jar test.js
// 也可以加入更多的参数

function exe(command){
    // windows下 
    var cmd = spawn("cmd",command);

    cmd.stdout.setEncoding("ASCII");
    cmd.stdout.on("data",function(data){
    console.log("------------------------------");
    console.log("exec",command);
    console.log("stdout:"+data);
    });

    cmd.stderr.on("data",function(data){
    console.log("------------------------------");
    console.log("stderr:"+data);
    console.log("------------------------------");
    });

    cmd.on("exit",function(code){
    console.log("exited with code:"+code);
    console.log("------------------------------");
    });
};

将上面的代码保存为 node-compress.js,执行即可

node node-compress.js

linux 版本

linux 调用java不用像windows 那样:

cmd /c java -jar yuicompressor.jar test.js

而是直接调用

java -jar yuicompressor.jar test.js

即可

所以完整的代码是:

var spawn = require('child_process').spawn;

exe(["-jar","yuicompressor.jar","test.js"]);
// 相当于在命令行下执行 java -jar yuicompressor.jar test.js

function exe(command){

    // linux下,不用 cmd /c java -jar yuicompressor.jar test.js,这种形式,直接
    // java -jar yuicompressor.jar test.js 即可
    var cmd = spawn("java",command);

    cmd.stdout.setEncoding("ASCII");
    cmd.stdout.on("data",function(data){
    console.log("------------------------------");
    console.log("exec",command);
    console.log("stdout:"+data);
    });

    cmd.stderr.on("data",function(data){
    console.log("------------------------------");
    console.log("stderr:"+data);
    console.log("------------------------------");
    });

    cmd.on("exit",function(code){
    console.log("exited with code:"+code);
    console.log("------------------------------");
    });
};

raphaeljs 在 IE8 下性能差的问题及解决方案

Raphaël 具有良好的兼容——IE能兼容到ie6,非常适合国情,但是情况正在发生变化,尤其是
在国外,考虑到IE9以及其他浏览器的份额,Raphaël 的作者推出了一个叫 Snap.svg
图形库,跟Raphaël 不同,Snap.svg完全是基于svg的图行库,少了些束手束脚。

不过在国内,ie6/7/8/仍然不可忽视,因此Raphaël 仍然是比较好的选择。

微软从IE9开始支持svg矢量图形技术,Raphaël 在 ie6/7/8 上使用的是专有的vml技术来模
拟svg的特性。

vml在IE8浏览器下性能非常之差

我们知道,直到IE9才支持svg,微软必须跟上开放标准的潮流,vml的没落就像很多IE其它专
有特性一样,渐渐被抛弃,到IE8最终发布的时候,对vml的支持已经非常不好了 [1]


“vml\:*”这个选择器被IE8认为不合法

并且,相比IE6/7,IE8下vml性能问题差了很多,可以看 stackoverflow上的一个用户测试

测试代码如下:

<script src="http://fiddle.jshell.net/js/lib/raphael-1.5.2-min.js"></script>
<div id="time-result"></div>
<div id="canvas"></div>
<script>
window.onload = function() {
    var timer = new Date();
    var paper = Raphael('canvas', 400, 400);
    var length = 25;
    for (var i = 0; i < 10; i++) {
        for (var j = 0; j < 10; j++) {
        paper.rect(length * i, length * j, length, length);
        }
    }
    $('#time-result').text('Rendered in ' + (new Date() - timer) + ' milliseconds.');
};
</script>

Raphael IE8 性能差的应对方案

通过修改meta标签,让IE8运行在IE7模式下,于是有了

改进1

<meta http-equiv="X-UA-Compatible" content="IE=7" >

但是,如果仅仅是这样的化会误伤IE9 —— IE9 已经支持svg了,如果页面上还有这个声明的
化,那么IE9也会以IE7模式来渲染页面。抛弃svg而使用vml,这样显然是很不合理的。

我困惑了很久,想尝试使用IE的另一个奇葩特性——条件注释来避免这个问题:

改进2 ——失败的尝试

将meta标签放在条件注释中,像这样

<!doctype html>
<html>
  <head>
    <!--[if lt IE 9]>
    <meta http-equiv="X-UA-Compatible" content="IE=7">
    <![endif]-->
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>

  </body>
</html>

但是遗憾的是,浏览器根本就不识别这样注释后的meta标签,所以这种方案以失败告终

改进3 —— 通过在服务器返回的header中设置,这个方案我没亲自尝试过

但是,PHP使用者,可以尝试下面的方案 [2]

header("X-UA-Compatible: IE=7,IE=9");

改进4 —— 最终方案

因为,我找到了更好的方案了,其实很简单,只要在 方案1 的基础上,做一点改变

<meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" >

IE确实支持这样的写法,不过还是有坑的,在iframe下有问题,详细参看stackoverflow上的
讨论 [3]

[1] http://www.cnblogs.com/rubylouvre/archive/2009/10/12/1581891.html

[2] http://stackoverflow.com/questions/6156639/x-ua-compatible-is-set-to-ie-edge-but-it-still-doesnt-stop-compatibility-mode

[3] http://stackoverflow.com/questions/3413629/emulate-ie7-for-ie8-but-not-for-ie9-using-x-ua-compatible

ubuntu 13.10 通过chrome vnc viewer 插件连接 windows7

chrome 安装 vnc viewer 插件就不说了,具体看这里

关键在于,windows7 安装了vnc server 后,通过ubuntu上的vnc viewer 连接 不上的问题

原因在与,win7 默认开启了防火墙设置。具体解决步骤如下:

点击windows徽标,搜索防火墙,打开“高级安全 Windows防火墙”

step1

step2

step3

接下来下一步,到结束,起个名字再用vnc viewer 连接就能成功了

ubuntu 13.10 下面安装 grunt 报错

$ npm install grunt #产生报错
npm ERR! Error: No compatible version found: underscore.string@'~2.2.0rc'
npm ERR! Valid install targets:

原因是ubuntu13.10中的npm版本过低

$ npm -v
1.2.18

解决办法 ,用npm重新安装npm

$ sudo npm install npm -g

使用inkscape和fontforge制作iconfont

iconfont是通过矢量字体的方式来做icon,可以在高分辨率的屏幕上
也不会失真,能通过css来控制其样式,就像控制普通的文字一样。

像很多浏览器特性一样,使用iconfont是有兼容性问题的,要使用
iconfont,你不得不这样写字体声明:

@font-face {
  font-family: 'mui-wl';
  src: url('http://at.alicdn.com/t/font_1384420140_864115.eot');                                        /* IE9*/
  src: url('http://at.alicdn.com/t/font_1384420140_864115.eot?#iefix') format('embedded-opentype'),        /* IE6-IE8 */
  url('http://at.alicdn.com/t/font_1384420140_8889937.woff') format('woff'),                            /* chrome、firefox */
  url('http://at.alicdn.com/t/font_1384420140_8170962.ttf') format('truetype'),                            /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
  url('http://at.alicdn.com/t/font_1384420140_9259503.svg#svgFontName') format('svg');                    /* iOS 4.1- */
}

字体编辑的工具,windows平台下有fontlab配合AI能很好的生成
iconfont,具体介绍参看这里,CSS3 icon font完全指南

生成ttf格式的文件后,要兼容ie系列浏览器,还需要转为其它几种
格式

网上有一些工具能够进行字体转化的工具,能将ttf格式的字体文件,
转为各种格式的iconfont字体文件,比如这
个:http://www.fontsquirrel.com/fontface/generator

那么整个过程就完毕了,下面要介绍的是在linux环境下进行字体文
件的的制作


需要的环境

  1. inkscape ,用于生成字体路径
  2. fontforge ,linux下面的字体编辑器,需要忍耐下,界面非常丑,
    有很多快捷键

制作过程

  1. 准备好svg字体路径,可以用inkscape ,或者AI
    步骤一
  2. 用fontforge打开一个svg字体文件(也可以是ttf格式的),比如
    http://at.alicdn.com/t/font_1384420140_9259503.svg ,看到很多图形
    步骤二
  3. 点击一个字体空位,复制画好的svg路径到空位上
    步骤三
  4. 文件->生成字体,完成
    步骤四
  5. 借助上面的字体转换工具,将生成的ttf文件上传,生成其它格
    式的文件
  6. demo

需要注意的点

  1. fontforge 打开生成的ttf文件,前32个字符是不可见字符,如
    果你在这前32个字符中填充了图形也是没用的
  2. 如果你自己托管字体文件的的话,需要注意字体的跨域问题:
    firefox和IE9不支持对icon font字体的跨域。解决办法是在服
    务器的header中添加acceess-control

    http-header-access-control

总结

这样的制作过程还是比较麻烦的,但是能通过操作fontforge这个
软件,对字体文件有个感性的认识,再使用在线的工具的时候就不
会觉得完全是个黑箱了

更佳的方案——使用在线的工具

  1. http://fontello.com/
  2. http://icomoon.io/app

用iconfont实现loading的icon

语法

daringfireball

footnote语法

只有phpmarkdown支持


That's some text with a footnote.[^1]

[^1]: And that's the footnote.

table

| 项目        | 价格   |  数量  |
| --------   | -----:  | :----:  |
| 计算机     | $1600 |   5     |
| 手机        |   $12   |   12   |
| 管线        |    $1    |  234  |

链接复用

I get 10 times more traffic from Google than from
Yahoo or MSN.