スマホでもPCでも遊べます
抜けているのは一番右下のパネルです。
登場するのは可愛い動物たちですよ。
第1問目
3x3バージョン | 4x4バージョン |
第2問目
3x3バージョン | 4x4バージョン |
第3問目
3x3バージョン | 4x4バージョン |
第4問目
3x3バージョン | 4x4バージョン |
第5問目
3x3バージョン | 4x4バージョン |
3x3バージョン | 4x4バージョン |
3x3バージョン | 4x4バージョン |
3x3バージョン | 4x4バージョン |
3x3バージョン | 4x4バージョン |
3x3バージョン | 4x4バージョン |
とにかくurlwatchでうまくいかなかった部分ができるようになったスクリプトをPythonで書いてしまおうというのが目標です。
具体的にはこの3点でしょうか。これに加えてパフォーマンスがよければ言うことなしです。
urlwatchのソースを参考に、ファイルをWEBからとってくる部分と、ファイルを比較する部分に分けて考えていくことにしました。
そして、ファイルをWEBからとってくる部分については、ダウンロードした元ファイルを残すという方針があるわけですから、こちらは比較的簡単でした。
urlwatchを見習って、URLをハッシュ化したものをファイル名にすることにしました。
URLそのままですと、ファイル名に使えない文字が入ってしまう可能性があります。ファイル名に使えない文字というのはOSによって異なったりするので、変に置換すると収拾がつかなくなったりしますので、ハッシュ値のほうが取り回しやすいだろうと考えました。
次にフィルタ部分をどうするかを考えました。
ありがちなのは、例えば、「あなたは○人目のお客様です」とか「今日のお天気は晴れです」とかいった、更新をチェックする意味はないけれども、毎回のように更新されている部分をHTMLから取り外す処理です。
これは正規表現でやるにはかなり無理があります。
やはり正攻法で、HTMLをパースして、XPath式か、CSSセレクタのようなもので、読み取る範囲や削除する範囲を指定する方向で考えたほうがよいようです。
問題になるのは、動物園のWEBサイトがどれくらい正当なHTMLで記述されているかという部分です。
こればっかりはやってみないと分かりません。
とりあえず、WEBを検索して、2つのパーサが候補になりました。
一つはlxml。とにかく高速なのが売りです。
もう一つはbeautifulsoup。こちらはエラー含みのHTMLの処理が得意です。
安直に考えて、まずはlxmlで試して、どうしてもうまくいかなかったら、例えばそのサイトだけbeautifulsoupで処理すればとても効率がよさそうです。
というわけで、lxmlを使うところから始めたのでした。
lxmlを試すにあたって、まずは札幌市円山動物園のWEBサイトにアクセスしました。北から順、というか、都道府県コードでいくとどうしてもこの動物園がトップにきますので。
ここのWEBサイトはxhtmlでutf-8で書かれています。HTML-lintを通したところ、「53個のエラーがありました。このHTMLは 78点です。」という結果がでました。まずまずの出来ではないでしょうか。
で、これをlxml.htmlでパースすると、とりあえず、無事読み込んでくれているようです。
抽出したい部分をXPath式で指定すると、うまくいきます。
これはいけそうだというので、続いて旭山動物園。こちらはいきなりフレームレイアウトで文字コードはShift_JIS。これだけ人気の動物園でも、WEBサイトはこんなものなのですね。
どうもホームページビルダーを使っているようなのですが、WEBサイト担当の方とか、業務量的に大変ではないでしょうか。
こちらもlxml.htmlでパースしてみると、うまくいっているようです。
lxmlは、文字コードはHTML内に記述された、charsetを見てくれているようです。
と、ここで問題発生です。
出力が短すぎ。どうもHTMLを最後まで読み込んでくれていないらしいことが分かりました。
何もエラーなど出ていなかったはずなのですが。
lxmlの公式サイトを見ても、lxml.htmlの部分については、エラーハンドリングの記述がありません。
エラーがあるなら例外を吐いて止まってくれればいいのに、何も言わずに結果を切り詰めるなんて...
ちなみに、同じHTMLをbeautifulsoupでパースすると、文字化けします。が、これは文字コードを適切に指定すればうまくいきました。どうもbeautifulsoupは、HTML内のcharsetを見てくれていないようです。
文字コードの部分だけ解決すれば、beautifulsoupで最後までパースできているようなのですが、こちらはかなり遅いということが分かりました。
さて、困ったのは
といった2点で、これらについてはとりあえず、手動。すなわち、旭山動物園のサイトを処理する際には、beautifulsoupを使用して、あらかじめShift_JISという文字コードを与えてやるという対応にしたのでした。
それで先に進めるわけですから。
ここから先は同様で、まずlxml.htmlでパースをしてみて、うまくいかないようなら、beautifulsoupで試す、の繰り返しで、それぞれの動物園ごとの設定ファイルを書いていったのでした。
200サイトもあるので、この作業だけで3日くらいかかったのですけれど。
チェック対象のページ数からして、wgetとdiffでやっていくのが効率的だろうという考えには達しました。
しかしもちろん、手でwgetやdiffを動かすわけにはいきません。
wgetだけなら、あるいはdiffの実行までなら手動操縦もありえます、が、diffの結果のチェックまで目視でやるには無理があります。
少なくともdiffの結果は一つのテキストファイルにまとまっていてほしいものです。
それともう一つ、diffにかける前に、チェック対象外の部分を削除する方法も検討する必要があります。
このあたりの実験的なコード作成には、深く考えることなくPythonを選びました。
自分にとって一番手っ取り早いという理由です。
そして、チェック対象のページが決まっていて、Pythonを使うとなると、wgetすら必要はありません。
Pythonのurllib2を使うと、HTMLのダウンロードができてしまうからです。
しかし実は、そこまでやる必要すらないだろうと思っていました。
urlwatchというPythonスクリプトを見つけてあったからです。
HTMLの取得からdiffの適用まですべて自動で作業してくれる優れものです。
手でフィルターを書けば、diffにかける前にHTMLデータの不要な部分を削除しておくこともできます。
これで、動物園・水族館WEBサイトのウォッチが現実のものになる、と思ったものでした。
実際のところ、これでもがんばればどうにかなるレベルではありました。このブログ内で動物園・水族館のWEBサイトの更新状況を報告していた時は、このurlwatchを使用していたのでした。
しかし、urlwatchにはurlwatchなりの問題がありました。
urlwatchはすばらしいソリューションを私に提供してくれました。
けれども、十分といえる域には達していなかったのです。
まずurlwatchの挙動について、簡単に説明しておきます。
lynxを通した結果に対してdiffを適用することで、無関係なjavascriptの変更やcssの変更を気にする必要がなくなり、WEBサイト上の意味のある文言だけを比較できるわけです。
相手がセマンティックなWEBサイトならこれで十分ではありませんか。
しかし、動物園・水族館はそのような相手ではありませんでした。
まず、urlwatchは必ずしも日本語を正しく扱うことができません。UTF-8しかまともに扱えません。
Shift_JISやEUC-JPエンコーディングのサイトは文字化けしてしまいます。
文字化けしながらも新旧比較はできるので、サイトが更新されたということと、大体の更新箇所はわかるので、ブラウザでそのサイトを開いて実際の変更箇所を目視確認するという作業が必要になります。
動物園・水族館が日本語文字コードの問題について深く考えているはずもなく、普通にShift_JISやEUC-JPエンコーディングのサイトがあります。
そしてもう一つの大きな問題。
それは、urlwatchのセールスポイントの一つであるフィルタの使い方が難しいことです。状況によっては使い物になりません。
フィルタはlynxを通した後のテキストデータに対して適用されます。
フィルタが使えるには、この時点で文字化けしていないという前提が必要になります。これで半数近くのサイトではフィルタが機能しないことになりました。
さらに文字化けしていなかったとして、どのようなテキストデータが出力されているのか、ハッキングなしに確認する方法がないため、フィルタの書きようがありません。
対象のサイトをlynxで開いて実際に見てみるくらいしか手がありません。
そしてさらにやっかいなことに、そのフィルタが正しく動作しているかテストする方法が見当たりません。
urlwatchを動作させてしまうと、たとえフィルタが間違って書かれていたとしても、その間違ったフィルタを通した結果がキャッシュに書きこまれてしまいます。原本はどこにも残りません。
フィルタの間違いに気づいて修正したとしても、再実行することができないのです。
せめて原本がどこかに残っていてほしいものなのですが、urlwatchの仕様上、フィルタを通した後のファイルしか残されません。
また、動物園・水族館のサイトはセマンティックなものであるとは限りません。正規表現でのフィルタ作成すら困難です。親切に表示された今日のお天気をどうやって正規表現で切り抜けというのでしょうか。
というわけで、urlwatchをベースに、自分なりのツールを開発する必要性に迫られたのでした。
ちなみに、urlwatchで200のサイトを監視していたところ、次のような時間がかかっていました。
大体動物園・水族館が一日の業務を終えるのは午後6時くらいだろうと目途をつけていました。もちろん実際には、動物園・水族館の主業務はWEBサイトの更新ではありませんから、とっても遅い時間に残業してブログとか書いていらっしゃる職員さんがたくさんいることも今ではわかっています。が、こちらもこちらの作業時間の都合上、午後6時くらいというのが一つのタイムリミットでした。
で、午後6時を過ぎたあたりでurlwatchを走らせます。200のうち大体50から80のサイトで更新がかかっていることが分かります。
明らかに無関係な「あなたは○人目のお客様です」のような更新内容を除き、それらのサイトを一つ一つブラウザで開いて目視確認し、変更箇所を手でテキストエディタに入力していきます。
北海道から鹿児島まで、全データをチェックすると作業完了が早くて午後8時、遅い日は午後10時手前までかかりました。
ということは1回のチェックの作業に2時間から4時間をかけていたことになります。
これで給料がもらえるならまだしも。あるいは給料がもらえたとしても連日午後6時から10時まで拘束、かつ集中して作業というのはちょっときつすぎます。
urlwatchで監視を続けるのは非現実的と言わざるをえませんでした。
動物園の基本DBが出来上がって、次は情報のメンテナンスのためWEBサイトの更新チェックの方法を検討することになりました。
このころには、動物園のWEBサイトの更新情報をブログのコンテンツにしてしまおうという下心が芽生え始めていました。
さて、動物園・水族館の数は200以上。この時点では更新頻度不明です。
中にはRSSを出力している園もありますが、一部の園だけで出力してても...といった感じです。
GoogleでWEBサイトの更新チェック方法を調べたところ、大きく分類して
が見つかりました。
また、腹案として、wgetでWEBサイトの情報をダウンロードしてきてdiffをかけてしまえばいいのではないか、という考えもありました。何せ200サイトです。導入がひと手間だけれども、wgetが一番現実的ではないかとその時は思っていました。
まず試したのはFirefoxのアドオンで、AlertBoxというものです。
https://addons.mozilla.org/ja/firefox/addon/alertbox/
これにめぼしい動物園のWEBサイトを登録して、1日、2日と様子を見てみました。
少なくとも、動物園のWEBサイトの監視という目的がなければ、AlertBoxは優れたソフトウェアであることに違いありません。
WEBサイトのページの一部分の変化だけを追跡することもできます。この機能は重要で、たとえば親切な動物園の場合、本日のお天気情報がサイトに掲載されていたりしますので、こういった情報は取り除いてサイトをウォッチしないと、私にとっては意味なく毎日更新されているように見えてしまいます。
機能的には、これでだめならほかの専用ソフトや、更新チェックのWEBサービスはさらにだめだろうと感じさせるに十分なものでした。
で、十幾つかのサイトを監視したところで、どうも目的に合致していないらしいことが見えてきました。
WEBサイトが更新されていることはわかるのですが、どこが更新されたのかがわからない。AlertBoxには変化した部分を指摘する機能があるにも関わらずです。
なぜかというと、動物園・水族館側が、そういった用途を考慮していないからです。
延々と10ページ分くらいスクロールしないと全体を見られないようなページが普通にあったりします。その一部、たとえばイベント予定の日付だけが変わっていたとして、その部分が変更箇所として緑背景で強調されていたとしても、ちょっとやそっとでは見つけられないのです。結局そのページ全体を読むことになってしまいます。
新旧のページをならべて比較する機能も、こんな巨大なページを相手にしては無意味に近いです。
さらに致命的だったのが作業効率です。
意外と動物園・水族館のサイトは更新されていることが分かりました。
せいぜい週一回、イベント情報やニュースが更新されるくらいじゃないかなと予想していたのですが、熱心な園・館は毎日更新がかかります。
また一つの園・館につき、1ページだけをウォッチすれば済むという話ではありません。
結果を先に書いてしまうと、動物園・水族館200サイトをウォッチするには、1,000ページ以上を監視する必要があり、一日に更新されるサイト数は50、ページ数は100を超えていました。
1,000ページをAlertBoxに登録する手間がまず非現実的ですし、更新チェックのためのデータDLやレンダリングにかかる時間も論外です。さらにそこから更新点を目視確認する手間については上述のとおりです。
というわけで、AlertBoxで使い方を工夫すればどうにかなるというようなレベルの課題に取り組んでいるわけではないということがわかりました。
もちろん、専用ソフトや更新チェックWEBサイトも論外と思われました。
ならば、もう一つの腹案、すなわちwgetとdiffではどうなのでしょうか。
仕組みが動き始めてしまえば、作業効率の点ではAlertBox他よりは圧倒的によさそうです。
というわけで、まず安直に考えたのは、wgetをウェブスパイダーとして使い、動物園のサイトを毎日まるごとダウンロードし、diffをかけるというやり方でした。
wgetはこういった用途向けの便利な機能を持っています。
wgetが超絶便利なwebクローラー、クローリングツールだとは知らなかった・・・!
あたりが参考になるでしょうか。
で、まず最初の動物園のサイトに対して、wgetを実行してみました。
そうしたら時間のかかることかかること。
10年以上も前からWEBサイトを運営している動物園はざらです。そうなると一つのサイトのページ数が何百にもなっていたりするのです。
これをひたすらクローリングするわけですから、1分や2分では終わりません。200サイト全部やったら一日以上かかってしまうかもしれません。しかも、これは相手にとっても迷惑ですよね。
これを毎日とか毎週とか、定期的に実行しないといけないわけです。ネットワーク帯域の無駄遣いで、あまり格好のいいソリューションとはいえません。
スタートに手間はかかりますが、手動でチェック対象のページを絞り込んだほうがいいという結論にすぐに達しました。
それともう一つやっかいなのは、最近はCMSを利用している動物園・水族館が多数あるということです。
余談ですが、びっくりするほど有名な園でもサイトはホームページビルダーで作られていたりします。
で、話を戻すと、CMSを使っていると、例えばメニューを一か所変更すると、全ページに変更が反映されます。
diffにかけると、同じような結果が全ページ分出力されてしまうわけです。
AlertBox並とは言わないまでも、チェックする部分を限定する工夫が必要になります。
そのあたりも、何かのライブラリで解決できるに違いないということで、wget&diffを軸にツールを考えていくことにしました。
会社ならともかく、個人ではMS Officeとかは持っていないので、基本的な道具として、深く考えずにLibreOfficeを選択しました。
Calcを起動して、動物園・水族館の施設名とWEBサイトのURLを入力していく、それだけの簡単な作業です。
ところがこれに、所在地だとか、入園料だとか、開園時間だとかの情報を入力していると、さすがに表計算ソフトというだけあって、面倒くさくなってきました。
そこで、そもそもDBソフトであるところのBaseでの管理に移行しました。
フォームを作れば入力作業の効率はぐんと上がります。
けれどもここで問題が発生しました。
Baseで入力したデータの取り出し方が分からないのです。
Baseを起動して見ればいいじゃないかと普通なら考えるのですが、私の場合、出来上がったDBを仲間と共有したいです。
誰もがLibreOfficeを持っているわけではないので、せめてExcel形式で出力しておきたい。
ということで、テーブルのデータをコピーして、Calcにペースト。
そうしたら、見事に日本語の部分が文字化けしてしまいました。
まあ、フリーソフトならこの手のトラブルはよくあることです。
こういう場合はデータを一旦テキストデータに出力してしまえば...いいはずなのですが、Baseは直接テキストデータを出力することができません。
公式リファレンスを見ても、テーブルの内容をCalcにペーストして、Calcからテキスト形式で出力せよとなっています。
ちなみに、Baseはテキストデータのインポートも直接はできません。Calc経由です。
Calcへのデータ受け渡し方法はコピー&ペーストのみ。
というわけで、簡単にはトラブル回避ができません。
そこでGoogleで調べたところ、https://forum.openoffice.org/ja/forum/viewtopic.php?f=16&t=209 という情報を入手することができました。
ここの情報に従い、BaseのテーブルをCalcにドラッグ&ドロップすることで無事、データを取り出すことができました。
けれども、もう、なるべくBaseは使いたくないと思わせるに十分な出来事でした。
入力作業をBaseのフォームでまとめて済ませてしまい、それが終わったらCalcにデータを移し、あとのメンテナンスはCalc上でやってしまおうと思いました。
細かい部分の使い勝手については、やはりExcelは素晴らしいソフトだなとあらためて感じさせられもしました。
後でひっかかった件なのですが、まとめて先にここに記録しておきます。
ウェブスクレイパーに投入する元データをCalcで管理しはじめたころ、やけに動作が重たいことに気づきました。
たかだか数百件なのに、レコード一つ挿入するだけで何秒も待たされます。
とてもやってられないというので、急遽Gnumericをダウンロードし、こちらにデータを移し替えて作業を継続するところまで行きました。
ちなみにGnumericもいいソフトなのですが、Excel基準で考えると、操作方法がCalcよりもさらに一癖あります。
それにWEB上の資料がCalcよりも少なくて、不安をかかえながらの作業になりました。
ところが、偶然、Googleで検索していて、Calcの動作が重たくなった原因が分かりました。
とても残念なことに、今、いくら検索しても、そのソースを見つけることができません。どなたかのブログだったかと思うのですが。
とりあえず、記録として、ここに原因を記載しておきます。
LibreOffice の特定のバージョンに限った話なのですが、Calcでセルに長い文字列が入っていると、動作が極端に遅くなる現象が生じるそうです。
私が使っているLibreOfficeのバージョンは4.2でした。3.xならこの現象は生じないとのこと。
また、OpenOfficeでも生じないとのことでした。
というわけで、2014年6月6日現在、私はOpenOffice Calcで動物園DBの作業を進めています。
未完成な部分も多いけれど、ウェブスクレイパーについて現時点までで蓄積されたノウハウを記録しておきます。
そもそもの動機は「来園者目線での動物園DB」を作りたいと考えたことです。
自分が動物園に遊びに行くにあたっては、サプライズに期待した行き当たりばったりではなく、事前に情報を集めておいて、見たいものを重点的に見てきたいほうです。
身の回りには同じような考えの仲間もいます。
なので、ホームページのアドレス、入園料、休園日、行き方などをまとめたDBを作って仲間内で共有しておけば便利だろうと考えました。
実はWikipediaの動物園の一覧を見れば、かなりの情報が入っているのですが、私の目的には記事が多すぎて一覧性に欠けています。
むしろ、例えばMAPPLEの動物園・水族館特集のほうが、使いやすいのですが、こちらはこちらで取り上げている動物園・水族館が少なすぎます。
Wikipediaの件数で、MAPPLEの一覧性+αを持つDBがほしいのでした。
これらの情報は各園のWEBサイトを見れば入手できます。
さらにウェブスクレイパーを仕込んでおけば、何か情報が変わった場合にキャッチできるので、DBを最新の情報に保つことができるだろうと、今から思えばとんでもなく楽観的なところから、事は始まったのでした。
この時点では、自分でウェブスクレイパーを開発することになるだろうとは思ってもいませんでした。
Wikipediaを眺めた時点で、ああ、このくらいの数があるのかということは目視でだいたいわかっているつもりでした。
記事を真剣に数えてみると、動物園、水族館、それぞれ百数十施設があります。
その前に、動物園、水族館とは何か? といった問題があります。
日本動物園水族館協会に加盟している施設かどうか、というのは一つの基準になりえます。これだと、動物園、水族館をあわせて百数十施設になります。
ですが、この基準でいくと、カピバラを飼育している大阪のひらかたパークがDBから外れてしまいます。もちろんひらかたパークで飼育しているのはカピバラだけではありません。あくまで一例です。
ひらかたパークが入っていないDBは私としては価値半減です。ひらかたパークの入らない基準はちょっと考えられません。
突き詰めれば私的に作るDBですし、動物園とは、とか、水族館とは、とかいった堅苦しい話は抜きにして、Wikipediaの記載を元に、「自分の興味」という視点から動物園・水族館っぽい施設をピックアップしていくことにしました。
せめて、日本動物園水族館協会に加盟している施設は全部カバーしたいとは思ったのですが、例えば小田原動物園のように、WEBサイトが見つからない施設については割愛せざるを得ませんでした。
私の行動パターンとして、WEBサイトがなければその施設に物理的にたどり着けませんから。
という基準でとりまとめ対象の動物園・水族館を改めて数えたところ、ざっくりと240ほどという数字が出てきました。
DBと呼ぶにはとても小規模ですが、内容としては十分に重たく、手ごろなところかなという印象でした。
こういったご時世ですから、動物園・水族館という施設ならまずWEBサイトを持っています。
それぞれの施設のWEBサイトをどうやって探すか、というところで、深い考えがあったわけではないのですが、上で数え上げた動物園・水族館の施設名をGoogleで検索し、出てきたWEBサイトを目視確認し、トップページを探すという方法にしました。
北から順に行くと、まずは札幌市円山動物園を調べることになるのですが、例えばこの施設の場合、札幌市の施設です。
独立したドメイン名を持っているわけではなく、札幌市のWEBサイトの中に円山動物園のサイトが含まれてしまっています。
URLはhttp://www.city.sapporo.jp/zoo/になります。
人間の目には、このサイトのコンテンツに見える「リンク・著作権・免責事項」も、URLを調べると「http://www.city.sapporo.jp/city/copyright/link.html」となっており、データとしては円山動物園のサイトに含まれているわけではないことになります。
後から問題になってくるのですが、たとえばウェブスパイダーとかをうかつに走らせると、こういった札幌市のWEBサイト関連のリンクを調べ上げ始め、とんでもない数のファイルがダウンロードされることになってしまったりします。また逆に、URLの階層外にあるという理由で必要なコンテンツがダウンロードされなかったりとかすることもありえます。
なので、それぞれの施設のWEBサイトの構造については、ある程度事前に自分の目で見ておく必要がありました。
こういった形で、とりあえず、施設名とWEBサイトのURLをまとめたDBの素は、一日がかりでどうにか準備ができました。