目的
郵便局のサイトでは http://www.post.japanpost.jp/cgi-zip/zipcode.php?zip=100-0001 といったURLで、郵便番号から住所を引くことができます。
ただ何かしらの自動処理に組みこもうとすると、APIは提供されておらず、更新あるたびにCSVダウンロードするのも面倒なので、スクレイピングしてみました。(zipcloudなどの外部API化サービスには後で気づきました……)
※郵便局のサイトは、robots.txtと利用規約を見るかぎり自動アクセスを禁止していないようです。アクセス頻度は常識的な範囲にとどめてください。
Nightmare
Nightmare(v2)は、Electronベースのブラウジング自動化ライブラリです。
今回はページ取得だけに使う……のは寂しいので、 http://www.post.japanpost.jp/zipcode/index.html の検索フォームからわざわざページ遷移してみます(ぉぃ
HTML
本記事投稿時点では、class="data"
で引っかけると住所のテキストが見つかります。
<tr>
<td class="data"><small>100-0001</small></td>
<td class="data"><small>東京都</small></td>
<td class="data"><small>千代田区</small></td>
<td>
<div class="data">
<p><small><a href="zipcode.php?pref=13&city=1131010&id=46366&merge=">千代田</a></small></p>
<p class="comment"><small>チヨダ</small></p>
</div>
</td>
コード
Nightmare公式の実行例では非同期制御のため、coに似たvoというライブラリを使っていますが、ここでは標準のPromise.resolve
でPromise
化してみました。
APIドキュメントには書いてないですが、Nightmareはthen
というメソッド持っているので、Thenableっぽいです。また、coやvoでもyield
構文で使えるので、Yieldableでもあるみたい。
'use strict';
var Nightmare = require('nightmare');
var nightmare = Nightmare();
Promise.resolve(
nightmare.
goto('http://www.post.japanpost.jp/zipcode/index.html').
type('input[name="zip"]', process.argv[2]).
click('input[src="/img/zipcode/btn_add_search_s.gif"]').
wait('.data').
evaluate(() => {
var data = document.getElementsByClassName('data');
return {
zip: data[0].innerText,
pref: data[1].innerText,
city: data[2].innerText,
aza: data[3].children[0].innerText
};
}
)
).
then((address) => {
console.log('〒' + address.zip + ' ' + address.pref + address.city + address.aza);
}).
catch(console.error);
nightmare.end();
直感的にメソッドチェーンできて良いですね><b
きちんとセレクタで掴めているか確かめる際は、Nightmare({fullscreen: true});
として適当にwait()挟んでおくと、ブラウジングの様子が見れて便利です。
実行結果
> node main.js 1000001
〒100-0001 東京都千代田区千代田
yield
とかPromise
使っているので、node環境によっては--harmony
オプション必要かも。
環境
{
"dependencies": {
"nightmare": "^2.0.7"
}
}
> node -v
v4.2.1