想了解一下中国现在空气质量的年度趋势,但是google找不到对应的年度曲线,只能看到最近24小时的数据,研究了一下,就自己动手做了一个简单的报表。

数据部分

数据来源中华人民共和国环境保护部数据中心, 这份官方公布的数据提供两种数据:

  1. 实时数据,粒度到每一个开放的监控点,相对准确,但是只提供最近几个小时内的数据,数据相对全面。
  2. 历史数据,独立到地级市级别,数据相对粗糙,相当于一个市级单位几个监控点的数据均值,所以,精确性相对较差。

另外一个更好的数据接口是pm25.in,这个是一个很好的网站,提供出了对应的api,但是只提供最近一个小时的数据。

这次的数据分析是直接采集官方的历史数据源,进行相对粗糙的数据分析。

工具

  1. Node.js
  2. Linux Shell
  3. D3.js chart

数据结果样例

下面是列出了10个重要城市的数据,其中:

  1. X轴是年度,分别为2014和2015年全年。
  2. Y轴代表天数,一年一共是365天。
  3. 不同的颜色代表具体的空气质量级别。


主体代码

下面数抓取数据的代码,抓取的数据结果为csv文件:

var fs = require('fs');
var fromYear = 2014;
var request = require('request');
var async = require('async');
var url;

var city = {
name: '北京市',
englishName: 'beijing'
};

function doQuery(pageId, callback){
require('sleep').sleep(3);
url = 'http://datacenter.mep.gov.cn/report/air_daily/air_dairy.jsp?city=' + encodeURIComponent(city.name) + '&startdate=' + fromYear + '-01-01&enddate='+(fromYear+1)+'-01-01&page=';
var u = {
uri:url+pageId,
headers:{
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Content-Type':'application/x-www-form-urlencoded'
}
};

request(u, function (error, response, body) {
console.log(u.uri);
if (!error && response.statusCode == 200) {
var firstIndex = response.body.indexOf('<area ');
var lastIndex = response.body.lastIndexOf('</map>');
var result = response.body.substring(firstIndex, lastIndex);
result = result.replace(/<area shape="rect" coords="[^"]+" title="/g, '').replace(/">/g, '');
console.log(result);
fs.appendFileSync(fromYear.toString(), result);

var regex = /总页数:<b><font color="#004e98">(\d+)<\/font>/;
var m = regex.exec(response.body);
if(m!=null){
var totalPages = m[1];
if(totalPages>pageId){
doQuery(++pageId, callback);
}
else{
console.log('completed, total pages:', totalPages);
callback(null, 1);
}
}
}
else{
console.log(error);
}
});
}

async.series([
function(callback){
fromYear = 2015;
doQuery(9, callback);
}
], function(err, results){
console.log("done,", err, results);
var exec = require('child_process').exec;
// exec('(echo 'year,2014,2015';(paste -d" " 20142 20152 | awk '{print "\""$1"\"" ","$3","$6}' ) ) > data.csv
var command = '(sort 2014 | uniq > 20142);(sort 2015 | uniq > 20152);(echo \'year,year2014,year2015\';(paste -d" " 20142 20152 | awk \'{print "\\""$1"\\"" ","$3","$6}\' ) ) > data-'+city.englishName+'.csv';
exec(command, function(err, stdout,stderr){
if(!stderr){
exec('rm 201*');
}
console.log(err, stdout, stderr);
});
});

抓取产出的数据样例:

year,year2014,year2015
"2014-01-01",85,65
"2014-01-02",158,79
"2014-01-03",74,200
"2014-01-04",165,226
"2014-01-05",113,122
"2014-01-06",190,60
"2014-01-07",122,85
"2014-01-08",32,190

具体生成图表都是用客户端的技术,下面是具体链接,可以通过查看源代码查看具体实现: