こんにちは!最近気になるニュースはスピノサウルスの尻尾の化石が発見されたこと1な、SRE部エンジニアの塩崎です。ZOZOテクノロジーズの前身となった会社の1つであるVASILYでは数多くのクローラーの開発・運用の担当をしてきました。 今回はその知見を生かして、クローラーを楽に運用するためのクラウドサービスを紹介します。
概要
データ解析を円滑に進めるためには、CSVやWeb APIなどの構造化されたデータが必要です。しかし全てのWebサイトにあるデータが構造化データを提供しているとは限りません。むしろ提供していないケースの方がはるかに多いです。そのため、Webクローラーを作成して構造化されていないWebページを解析し、構造化データを生成する必要があります。
しかし、Webクローラーの運用には数多くの「つらみ」があります。特に大量のWebページを1日1回などの頻度で定期的にクロールする際には「つらみ」が多くなります。少しでもこの「つらみ」を減らし、運用を楽にするためのクラウドサービスを紹介します。
クローラーの運用の「つらみ」とは
クローラー運用でどのような「つらみ」があるのかを説明します。なお、ここで想定しているクローラーはクロール対象のサイト数が数十以上、ページ数が数百万以上、クロール頻度が毎日というかなり大規模なものです。
インフラの運用
EC2やGCEなどを使いクローラーを動作させるためのインフラを自分たちで管理するのは大変手間がかかります。大規模クローラーを運用する場合は1台のサーバーだけで処理が完結することはありません。多くの場合では非同期ジョブキューを活用した分散システムが必要になります。以前、このような仕組みを作った際には、Mesos + Marathonを使ったインフラを数人月の開発工数で構築しました。頑張って仕組みを作ってみたものの、運用をするために分散システムの知見が必要になり、運用者に求められるレベルが上がるという問題も同時にありました。
サイトの構造が変わることへの対応
クローラーで最も運用負荷がかかるのは、サイト構造の変化への対応です。今日ではWebサイトのリリースは毎週・毎日行うことが当たり前のようになっています。そのため、あるタイミングで作成した要素をパースするための設定がある日突然使えなくなってしまう可能性があります。
Ajaxを使っているサイトの対応
サーバーからダウンロードしたHTML中に欲しい要素がない場合は、要素をパースするのが非常に面倒になります。Vue.jsやReactなどのSPAフレームワークで作られたページについては言うまでもないですが、意外と一部の項目のみがAjaxで取得されているケースも多いです。例えばECサイトの在庫状況のような頻繁に変更されうる情報をユーザーに提供するため、その部分のみをAjaxで取得することがあります。そのようなサイトをクロールするためにはChrome DevToolsなどを使いAjax通信を解析して、同等なAPI呼び出しを行う必要があります。
BANとの戦い
一部のWebサイトはWebクローラーからのアクセスを自動的に遮断するための対策を実装しています。多くの場合はIPアドレスを使い、一定の期間で閾値以上の回数のアクセスがあったらそれを遮断するという処理が行われています。もちろんサイトの運営に支障が出るレベルのアクセスをしたり、利用規約で禁止されているようなクロール行為をするのは論外です。ですが、常識的な2アクセス頻度であったとしてもブロックされるケースがあります。そのようなサイトをクロールするためにはIPアドレスを複数個用意し、適切にローテーションを行う必要があります。
選定のポイント
上記で出た「つらみ」を元にクローラー運用を楽にするためのポイントを考えていきます。
インフラの抽象化
大規模クローラーは分散システムになりがちですが、分散システムの運用はモノリシックなシステムの運用に比べて難易度が上がります。そのようなシステムの運用に慣れた人員を集めることはとても困難です。そのため、この部分を「いい感じに」隠蔽し、アプリケーションエンジニアがアプリケーションレイヤーのみに集中できるようなPaaS、SaaSが必要です。
パース結果をGUIで確認する機能
XPathやCSSセレクターなどを使ったパース結果をブラウザなどの画面でグラフィカルに確認したいです。クロール対象サイトのHTML構造が変わった後には速やかにそれに追従する必要があります。そのため、ブラウザ画面をクリックしてパースする要素を指定できる必要があります。わざわざHTMLコードを調べるのに比べ、グラフィカルに指定できる方が効率的です。
JavaScriptの実行をしてくれるヘッドレスブラウザ
Ajax通信の解析は骨の折れる作業です。個人的な感覚では、HTML中に直に埋め込まれている要素を取得するのと比較して、数十倍の手間がかかります。ですので、JavaScriptの実行を行ってくれるヘッドレスブラウザがあり、onloadなどのイベントに紐づく処理がある程度実行されたあとのHTMLを取得したいです。
IPアドレスのローテーション機能
BAN対策のために複数個のIPアドレスを使い回し、必要に応じてそれらを使い回しできるような機能が欲しいです。ProxyMeshやTorのようにこの機能を単体で提供するSaaSやOSSもありますが、クローラー本体を動かすためのクラウドサービスに統合されていると使い勝手が良いです。
ベンダーロックインしてない
古くからあるクローラー用のクラウドサービスとしてkimonoは有名でしたが、2016年にPlantirによって買収されたタイミングでサービスの提供が打ち切られました。このような事象が発生した場合、長期的な戦略としては別のクラウドサービスへのマイグレーションが必要です。ですが短期的な視点に立つと、完全なマイグレーションが完了するまでの間のつなぎとして、自分たちのインフラでクローラーを動かす必要が出てくるかもしれません。
また、スモールスタートで始めたプロジェクトが大きく成長し、十分な運用体制が取れるようになることもあります。そのときに、ベンダーロックインをしていなければ、自分たちのインフラに載せ替えることによってコストメリットを得るというオプションを考えることができます。
このことから、ベンダーロックインをしていない、OSS製品をベースにしたクラウドサービスを利用することにはメリットがあります。しかし、発生頻度などを考慮すると、他の項目と比べた優先度は低いです。
要件を満たしそうなクラウドサービスの検討
Scrapinghub
最初に紹介するのはScrapinghubです。Python製のWebクローラーとして有名なScrapyの開発元が運営しているPaaSです。自社が主導的に開発を行い、OSSとしても公開しているScrapyの実行基盤を提供しています。ScrapyそのものはPythonで書かれたOSSであり、自身のPCやEC2上に構築したLinuxサーバーの上で動かすこともできます。
Webページをパースするための処理はすべてPythonコードで実装します。XPathやCSSセレクターを使って要素を取得したあとに、Pythonコードで文字列処理を実装可能です。Pythonが持っているエコシステムをフル活用できる柔軟性が魅力的です。また、requirements.txt形式でPaaS環境にライブラリをインストール可能であり、それに加えて独自のDockerイメージの利用も可能です。そのため、MeCabを使った形態素解析などのネイティブライブラリが必要な処理も実装できます。
一方、パース結果をGUIで確認する機能は搭載されていません。同じ開発元がビジュアルスクレイピングツールであるPortiaというOSSを作っていましたが、他のクラウドサービスに比べるとGUIツールとしての機能が不足しているように感じます。ブラウザベースで抽出したい要素を選択すると、Scrapyを使ったクローラーのソースコードをアウトプットする機能があります。しかし、出力できるクローラーの自由度が高くないため、あくまで補助的なツールとしての利用に限定され、メイン処理はPythonコードで書く必要があります。また、ここ1年くらいコミットが一切ないので、メンテナンスされていない疑惑があります。そのため、パース結果をGUIで確認する機能はScrapyのエコシステムの外のツールに頼る必要があります。以前に以下のブログで紹介した、XPath HelperというGoogle Chromeの拡張機能を使うことで、目的の要素を抽出するためのXPathを高速に見つけることができます。
また、JavaScriptの実行をするためのヘッドレスブラウザの機能も搭載されています。ただ単にページロード時のレンダリングをするだけでなく、Lua言語で書かれた関数を渡すことによって、フォームのクリックイベントなどを処理できます。クローラー用に軽量のヘッドレスブラウザを独自開発しているという気合の入れ方が凄いです。このモジュールもSplashというOSSとして公開されており、自前のインフラでホスティングすることも可能です。
IPアドレスのローテーション機能もついています。Scrapyとの統合も簡単で、ソースコードに数行の設定を追加するだけでIPアドレスのローテーションを行えます。接続元IPのロケーションを選ぶことができるので、海外IPからの大量アクセスによるアクセス遮断を防げます。
このように、基本的な機能は全てOSSとして公開されているので、これらの機能をEC2などのIaaS上で動作させることも可能です。自前のサーバーでホスティングするためにはScrapydというツールを使いデーモン化します。しかし、ScrapydのWebコンソールは機能が不足しており、また複数台のサーバーをまとめ上げる機能もありません。そのため、Scrapydだけではクローラークラスターの運用には不十分です。クラスターの運用をするためには、サードパーティツールである、ScrapydWebを組み合わせる必要があります。このツールは複数台のサーバーにインストールされているScrapydの状態を一元して監視したり、ジョブをスケジュール実行する機能があります。
ParseHub
次に紹介するのはParseHubです。先程紹介したScrapinghubとは違い、プログラミングレスでクローラーを作ることができるSaaSです。ParseHubのクライアントツールを立ち上げると、ブラウザのような画面が立ち上がり、その画面でグラフィカルに要素を選択できます。クリックで要素を選択できるだけでなく、XPathやCSSセレクターを使った要素の選択ができる柔軟性も併せ持っています。要素を選択した後は、正規表現やJavaScriptで変換処理を行うことができます。さらに、変数・条件分岐・ループ処理・サブルーチンなどの基本的なプログラミング言語としての機能も有しています。
ヘッドレスブラウザのサポートはScrapinghubよりも充実しています。フォームをクリックしてその結果を取得するという操作などもグラフィカルに行うことができます。Scrapinghubではこのような処理を実現するためにLuaの関数を書く必要があり、手間になりがちです。
IPローテーションの機能もあり、BAN対策をすることもできます。ただし、接続元のIPアドレスのロケーションを指定する機能はないので、そのようなことをしたい場合はCrawleraやProxyMeshなどの外部サービスを使う必要があります。
これらのツールはOSSとして公開されていないので、がっつりとベンダーロックインされる点には注意が必要です。
なお、ParseHubに似たビジュアルスクレイピングサービスとしてOctoparseやImport.ioがあります。ビジュアルスクレイピングツールを求めている場合はこれらの検討もしてみると良いかもしれません。
Apify
最後に紹介するのはApify です。これはJavaScriptを使ってクローラーを作成できるPaaSです。ヘッドレスブラウザとしてGoogle ChromeとPuppeteerを使っています。
Apify SDKというOSSが公開されており、クローラーをローカル環境で動かすことも、Apifyが提供しているPaaSで動かすこともできます。
クローラーのマーケットプレイスの存在がApifyの面白い点です。ZOZOTOWNや楽天のような日本のWebサービスのクローラーはありませんが、GoogleやInstagramなどのグローバル展開しているサービスのクローラは数多くあります。クローラーのソースコードがGitHubで公開されているので、これらをforkして自分たちのニーズに合わせてカスタマイズすることもできます。
比較
ここで、今回紹介した3つのクラウドサービスが適しているケースをまとめます。
Scrapinghub
Scrapinghubはプログラマー向けのサービスです。以下のケースではScrapinghubを使うのがいいでしょう。
- PythonやJavaScriptなどの汎用プログラミング言語を日常的に使っている
- クローラーをコードベースで管理したい
- GitHubを用いたコードレビューやCI/CDパイプラインの仕組みを使いたい
- 機械学習や自然言語処理などのPythonが得意とする処理を組み込んだクローラーを作りたい
- 将来的に大規模化することが予想されており、自前のインフラで動かすための人員を確保できる予定がある
ParseHub
ParseHubはノンプログラマーでも扱えるような支援機能が豊富です。以下のケースでParseHubを使うとその良さが発揮されるでしょう。
- ノンプログラマーでクローラーの開発・運用をする必要がある
- ページ内で複数回のクリックをしないと取得できない要素が多い
- ベンダーロックインをいとわない代わりに開発スピードを上げたい
Apify
上記の2つと比較してApifyを積極的に選ぶ場面は多くありません。 あえて挙げるならば、以下のケースではApifyに優位性があります。
- Apifyのマーケットプレイスにあるクローラーが自分たちの要件を満たしている
- クロール対象のサイトがGoogle Chrome固有の機能に強く依存している
まとめ
我々のチームでは以上の検討をした結果、Scrapinghubを利用することにしました。クローラーの開発運用を行うメンバー全員がプログラマーであり、コードベースでの管理をする恩恵が大きいと判断したためです。GUIを使ったパース項目の確認機能が不十分ですが、XPath Helperを活用することによって不十分な点を埋め合わせることができます。
このようにZOZOテクノロジーズでは一度作ったシステムをそのままにせず、時代に合わせた最適なアーキテクチャを模索する営みを継続的に行っています。
ZOZOテクノロジーズでは、一緒にサービスを作り上げてくれる仲間を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください!
-
どの程度までなら常識的なのかは議論の対象になりがちですが、一例を挙げるなら岡崎市立中央図書館事件の判例で1秒間に1アクセス程度は常識的とみなされました。↩