Java
スクレイピング
mozilla
PhantomJS
SWT

Javaですべての上場企業のと地方自治体のサイトをスクレイピングして大変だったこと

More than 3 years have passed since last update.

私は主にJavaを使って大量のサイトからクロールとスクレイピングをしています。

作っているサイトは

happyou.info

です。上場企業と官公庁と地方自治体とその他1万サイトくらいスクレイピングしています。

このエントリでは、技術的なこと特にめんどうくさかった点を書き残しておきたいと思います。基本的なことかもしれませんが、私自身忘れそうなところもあるので。


1.上場企業は企業が入れ替わる

上場企業は毎日企業が入れ替わります。新規上場、上場廃止、合併、分社化、企業名変更は毎日のことです。この変化にキャッチアップするのが難しかったです。

日本取引所グループ

「よし上場前からきっちりスクレイピングして事前に準備しておくぞ」と思っても、上場にあわせてサイトをリニューアルしたりする企業も多いので油断なりません。 官公庁のサイトは、民間企業に比べるとはるかに移転が少なく落ち着いています。

地方公共団体情報システム機構


2.ページのダウンロードが難しい

何種類かのダウンロードを用意しておく必要がありました。

(2-a) 大半のページはwget (java.net.HttpURLConnection相当)で対応できます。

(2-b) そのページがajaxやJavaScriptなどを使って動的に生成されている場合は、 PhantomJS を使ってダウンロードするのが一般的です。ただ、PhantomJSは結構な頻度で文字化けするので、文字化けが起きていないかどうかチェックする必要がありました。

(2-c) まれにPhantomJs でもダウンロード出来ないページが存在します。 動的なダウンロードの先にさらに動的なページが存在したり、その先にあのAdobeFlashが読み込まれる場合などです。 このケースでは、私はEclipse SWT の SWT WidgetsXULRunnerを用いました。自前のGUIのウィンドウの中にFirefoxを埋め込みます。

この方式の良い所は、実質的にFirefoxなので、ブラウザの挙動をabout:config と同等のレベルで細かく制御できる点です。画像を読み込まない設定にしたり、勝手に印刷ダイアログが立ち上がったりしないような設定を行いました。

<input type='button' onClick="javascript:jump_to_other_page()">...

等のリンクにも対応出来ます。

欠点としては、実際にブラウザを立ち上げてページの内容を描画してしまうので、CPUとメモリを消費してしまう点が挙げられます。1ページなら問題ありませんが、多数のページを同時にダウンロードすると大変なことになります。あとブラウザなのでやはり落ちます。勝手に巨大なページをダウンロードし始めCPU100%になったりもします。 そのためクローラ本体とは別のVMに切り離しておく必要がありました。

(2-d) それでもダウンロード出来ないページがさらにまれに存在します。このようなケースに遭遇した場合は、私はウェブアプリケーションのテストに用いられているSelenium を使いました。 Seleniumは非常にすばらしいテストフレームワークですが、クローラとしては超ゆっくりで負荷もかけられません。最後の手段として使っています。

(2-e) 相手サーバに負荷のかからないように。


  • アクセスは5-10秒の間隔を空けています。robots.txtにそれ以上インターバルが指定されている場合はその指定を守ります。


  • アクセスしてはいけないフォルダには触れないようにします。仮にrobots.txtに指定がなかったとしても、定番として指定されるところの/wp-admin/,/wp-content/,/wp-includes/, /xmlrpc.php, /trackback/ といったディレクトリにはアクセスしないようにしています。


  • HTTPリクエストを送る際に、If-Modified-Sinceヘッダを使って、前回アクセスした時刻から変更がないかどうかをチェックします。 ステータスコード304 Not Modified が戻ってきたら、Body本体のダウンロードは省略されることで、結果的に相手のWebサーバにかかる負荷は小さくなります。



3.Adobe Flashの対応

主に企業のサイトではトップページやナビゲーションメニューに Adobe Flashが使用されているケースがあります。 私は、swfデータをxmlテキストに変換するswfmill というツールを利用しました。この変換器でxmlに変更し、xml中のURLっぽい文字列を正規表現で抽出しています。 そしてswfを「リンクが列挙されているだけのシンプルなHTMLページ」として変換しフレームと同じ扱いとして処理しました。 ゲームなどではもっと細かく解析する必要があるのかもしれませんが、クローラとしてはリンク先が取得できれば良いので、これで十分でした。世間的にもFlashさんは役割を終えつつあるようですね。長い間、お疲れ様でした。


4.現実世界のHTMLは美しくない

こうしてダウンロードされたHTMLページですが、その内容は、キレイではありません。CMSを使っているかどうかもあまり問題ではないよう(むしろ…)。この生HTMLをパースするのがまず大変でした。それを何事もなかったかのようにそれなりに表示してくるウェブブラウザって凄い!

Mozilla Developer Network

しかし、使ってゆくにつれ、ブラウザのパーサは表示するために最適化されていて、解析するためには使い辛いことがわかってきました。現在ではJava製のHTMLパーサを複数組み合わせて使っています。


5.パターン認識プログラム

このようにしてダウンロードし整形されたHTMLを元データにしています。この元データに対してパターン解析を行い、繰り返しのパターンを発見することで更新情報を抽出しています。パターン解析は長い道のりであるため、とてもブログでは書ききれません。

最後に宣伝です。

happyou.infoはあらゆる分野のサイトを網羅的にスクレイピングし、更新情報をお届けできます。個々の更新情報に自動的にタグを付けて分類しています。Web APIにも対応しました。ぜひご検討ください。

happyou.info

以上です。 こんな泥臭い作業でしたが、この文章が誰かの役に立てたのならそれで十分です。 次はプッシュ通知に対応したいですね!任意のサイトの更新がプッシュ通知でわかったら便利かな‐と思うんですよ。