2016年7月12日火曜日

でんき家計簿のデータをMySQLに保存する(phantom.jsを使う)

先日、selenium+firefoxを使用したでんき家計簿のスクレイピング をやってみた。
次はphantom.jsを使ってcronで実行できるようにしたいと思った。

といっても、driverの部分を変えるだけ。
最初は、

var driver = new webdriver.Builder().forBrowser('phantomjs',phantomjs.path).build();

と書いていたんだけど、cronで実行するとphantom.jsのパスが見つからないと怒られてしまった。
調べてみると、適切な書き方があった。
var driver = new webdriver.Builder()
       .withCapabilities({"phantomjs.binary.path":phantomjs.path})
       .forBrowser('phantomjs')
       .build();
これでOK!

var argv = require("minimist")(process.argv.slice(2));
if(!argv.u || !argv.p){
console.log(process.argv[1] + ' -u [userid] -p [password]');
console.log('\toption -d DB Write Mode');
console.log('\toption -c Phantom Mode');
return 0;
}
if(argv.d){
if(!argv.dbhost || !argv.dbuser || !argv.dbpass || !argv.dbname || !argv.dbtblname){
console.log(process.argv[1]
+ ' --dbhost=[hostname] --dbuser=[username] --dbpass=[password] --dbname=[dbname] --dbtblname=[dbtblname]');
console.log(argv.dbhost);
console.log(argv.dbuser);
console.log(argv.dbpass);
console.log(argv.dbname);
console.log(argv.dbtblname);
return 0;
}
}
var webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
if(!argv.c){
var driver = new webdriver.Builder().forBrowser('firefox').build();
}else{
var phantomjs = require('phantomjs');
console.log(phantomjs.path);
// var driver = new webdriver.Builder().forBrowser('phantomjs',phantomjs.path).build();
var driver = new webdriver.Builder()
.withCapabilities({"phantomjs.binary.path":phantomjs.path})
.forBrowser('phantomjs')
.build();
}
driver.get('https://www.kakeibo.tepco.co.jp/dk/aut/login/');
driver.findElement(By.name('id')).sendKeys(argv.u);
driver.findElement(By.name('password')).sendKeys(argv.p);
driver.findElement(By.id('idLogin')).click();
/* 使用量と料金をグラフで見る */
driver.findElement(By.id('idNotEmptyImg_contents01.jpg')).click();
/* 時間別グラフはこちら */
driver.findElement(By.id('bt_time_view.jpg')).click();
/* データと日付を得る */
driver.getPageSource().then(function(pageSource){
var result = {};
getElectricityUsage(pageSource,result);
// console.log(JSON.stringify(result));
if(argv.d){
var mysqlid = { host : argv.dbhost,
user : argv.dbuser,
password : argv.dbpass,
database: argv.dbname};
writeDB(mysqlid,argv.dbtblname,result);
}
});
driver.quit();
function getElectricityUsage(pageSource,result) {
var findstr = 'var items = [["日次",';
var datePattern = /20\d\d\/\d\d\/\d\d/i;
var lines = pageSource.split('\n');
lines.forEach(function (line) {
var findindex = line.indexOf(findstr);
if (findindex != -1) {
var ElectricityUsage = line.substr(findindex+findstr.length).replace(/]];/g,"");
process.stdout.write(ElectricityUsage+"\n");
var ElectricityUsageArray = ElectricityUsage.split(",");
process.stdout.write("要素数:"+ElectricityUsageArray.length+"\n");
var ElectricityUsageValueArray = new Array();
ElectricityUsageArray.forEach(function (item) {
ElectricityUsageValueArray.push(parseFloat(item));
});
result['value'] = ElectricityUsageValueArray;
}
if (line.indexOf('の電気使用量') != -1) {
item = line.match(datePattern);
process.stdout.write(item[0] + '\n');
result['date'] = item[0].replace(/\//g,"-");
}
});
}
function writeDB(mysqlid,tblname,result){
var mysql = require('mysql');
var colname = "`0000-0030`,`0030-0100`,`0100-0130`,`0130-0200`,`0200-0230`,`0230-0300`,`0300-0330`,`0330-0400`,"
+"`0400-0430`,`0430-0500`,`0500-0530`,`0530-0600`,`0600-0630`,`0630-0700`,`0700-0730`,`0730-0800`,"
+"`0800-0830`,`0830-0900`,`0900-0930`,`0930-1000`,`1000-1030`,`1030-1100`,`1100-1130`,`1130-1200`,"
+"`1200-1230`,`1230-1300`,`1300-1330`,`1330-1400`,`1400-1430`,`1430-1500`,`1500-1530`,`1530-1600`,"
+"`1600-1630`,`1630-1700`,`1700-1730`,`1730-1800`,`1800-1830`,`1830-1900`,`1900-1930`,`1930-2000`,"
+"`2000-2030`,`2030-2100`,`2100-2130`,`2130-2200`,`2200-2230`,`2230-2300`,`2300-2330`,`2330-2400`";
var valline = "";
for(var i=0;i<48;i++){
if(i != 0) valline+=",";
valline+=result['value'][i];
}
console.log('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')');
var connection = mysql.createConnection(mysqlid);
connection.connect();
connection.query('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')',
function(error,results,fields){
if (error) {
console.error('error connecting: ' + error.stack);
return;
}
});
connection.end();
}
これを定期的に呼べばいい感じに電力使用量が入手できる。

2016年7月3日日曜日

でんき家計簿のデータをMySQLに保存する

でんき家計簿
 というサービスがある。

