あちこちスクレイピングして、松山の鉄道・船・飛行機の運行状況をまとめるサイトを作ってみた
WebMatrix + Azure Web サイト(マイクロソフトのクラウド環境や開発ツールを無償提供 | Microsoft BizSpark、ありがとう!)で愛媛・松山の鉄道・船・飛行機の運行状況を集約したサイトを作ってみました(飛行機の英語の綴りミスなんかがボロボロ見つかる程度の成熟度です)。誰の役に立つというものでもないですが、自分的には満足です。そのうちわざわざサイトに行くのも面倒になると思うので、ゆくゆくは Twitter の BOT か何か作って、情報をプッシュできるようにしたいですね。
このサイトの情報は、大きく分けて二つの方法で取得しています。
- サイトをスクレイピングして情報取得(鉄道、船、JAL)
- (非公開)API を叩いて JSON から情報取得(ANA、ピーチ)
- (ジェットスターだけはうまくいかなかった! 今度誰か教えて!*1)
スクレイピングで面倒だったのは、情報の形式が一定していないこと、文字コードがバラバラなこと(ローカルでテストしているときは文字化けしないのに、クラウドで動かすと文字化けすることもあった)でしょうか。とくに情報の形式が一定していないのはしんどいですね。イレギュラーなケースを見つけるたびにデータ標準化のための処理が膨れ上がっていくので、最後は妥協、妥協、妥協。ペライチのページにコードをべた書きして、それをまとめていくという開発手法は WebMatrix が得意とする分野だと思うけれど、最後のほうはちょっと力不足かなって感じもしました。まぁ、そんなときはサクッと Visual Studio に切り替えちゃうんですけど。
開発の流れ
運行情報のページをブラウザーでみる。ブラウザーの開発者ツールで DOM をみたり、リクエスト・レスポンスをみたりしながら、静的ページであればスクレイピング、ページを動的に組み立てているなら API を探してそれを叩いてみるという感じ。
スクレイピングであれば、NuGet Gallery | HtmlAgilityPack 1.4.9 が超簡単。XPath でノードを指定してサクッと中身を取ってこれる。
using (var client = new WebClient()) { var response = client.DownloadString(url); var json = Json.Decode(response); var doc = new HtmlAgilityPack.HtmlDocument(); doc.LoadHtml(doc) // <div class="ss_comment">ここがほしいやで</div> var message = doc.DocumentNode .SelectSingleNode(@"//div[@class=""ss_coment""]") .InnerText; @ObjectInfo.Print(json) }
これが使えないならば、正規表現で頑張ることになるのかな。今回はそこまでしなければならないケースはなかった。
非公開 API があるのならば、JSON Helper が便利。Chrome の場合、開発者ツールの[Network]タブでリクエスト・レスポンスをみると、内部 API らしきものが見るかる。今回見つけたなかでは、ANA が出発・到着空港の天気までとれる重量級。一方、ピーチは割と扱いやすい感じ(ASP.NET っぽかった)。
using (var client = new WebClient()) { var response = client.UploadString(url, postData); var json = Json.Decode(response); @ObjectInfo.Print(json) }
ObjectInfo.Print で Json オプジェクトの中身をみながら、自分が使いやすいようにデータを取捨・加工する。
コーディング自体はとても簡単で、開発時間のほとんどは API のパラメーター解析に費やされた。
これから
閲覧時に情報を取りに行く設計になっているので、キャッシュが効いていない場合にロードがとても遅い。相手にも負荷がかかって迷惑*2なので、バックグラウンドで情報を取得するようにしたい。Twitter BOT にするにも必要な処理だし。