NAVERまとめから位置情報を含むスポット情報をJSON形式で取得する
現在開発中の別のサービスのために、位置情報を含むスポット情報が欲しかったので、たまたま見つけたNAVERまとめからデータを取得するツールを作ってみました。
URL
概要
NAVERまとめのURLを入力すると、そのページにあるタイトル・説明と位置情報付きのスポット情報をJSON形式で返します。
(実行例)
入力:
http://matome.naver.jp/odai/2134519339022942401
出力:
{ "matome": { "title": "京都旅行で「カップルデート」にオススメの人気観光スポット", "discription": "日本国内でも、特に人気のデートスポットが京都です。京都には、古き良き町であったり、オイシイ食文化が残っています。京都旅行でオススメの人気観光スポットを紹介します!!" }, "location": [ { "spotName": "京都タワー", "address": "日本, 〒600-8216 京都府京都市下京区東塩小路町 京都タワー", "discription": "京都駅から下車してすぐの場所にあるので、アクセスは抜群です。1964年に建てられた古いタワーですが、京都のシンボルとして親しまれています。\n\n展望室営業時間:9:00~21:00\n大人:770円\nhttp://www.kyoto-tower.co.jp/", "image": { "thumbnailUrl": "http://rr.img.naver.jp:80/mig?src=http%3A%2F%2Fimgcc.naver.jp%2Fkaze%2Fmission%2FUSER%2F20120818%2F13%2F1169533%2F7%2F540x405x8c76a58e48ef57fe4f9388ef.jpg%2F300%2F600&twidth=300&theight=600&qlt=80&res_format=jpg&op=r", "originalUrl": "http://tkpkyoto.net/images/map_gckyoto_540.jpg", "sourceUrl": "http://tkpkyoto.net/access.shtml" }, "lat": 34.98752, "lng": 135.759301 }, { "spotName": "東本願寺", "address": "日本, 〒600-8505 京都府京都市下京区常葉町 東本願寺", "discription": "巨大な建物の数々を見れば、度肝を抜かれる事は間違いなし、本当に大きい木造建築は圧巻\n\n京都の寺が詰まらないと思っている人は、最初に京都駅から近い東本願寺に行きましょう。京都駅から歩いて行けて、世界最大の木造建築に驚きます。\n\nhttp://www.higashihonganji.or.jp/", "image": { "thumbnailUrl": "http://rr.img.naver.jp:80/mig?src=http%3A%2F%2Fimgcc.naver.jp%2Fkaze%2Fmission%2FUSER%2F20120820%2F13%2F1169533%2F28%2F1280x960xa5a79e5818e4780010691a1.jpg%2F300%2F600&twidth=300&theight=600&qlt=80&res_format=jpg&op=r", "originalUrl": "http://userdisk.webry.biglobe.ne.jp/001/247/64/N000/000/000/117603302339416302404.JPG", "sourceUrl": "http://kontomo.at.webry.info/200704/article_1.html" }, "lat": 34.9912688, "lng": 135.7587804 }, *長いので以下省略* }
フォーム入力だけでなく、APIもあります。
コーディング
構成は Node.js + Express + Heroku です。 前に作った Beatube IIDX ~ver.SPADA~ のソースをかなり流用したため、書いた量自体はほんのわずかですが、その中でポイントを2点ほど紹介します。
関数プロパティによるメモ化パターン
いわゆるキャッシュです。 同じURLに対するリクエストが2回以上来た時、(ページが更新されていなければ)結果は同じなのに毎回ページを取得して処理するのは無駄になります。 なので、関数のプロパティにURLをキーとしたハッシュを持たせておき、同じキーがある場合はその値を返すようにしました。
シングルトン
シングルトンとは、あるクラスのインスタンスを一つだけにする(何回newしても必ず同じインスタンスが作られる)というデザインパターンです。 今回のケースですと、インスタンス化した関数にキャッシュを持たせているため、どこかでもう一つ別のインスタンスが作られた場合に、また一からキャッシュをためることになります。 なので、このパターンを当てはめました。
exports.Scraping = function Scraping(){ // singleton // インスタンスをキャッシュする var instance = this; // ローカル変数 var request = require('request'); var cheerio = require('cheerio'); // 変換データのキャッシュ var cache = {}; /** * htmlのbodyを解析して位置情報のリストを返す * * @method getLocation * @return {Array} 位置情報のリスト */ this.getLocation = function(url, callback){ if(cache[url]){ return callback(cache[url]); } _getBody(url, function(error, body){ if(error) { return callback({}); } var $ = cheerio.load(body); var matomte = { title: $(".mdHeading01Ttl a").text() || "", discription: $(".mdHeading01DescTxt").text() || "" }; var location = []; $(".MdMTMWidgetList01 ._jWidgetData").each(function(){ var json = JSON.parse($(this).attr("data-contentdata")); // console.log(json); if(json.location){ var lo = { spotName: json.location.spotName || json.title, address: json.location.address, discription: json.description, image: { thumbnailUrl: json.thumbnailUrl, originalUrl: json.url, sourceUrl: json.sourceUrl }, lat: json.location.lat, lng: json.location.lng }; location.push(lo); } }); var result = { matome: matomte, location: location }; cache[url] = result; return callback(result); }); }; /** * リクエストのbody要素を返却する * * @method _getBody * @return {String} body要素 */ function _getBody(url, callback){ request({url: url}, function(error, response, body) { if(error || response.statusCode != 200){ // console.log(error); return callback(error); } // console.log(body); return callback(null, body); }); } // Singleton // コンストラクタを書き換える Scraping = function(){ return instance; }; };
今回参考としたページ
JavaScriptパターン ―優れたアプリケーションのための作法
- 作者: Stoyan Stefanov,豊福剛
- 出版社/メーカー: オライリージャパン
- 発売日: 2011/02/16
- メディア: 大型本
- 購入: 22人 クリック: 907回
- この商品を含むブログ (76件) を見る
- p44 3.2 カスタムのコンストラクタ関数
- p79 4.8 関数プロパティによるメモ化パターン
- p147 7.1 シングルトン
余談
Herokuに登録するとき、何を間違えたか無意識にURLを「json-parse-hatena.herokuapp.com」にしていて、デプロイした後に気づきましたw
この記事は、習慣化の手助けをするためのアプリ「TheHabit」に背中を押してもらって書いています。 (ブログを書くタスク:3回目)