スマートメーターが設置されていれば、30分間隔の電力使用量が表示できる。
https://www.kakeibo.tepco.co.jp/dk/syo/electricUsage30MinGraph/

これをなんとかMySQLに保存したいと思った。
wgetでもごもごできるかなと思ったけど、認証があるしメンドクセー。
と思って数日経過し、ネットサーフィンしていたら、
すでに実現している人がいた。スゲー。
http://sirrow.info/archives/578

いろいろな技術を使っているのね。
  • minimist・・・コマンド引数パーサー
  • selenium-webdriver・・・Web自動テストツールらしい
  • phantomjs・・・ブラウザ画面のないQtWebKit ベースのブラウザらしい
 selenium-webdriver
 スクレイピングするツール?
https://www.npmjs.com/package/selenium-webdriver
http://www.seleniumhq.org/docs/03_webdriver.jsp#selenium-webdriver-api-commands-and-operations

PhantomJS
http://tips.hecomi.com/entry/20121229/1356785834
http://phantomjs.org/download.html
ふーん。キャプチャできた!

まずは
selenium-webdriver + firefoxででんき家計簿にアクセスしてみる
ほぼ前述の方と同じだ。 Orz
こんな感じ。
var argv = require("minimist")(process.argv.slice(2));
if(!argv.u || !argv.p){
console.log(process.argv[1] + ' -u [userid] -p [password]');
return 0;
}
if(argv.d){
if(!argv.dbhost || !argv.dbuser || !argv.dbpass || !argv.dbname || !argv.dbtblname){
console.log(process.argv[1]
+ ' --dbhost=[hostname] --dbuser=[username] --dbpass=[password] --dbname=[dbname] --dbtblname=[dbtblname]');
console.log(argv.dbhost);
console.log(argv.dbuser);
console.log(argv.dbpass);
console.log(argv.dbname);
console.log(argv.dbtblname);
return 0;
}
}
var webdriver = require('selenium-webdriver'),
By = webdriver.By,
until = webdriver.until;
var driver = new webdriver.Builder()
.forBrowser('firefox')
.build();
driver.get('https://www.kakeibo.tepco.co.jp/dk/aut/login/');
driver.findElement(By.name('id')).sendKeys(argv.u);
driver.findElement(By.name('password')).sendKeys(argv.p);
driver.findElement(By.id('idLogin')).click();
/* 使用量と料金をグラフで見る */
driver.findElement(By.id('idNotEmptyImg_contents01.jpg')).click();
/* 時間別グラフはこちら */
driver.findElement(By.id('bt_time_view.jpg')).click();
/* データと日付を得る */
driver.getPageSource().then(function(pageSource){
var result = {};
getElectricityUsage(pageSource,result);
// console.log(JSON.stringify(result));
if(argv.d){
var mysqlid = { host : argv.dbhost,
user : argv.dbuser,
password : argv.dbpass,
database: argv.dbname};
writeDB(mysqlid,argv.dbtblname,result);
}
});
driver.quit();
function getElectricityUsage(pageSource,result) {
var findstr = 'var items = [["日次",';
var datePattern = /20\d\d\/\d\d\/\d\d/i;
var lines = pageSource.split('\n');
lines.forEach(function (line) {
var findindex = line.indexOf(findstr);
if (findindex != -1) {
var ElectricityUsage = line.substr(findindex+findstr.length).replace(/]];/g,"");
process.stdout.write(ElectricityUsage+"\n");
var ElectricityUsageArray = ElectricityUsage.split(",");
process.stdout.write("要素数:"+ElectricityUsageArray.length+"\n");
var ElectricityUsageValueArray = new Array();
ElectricityUsageArray.forEach(function (item) {
ElectricityUsageValueArray.push(parseFloat(item));
});
result['value'] = ElectricityUsageValueArray;
}
if (line.indexOf('の電気使用量') != -1) {
item = line.match(datePattern);
process.stdout.write(item[0] + '\n');
result['date'] = item[0].replace(/\//g,"-");
}
});
}
function writeDB(mysqlid,tblname,result){
var mysql = require('mysql');
var colname = "`0000-0030`,`0030-0100`,`0100-0130`,`0130-0200`,`0200-0230`,`0230-0300`,`0300-0330`,`0330-0400`,"
+"`0400-0430`,`0430-0500`,`0500-0530`,`0530-0600`,`0600-0630`,`0630-0700`,`0700-0730`,`0730-0800`,"
+"`0800-0830`,`0830-0900`,`0900-0930`,`0930-1000`,`1000-1030`,`1030-1100`,`1100-1130`,`1130-1200`,"
+"`1200-1230`,`1230-1300`,`1300-1330`,`1330-1400`,`1400-1430`,`1430-1500`,`1500-1530`,`1530-1600`,"
+"`1600-1630`,`1630-1700`,`1700-1730`,`1730-1800`,`1800-1830`,`1830-1900`,`1900-1930`,`1930-2000`,"
+"`2000-2030`,`2030-2100`,`2100-2130`,`2130-2200`,`2200-2230`,`2230-2300`,`2300-2330`,`2330-2400`";
var valline = "";
for(var i=0;i<48;i++){
if(i != 0) valline+=",";
valline+=result['value'][i];
}
console.log('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')');
var connection = mysql.createConnection(mysqlid);
connection.connect();
connection.query('insert into '+tblname+'(date,'+colname+') values("'+result['date']+'",'+valline+')',
function(error,results,fields){
if (error) {
console.error('error connecting: ' + error.stack);
return;
}
});
connection.end();
}
得られたデータはこんな感じ。

ひさしぶりにすごいなと思った。