こんにちは! バックエンドエンジニアのりほやんです!
2017年の2月28日にIQONはリブランディングを行い、タグラインを "わたしの「好き」がここにある” に刷新しました。
この “わたしの「好き」がここにある” という体験をユーザーにしていただくには、IQONに掲載されている商品情報がとても重要になります。 そして、正確な商品情報の掲載にはクローラーが正しく運用され稼働していることが必要不可欠です。
本記事では、IQONの商品情報を支えるクローラーの運用をどのように仕組み化しているかについてご紹介します。 クローラーを作成、運用されている方々のお役に立てたら幸いです。
弊社テックブログでは以前、『速くクロールすること』に注目した記事を公開しましたが、今回は『正しくクロールすること』に注目しました。 『速くクロールすること』に注目した『Docker / Apache Mesos / Marathon による3倍速いIQONクローラーの構築』を合わせて読んでいただくと、より深く弊社のクローラーを理解していただけると思います。
IQONのクローラー運用
IQONでは、毎日数百の提携ECサイト、数百万ページのクロールを行っています。 そして、提携しているすべてのクロール元サイトから辿ることができる全ての商品ページを取得し、なおかつタイトル・価格・ブランド・在庫などのすべての情報が記載されている内容のまま、IQONに掲載されていなければいけません。 そこで、下記の2つの条件を満たすことをクローラーが正常稼働している条件としています。
- 正しい商品情報がクロールされている
- すべての商品がクロールされている
VASILYではそれぞれの条件を満たすために、以下のことを行っています。
- 正しい商品情報がクロールされている
- 作成: リニューアルや修正に強いXPathを作成する
- 作成: 細かくパースチェックを行う
- 運用: パースエラーが発生していないかをチェック
- すべての商品がクロールされている
- 運用: 商品詳細総ページ数に変動がないかチェック
- 運用: 新商品の追加数に変動がないかチェック
では実際に、それぞれのチェックや重要なポイントをクローラ作成時と運用時に分けてご紹介します。
クローラー作成
リニューアルや修正に強いXPathを作成する
VASILYでは、クローラー作成時の要素パースにXPathを用いています。 XPathはXML文章中の要素、属性値などを指定するための言語です。 クローラー運用の負担を軽減させるため、クローラー作成時にリニューアルや修正にも強いXPathを作成することが大切です。 クローラー作成に便利なXPathの記法を2つご紹介します。
複数のclassが指定されている要素の取得
下記のようにclassが複数指定されている要素を取得したい場合のXPathを考えてみます。
// 商品タイトル <div class= "title class1 class2"> ロングカーディガン </div>
上記は『ロングカーディガン』という商品タイトルを表すHTMLです。 ロングカーディガンという文字を取得したい場合、どのようなXPathになるでしょうか。 classを指定して要素を取得する場合、下記のようなXPathがすぐに思いつくと思います。
//div[@class='title class1 class2'] => ロングカーディガン
しかし、リニューアルなどで紐付いているclassが以下のように変更された場合、先ほどのXPathでは要素が取得できなくなってしまいます。
// 商品タイトル <div class= "title class1 class3"> ロングカーディガン </div>
そこで、指定する文字列が含まれている要素を取得することができるcontainsを使います。 『ロングカーディガン』は商品タイトルなので、titleというclass名は変更されにくいと考えられます。 このように変更されにくいclass名を指定して、下記のように記述します。
//div[contains(@class,'title')] => ロングカーディガン
このXPathは、titleというclassが含まれるdiv要素を取得します。 このXPathであれば、先ほどのように紐づくclassがclass2からclass3に変更されたとしても、titleというclassが指定されている限りタイトルの取得が可能です。
テーブル内の要素を取得する場合
次にテーブル内の要素を取得するパース処理を考えてみます。
<table class="table"> <tbody> <tr> <th>カテゴリ</th> <td>カーディガン</td> </tr> <tr> <th>素材</th> <td>綿100% </td> </tr> <tr> <th>性別</th> <td>レディース</td> </tr> </tbody> </table>
このようなテーブルからレディースという要素を取得したい場合、tr要素の3番目のtd要素という情報から下記のように書くことができます。
//table/tbody/tr[3]/td
しかし、上記のようにtrの3番目というような指定をするとテーブルの要素が増減した際に、違う情報を取得してしまう可能性があります。
// 要素が増えてしまった時、trの3番目の要素は原産国になってしまう。 <table class="table"> <tbody> <tr> <th>カテゴリ</th> <td>カーディガン</td> </tr> <tr> <th>素材</th> <td>綿100% </td> </tr> <tr> <th>原産国</th> <td>日本</td> </tr> <tr> <th>性別</th> <td>レディース</td> </tr> </tbody> </table>
//table/tbody/tr[contains(th,'性別')]/td => 原産国
そこで、tdに紐づくth要素を指定することで、要素の増減に左右されず性別を取得することができます。
//table/tbody/tr[contains(th,'性別')]/td => レディース
細かくパースのチェックを行う
要素をパースする処理を書き終えたら、正しいパースを行えているかを確認するために、パースチェックを行います。 パースのチェックスクリプトを作成しておくと便利です。
この際、下記の2つのチェックを行うスクリプトを用意します。
- 1つのパースをチェックする
- すべてのパースをチェックする
すべてのパース処理を書いた後にすべてのパースをチェックするだけでなく、1つパース処理を作成する度にパースのチェックを行う方が、ミスに気づきやすく最終的に運用の負担が少なくなります。
このようなクローラー作成作業を効率化するために、VASILYでは、Crawler Generatorという社内ツールが開発されています。
このツールでは、クロールする項目ごとにXPathや、正規表現などを設定するだけでパース処理が作成できるため、効率的にクローラーを作成できます。 また、項目ごとにプレビュー機能がついており細かく項目のチェックを行うことで、間違った情報をパースしてしまっていることにもすぐに気づくことができます。
クローラー運用時
クローラーを作成した後も、クロール元サイトのリニューアルなどにより正しいデータ取得できなくなることがあります。 この正しいパースができなくなっているという異常を未然に防ぐことは難しいため、いち早く異常を検知し、修正することが大事です。 VASILYではクローラーの異常を検知するために、3つのチェックを行なっています。
- パースエラーが発生していないか
- 商品詳細総ページ数に変動がないか
- 新商品の追加数に変動がないか
パースエラーが発生していないか
初めは正しい情報をパースできていても、クロール元サイトのリニューアルなどで、正しい情報をパースできなくなることがあります。 そこで処理を行った商品ページ総数のうち、ある一定以上パースが失敗している場合を、異常として検知します。 しかし異常が検知されたクローラーの何のパースが失敗しているかを特定・調査しなければいけません。 この時、ログが散在していたり・使いにくい状態だと調査に時間がかかってしまいます。 そこで、ログの集約・調査に、BigQueryを用いています。 BigQueryにログ集約テーブルを作成し、クロールの処理ログを流すことで、エラーの特定調査を効率的に行えるようにしています。 あるサイトでパース異常が検知されたら、どこのパースが失敗しているかをBigQueryのログ集約テーブルから調査し、修正を行います。
商品詳細総ページ数に変動がないか
IQONのクローラーは毎日クロール元の商品リストページから、全商品詳細ページを取得しています。 ECサイトの商品総数は日々多少の増減はしますが、大幅に変化することはあまりありません。 そこで毎日の総商品詳細ページ数を監視し、大幅な変化が見られるサイトを異常とみなしチェックすることで、すべての商品をクロールしていることを保証しています。 この大幅な変化が見られるサイトを検知するために、標準偏差を用います。 毎日クロールするページ総数が変わらないことを期待し、直近1週間のクロール数と今日のクロール数から、標準偏差を求め異常かどうかを検知しています。 ここで直近1週間のデータを使用している理由は、様々な日数で試した結果、異常がない日が続く日数として1週間が適切であったからです。 一週間以上の長い期間を対象とすると、過去に異常検出された日が入ってしまい、異常でないサイトも異常として検知されてしまうことがあります。 また、異常とみなす閾値については、初めは厳しく設定し運用する中で調整しています。
新商品の追加数に変動がないか
商品詳細総ページ数チェックに加えて、新商品追加数に変動がないかをチェックしています。
しかし新商品が毎日追加されるサイトもあれば、更新頻度が低いサイトもあり商品追加頻度は各ECサイトごとに様々です。 そこで、2つのチェックを行い異常を検知しています。
まず過去新規アイテム追加0である日が最大何日続いていたかを調べ、その連続日数を超えている場合、異常として検知するというチェックを行っています。 具体的には、直近1か月のクロール情報から日ごとの新規アイテム追加数を取得し、アイテム追加が0である日の最大継続日数を算出します。 今日のアイテム追加数が0であるサイトの中から、最大継続日数を更新しているものを異常とみなし検知します。 ここで直近1か月のデータを用いているのは、先ほどと同じく異常が正しく検知されるのに適した日数が1か月であったからです。 状況によって適した日数は変わりますが、だいたいの目安として考えていただけると幸いです。
また、毎日アイテム追加が行なわれているサイトが、急にアイテム追加されなくなった場合も検知しています。 具体的には、連続10日間アイテム追加されていたが、突然アイテム追加数が0になった場合を異常とみなして検知しています。 連続10日間アイテム追加があるということは基本的に毎日アイテムが追加されるサイトと考え、毎日アイテム追加があるはずのサイトが急にアイテム追加されなくなった場合は、こちらのクロールに異常があると考えこのチェックを導入しています。
過去10日間のデータを用いているのは、パースのエラーなどの要因でアイテム追加に影響があったサイトも、この検知の対象になるように調整した結果です。
修正対象クローラーを分かりやすく確認するために
これまでIQONがクローラーをどのようなチェックで運用しているかをご紹介しました。 これらはチェックの方法であり、毎日どのサイトで異常が発生しているかを一目で確認できるものが必要です。 VASILYでは、昨年末まで修正対象のクローラーを検知するために専用のダッシュボードを作成し運用に使用していました。 しかし、誰がどのクローラーの修正を行ったかがわからなかったり、見るべき指標が多く、異常を検知できていない時があるという問題がありました。
そこで改めて効率的にクローラーの異常をわかりやすく検知し運用するためにはどうすれば良いかを考えた結果、クローラーチェックツールの開発に至りました。
このツールでは、運用に必要な下記3つのチェック項目それぞれについて正常か異常かが一目でわかり、なおかつ対応が必要なクローラーがどれかをすぐに確認することができます。 また修正状況を確認することもできます。
- 商品詳細ページ数に変動がないか
- 新規アイテム追加に異常はないか
- パースのエラーが発生していないか
すべてのサイトに対して3つのチェックを行い、異常が検知されたチェックを赤く表示しています。 この時どれくらいエラーが起きているかという数値は表示せず、エラーが起きているサイトはすべてその日中に修正すべきと考え、異常か正常かという表示のみを行っています。
担当の欄には、バックエンドチームの名前がランダムに割り振られ、毎日割り振られた担当のクローラーの修正を行います。 異常が修正されたことを確認した後、画面上のFixedボタンを押すことで、対応完了したことが他の人にもわかるようになっています。 このツールを用いることで、どのクローラーで異常が発生しているかが一目でわかりまた誰がどのクローラーを修正したかが分かりやすくなり、効率的にクローラーを運用できるようになりました。
まとめ
以上、IQONのクローラー運用についてご紹介しました。 IQONでは、数百のECサイトをクロールしているため、クローラーを効率的に作成・運用するために仕組み化を行っています。 現在、クローラーの異常は当日中に検知・修正し、再稼働させていることで毎日正しい情報をIQONに掲載することができています。 ぜひご紹介した仕組みの中で参考になるものがあれば導入してみてください♩
最後に
クローラーの運用はとても地道です。しかしIQONに、商品情報が正しく掲載されていることは必要不可欠です。 そして正しい商品情報を掲載するためのクローラーを、効率的に運用することにとてもやりがいを感じます! VASILYでは、クロール・効率化・仕組み化に興味がある人を大募集しています。 春季インターンの募集も行っておりますのでご興味のある方は、是非弊社に遊びに来てください!