はじめまして
皆さん、こんにちは。Qiita初投稿、松井 敏と申します(以前は@moririringという名前で活動してました)。現在僕は、読んだマンガを登録するサイト「マンガ読んだ!!」を作っています。一応公開していますが、まだまだα版です。宣伝活動も殆どしていないですし、実際まだ結構大幅に変わる可能性も高いので、バグもありありで、折角の入力データも保持をお約束出来ない状態です。
スクレイピング Advent Calendarに投稿した背景
似たようなサイトで自分で読んだ本を1冊ずつ手動で登録するサイトはありました。けれど、正直それは手間過ぎて、自分が読んだ本全部を登録する気は起きませんでした。そこで、僕はなるべく多くのマンガが登録してあり、ボタンを押すだけですむ仕組みにこだわりました。つまり、最初から登録されているマンガの数が重要でした。では、どうやって登録するか?答えはスクレイピングです!
スクレイピングするサイト
マンガをスクレイピングするサイトとして最初に考えるのはAmazonや楽天ではないでしょうか?実際僕も最初それは考えました。でも、エンジニアとしてはよく言われるのは、やはり一次情報、「原典」を探せではないでしょうか?原典と言えば、出版社サイトです。そこで、最初はとりあえずマンガ大手の集英社、講談社、小学館、秋田書店からスクレイピングすることにしました。とりあえず!
スクレイピングの著作権とか
出版社からどこまで自分のサイトにデータを持ってきて良いのだろうという疑問がありました。これに関しては、最初暫くはスルーしていましたが、やはり公開したときのことを考え、集英社と講談社に直接電話しました。結果、個人運営のサイトであれば、サイトの内容と表紙の画像に限っては、使用しても問題ないと回答を頂きました。というわけでその二社は一応公認です。(他は質問前。。)
※どのケースでも同じかは分かりません。自分の状況をなるべく伝えた結果そのように言ってもらったという話なので、同じような条件下で必ずOKがもらえるという保証はないと思います。
スクレイピングの技術ベース
それでは、技術面を。僕はC#をこよなく愛しているので、開発言語はもちろんC#。開発環境はVS。スクレイピングはSeleniumを使いました。これでスクレイピング用のDllを作って、MSTestで動かしました。MSTest??。はい。こだわりではなく、最も手軽だっただけです。これでサイトから、文字情報はcsvに、表紙はjpgにしてローカルに落としてきて、DBやアプリに組み込みました。
スクレイピングの問題点
上の方法は動くというだけで、色々ありますが、一番の問題はローカルでしか実行出来ないことです。実行している間はパソコン占拠、雑誌社によっては1日以上かかることもあります。これを本当にどうにかしたい。ローカルで動かすのが嫌だということは、手段としてはクラウド上で作業をさせることになります。最初はAzureのWindows Virtual Machinesで同じように動かすことを考えました。
スクレイピングフローの見直し
そうなると、データもローカルに落として書くより直接サーバーに上げたくなりました。フローを見直して、スクレイピングしたタイミングでデータはSQL Database、画像はBLOB ストレージへ、ついでにスクレイピングに終了時にSlackへ結果を投げるようにしました。これでローカルから切り離す準備が整いました。
スクレイピングライブラリAngleSharp
ここいらで、実はもうサイト自体は公開しました。その際、親しい人らにレビューを頼みました。するとある友人は非常に協力的にアドバイスをくれて、スクレイピングも手伝ってくれてプルリクをもらいました。その際に、スクレイピングするのにSeleniumはテストツールなので、スクレイピング用のライブラリを使えという何とも的確なアドバイスとともにAngleSharpを教えてもらいました。
多謝みうみう。
スクレイピングキッカーAzure WebJobs
色々準備が整ったので、Virtual Machines上で動くツールを作ったり、Jenkins入れることも考えました。そんな時たまたま見つけたAzure WebJobsが用途に合っていそうなので使ってみました。この時もSeleniumを止めて、GUI不要になっていたことは重要でした。少なくともスクレイピングに関してはGUIツールは使わない方が、可能性が広がると思います。
スクレイピングが何処からでも使える、見える
実際動かしてみると、ローカル環境と雲泥の差です。出版社毎にJobを分けて作りましたが、同時に叩いても問題なく動きます(Job分けてもパソコンは同じようなので限界はありそうですが)。長時間かかるものは、夜寝る前などにキックするだけです。スマホからでもキックできます。そしてスクレイピング結果もSlackに流れるのでスマホから確認できます。本当に、超便利になりました。
スクレイピングの速度
安定してくるとやはり欲が出ます。今度はスクレイピングの速度が気になってきました。そこで、高速化を検討しました。C#で並列化は簡単だったんですが、同時にSQLにも書き込んでいて、SQLがスレッドセーフでないところではまりました。非同期操作を用いて、一度に複数のクエリを処理するを参考にしてみたけれどどーにもうまくいきませんでした。
スクレイピングの高速化
その後もうまくいかずなくて悩んでいたら、並列実行とSqlConnectionという記事を読んででサクッと並列化出来ました。実際難しいことなくusingしただけというね。さらに並列で、asyncに出来なくて悩んでいたらまた同じブログForEachAsync - 非同期の列挙の方法 Part2で解決でした。まさかWaitしちゃえば良いのかーって感じでした。ま、これスクレイピングというよりSQLの高速化ですね。
スクレイピングタスクとスクレイピング環境の調整
さて、並列化によって3倍以上高速化出来たのですが、Webjobsで複数タスク同時実行すると落ちました。今の所は全部SqlConnection.OnErrorですね。正直理想解はまだわかってませんがスレッド数を的確に調整する必要がありそうです。とりあえず現状は1個ずつしか動かしていません。スケール出来るならFuctionsにした方が良いかなー。この辺はまた今後に見直しです。
スクレイピングのキックパターン
あとキックを、「新規」、「全部」、「差分」チェックして全部、「指定」番号のみなど色々作って、用途に分けてキックできるようにしました。実際大量のスクレイピングならそれぞれ必要だと思います。まだ、「全部」が多いフェーズですが、今後落ち着いたら完全自動で「新規」を目指しています。というか、最初から、ここが目標でクリアしたらβ版にするつもりなのですが。
集英社のサイトリニューアル
ここからは各出版社ならではの問題を。まず一番ダメージ大きかったのがサイトリニューアルです。集英社は今年の9月ぐらいにサイトが一新しました。これはなかなか辛かった。特にきつかったのはサイト内のマンガを全検索する方法が無くなったことです。以前は細かく検索できるようになっていたのですが、現在はなくなりました。あと半角全角空白扱いも変わったりとか。
集英社のスクレイピング全情報取得
どうやって解決したか?これは出版社全般に言えることですが、殆どの出版社は漫画サイトと出版している本全部のサイトがあります。少なくとも4社ともあります。そして集英社も出版している本全部サイトの方なら全検索出来ました。もっともこれに気づくのには結構かかりましたし、結構作り直した部分は多かったです。でも、変わるものという前提で設計を見直したのは大きいかもしれません。
集英社の超例外マンガ
あと7月頃に僕からしたらとんでもないマンガを出ました。それが週刊少年ジャンプです。これ本来雑誌なんですが、一応URLのカテゴリーがマンガです。このマンガは集英社に1万冊近くあるマンガの中で他にはない特徴があります。それは作者がないんです。あらゆるマンガに作者は居るもんだと思って作っていたので、これは本当に予想外でしたね。案の定スクレイピング中落ちました。
秋田書店のバギどもえ
秋田書店にバギどもえというマンガがありました。このマンガ、多分誰も気づかないミスがあって、秋田書店の全マンガの中で唯一、タイトルに\tが入っていました。当時csvでタブ区切り出力していた時これが致命傷でした。まあ、プログラム側でTrimさえしていれば問題なかったのですが、なくてもそれまでは動いていたので、入れてなかったんですよね。
秋田書店のグラップラー刃牙
あと、グラップラー刃牙完全版というマンガがありました。秋田書店のサイトのISBNチェックをしていた時にこの本だけあわない。なんでかなーと思ったらこの本サイト側の表記がそもそも間違っていました。ちょっと面白いのはAmazonはちゃんと間違ったまま表記されていました。後日直接秋田書店に問い合わせたら、正しいISBNに修正されました。そして後日Amazonみたらちゃんと直ってました。
秋田書店の柚木N’
SQLのエスケープシーケンスに'がありました。文章とか本のタイトルとかはちゃんと対応していたのですが、'が作者に来ることはないと思って作者には対応してなかったんですよね。実際他の出版社でもちゃんと動いていたし。そしたら秋田書店だけオカシイ。調べたらこの人でした。名前にダッシュはないと思ったら、この人の名前は柚木N’でした。
秋田書店の新刊が月末に0冊に
あと、秋田書店だけ新刊は、発売日が来たら、ちゃんとページからなくなります。素晴らしい対応ですね。他の出版社は発売日後も残っている。でも、なくなるため、月末になると新刊が0冊になります。こちらは月頭にスクレイピング作ったので、月末になったら急に落ちて、??と思った記憶があります。まあ0冊対応すれば良いだけなんですが、気づきにくい問題でした。
講談社の圧縮対応
講談社は画像データはAWSに置いていたりして技術的には進んでいると思いました。そのためこのサイトだけ一つ非常にスクレイピングに苦労したことがあります。定期的にページ情報が壊れることがある。この理由が本当に分かりませんでした。理由は、定期的に圧縮したデータを送ってくるが答えで、その際は解凍する必要がありました。これは全スクレイピングの中で一番悩んだことでした。
講談社の同タイトルマンガ
ページが登録済みかを確認するのは基本ISBNでやるんですが、1度それ以外の方法を模索しているとき、講談社だけ、絶対にISBN以外では区別不可能なページがありました。ムヨン-影無し-とムヨン-影無し-。これ、ISBN以外情報に差がないのです。テキストでは巻数情報もないし、発売日情報もない。つまり同じ情報。せめてタイトルに巻数入れてくれよーと思いました。
小学館のバグ対応(※現在は修正済み)
実は小学館はまだスクレイピングをしている途中です。ただ、全ページスクレイピングをするにあたって致命的なバグがありました。ページがある程度以上行くと情報が正しく出ない。これに関しては、小学館に問い合わせたら直してもらえました。ありがとうございます!スクレイピングして気づいたバグはなるべくそのサイトに伝える方が良いんだなーと思いました。
まとめ
というわけで、マンガ読んだ!!で必要な各出版社のスクレイピングについて技術面やサイト側の話などを書かせてもらいました。長々とお付き合いありがとうございます!サイト自体はもう少ししたら、使っていけるレベルに達すると思います。β版でも使いたいという奇特な方は是非フィードバックお願いします!