About connecting the dots.

data science related trivial things

Chrome Developper ToolとCasperJSでスクレイピング

思い出したかのように再開している中古マンション売買データを分析してみたのシリーズですが,今回はちょっと脇にそれてデータ集めのお話について説明したいと思います.いわゆるスクレイピングというやつです*1.今回のデータを最初に集めたときは,たいした量でもなかったんで手動でデータをコピペしてたんですが,もう少しサンプル数を増やそうと思ったら,それだと限界があります.

とはいえ,実のところJavaScriptが個人的にあまり好きではないので,あれこれいじるのは辛いなーと,いくらかいじってはよーわからんとなっていました.そんな折,職場のJSエキスパートな方に軽く相談してみたら,ささっと解決したので,備忘録も兼ねてやり方をまとめておきたいと思いました,というのが今回の趣旨です*2

ChromeのDevelopper Toolでプロトイタイピング

Developper Toolの立ち上げ

ということで,実際にスクリプトを書く前に,まずはブラウザでプロトタイプを作っておきましょう.Chromeを立ち上げて,今回のターゲットページであるところのREINSのサイトにアクセスします.ショートカットキー"Ctrl+Shift+I"(Macの場合は"Cmd+alt+I")を押すと,以下のようにDevelopper Toolが立ち上がります.

http://f.st-hatena.com/images/fotolife/S/SAM/20141112/20141112231218_original.png

要素へのアクセスとセレクトフォームの選択

左上のElementsタブには,ページのhtml要素が表示されています.で,一番左の虫眼鏡アイコンを押すと,ページの要素を直接選択できるようになるので,まずは都道府県を選択するプルダウンメニューをクリックしてみましょう.

f:id:SAM:20141112231219p:plain

そうすると,当該要素のhtml要素が自動的に展開されます.今回の例では,以下のような要素があります.

<select name="prefCodeA" id="Address03" onchange="changeAreaSelectBoxElement('1')">...</select>

これを展開すると,以下のように都道府県のメニューが並んでいます.これのどれかを選択してあげれば,いいわけですね.

<option value="00">選択して下さい</option>
<option value="01">北海道</option>
<option value="03">岩手県</option>
<option value="04">宮城県</option>
<option value="07">福島県</option>
<option value="08">茨城県</option>
...(以下略)

Consoleでのインタラクティブな挙動確認

で,実際に選択の挙動を試してみるためには,Developper Toolの一番右のタブのConsoleを選択します.そうするとJSを入力して実際に動かすことができるようになるので,以下のスクリプトを打ってみましょう.すると,#Addressで指定されたIDの要素である,都道府県の選択ボックスの値が変わります.

// 選択して
var pref = document.querySelector("#Address03");
pref.selectedIndex = 1;
// changeイベントを実行 
var e = document.createEvent("HTMLEvents");
e.initEvent("change", false, true);
pref.dispatchEvent(e);

地域の選択も同様に以下のコマンドを打てば実行可能です.

<select name="areaCodeA" id="Address04" onclick="changeAreaDetailInfo(1)">...</select>
// 選択して
var reg = document.querySelector("#Address04");
reg.selectedIndex = 2; // 適当に
// clickイベントを実行 
e= document.createEvent("HTMLEvents");
e.initEvent("click", false, true);
reg.dispatchEvent(e);

アラートの無効化とフォームの送信

と,ここまで終わったらフォームをsubmitすればOKです.といいたいところですが,実際にはボタンを押すとアラートが立ち上がってしまいます.これだと都合が悪いですね.ということで,このアラートを抑制しましょう.アラートを起こすメソッドは,window.alert()です.JSは基本的に全てのメソッドについてオーバーライドが可能なので,このwindow.alert()を以下のように書き換えることで,アラートウインドウが立ち上がらないようにできます*3

window.alert = function() {}

ということで,これでようやくsubmitを実行することができます.「検索する」ボタンを虫眼鏡アイコンで選択すると,以下のようになります.ボタンを押すと,このsearchSubmit(1)メソッドが実行されるわけなので,そのままこれを打ち込んであげればOKです.

<a id="subA" href="javascript:searchSubmit(1);">
    <img id="srhA" src="../images/search_button.gif" alt="検索する" width="120" height="32">
</a>
searchSubmit(1);

すると無事画面遷移が発生して,結果画面に飛ぶことができました.あとはページを保存,要素を選択して保存...と繰り返すようなスクリプトを書いていけばOKですね.長くなるので今回は(以下略)にしてしまいます.

CasperJSで書き直す

上記手順で,だいたいどうすればページ遷移まで進めるかがわかりました.というわけで,これをJSのスプレイピングライブラリとしてわりとメジャーなCasperJSを使って書き直してみましょう.CasperJSについての説明はWeb上にいくらでもあるので,これとかこれあたりを読めばどんな感じのものかわかるかと思います.

で,個人的な好みの問題で,素のJavaScriptはとても触る気にならないので,今回はCoffeeScriptで書いてみます.こちらについてもこちらとかみていただければ,基本文法はわかるかと思います.

ということで,早速ですが,以下がCasperJS + CoffeeScriptで書き直した画面遷移用のスクリプトになります.別に特殊なことをしているわけではなく,単に書き下しただけですね.このスクリプトでは,ページ遷移後にページのソースを標準出力に出して終了します.

targetUrl = 'http://www.contract.reins.or.jp/search/displayAreaConditionBLogic.do'

casper = require('casper').create()

casper.start targetUrl

# select prefecture
casper.then ->
  @evaluate ->
    prefecture = document.querySelector('select#Address03')
    prefecture.value = '14'
    e = document.createEvent('HTMLEvents')
    e.initEvent('change', false, true)
    prefecture.dispatchEvent(e)

# select region
casper.then ->
  @evaluate ->
    region = document.querySelector('select#Address04')
    region.value = 'A1402'
    e = document.createEvent('HTMLEvents')
    e.initEvent('click', false, true)
    region.dispatchEvent(e)

# remove alert and submit
casper.then ->
  @evaluate ->
    window.alert ->
    searchSubmit(1)

casper.then ->
  @echo(@getPageContent())

casper.run ->
  @exit()

ということで,いろいろ試して楽しく(マナーを守って)スクレイピングしよう,というお話でした.

*1:Webスクレイピング勉強会@東京なんて勉強会も開催されていましたね.

*2:わからないことを自分一人で云々考え続けるのは,だいたいにおいていいことはないなぁと思わされますね.

*3:ここの部分,実行されるJSのメソッドの中身までみて,その処理を実行させることでアラートを抑制するやり方もあります.気が向けば追記します.