本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回は本誌Vol.68~73まで「フロントエンドWeb戦略室」を連載していたmalaさんで、テーマはクローラの作り方です。個人用のちょっとしたダウンローダを書くときから、大規模なクローラを書く場合まで、Perlは強い味方になります。
なお本稿のサンプルコードは、本誌サポートサイト から入手できます。
クローラの礼儀作法
クローラ、スパイダ、bot[1] を稼働させる際は、アクセスのしかたによっては相手先のサービスに多大な負荷をかけてしまいます。本節ではまず、使用言語にかかわらずクローラを書くうえで一般的に知っておくべき作法について述べます。
robots.txtによるbotの制御── アクセスしてよいかの指示
Webサイトに置かれるrobots.txtは、botから「アクセスしてよいか」を判断するものです。アクセスする対象がhttp://example.com/
であれば、http://example.com/robots.txt
に設置されます。
以下はmixiの例 です。
User-agent: *
Noindex: /show_friend.pl
Noindex: /show_profile.pl
Disallow: /add_diary.pl
Disallow: /show_calendar.pl
Disallow: /confirm.pl
Disallow: /confirm_email.pl
Disallow: /invite.pl
Disallow: /join.pl
...
ログインしないと見られないURLにクローラからアクセスするのは意味がないので、最初から除外しているわけです。
robots.txtの仕様は、意外なことに標準化団体などによって規定されておらず、大手検索エンジンなどの対応によって事実上のスタンダードになっています。現在ではもっぱら「検索結果から除外してほしいURL」を指定するものとして認識されていますが、robots.txtが提案された当初は、クローラが動的に生成されるページに際限なくアクセスし続けて負荷をかけてしまう事故を防ぐ意味合いが強いものでした。検索エンジン以外にも、たとえば歴史あるHTTPクライアントwget もrobots.txtに対応しています。wgetにはリンクをたどってサイトを丸ごと保存する機能があるため、robots.txtの尊重は重要な機能の一つです。
metaタグによるbotの制御── アクセスしたあとの振る舞いの指示
HTMLのmetaタグでもクローラに指示を出すことができます。「 アクセスしてよいか」を指示するrobots.txtと違って、metaタグはアクセスしたあとの振る舞いを指示するためのものです。bot 向けの主なものは、noindex(検索エンジンの結果などにインデックスすべきではない) 、nofollow(リンク先をたどるべきではない) 、noarchive(キャッシュなどを表示すべきではない)の3つです。
検索エンジンへの掲載から除外
<meta name="robots" content="noindex">
検索エンジンへの掲載を除外し、リンク先もたどらない
<meta name="robots" content="noindex,nofollow">
robots.txtやmetaタグは遵守すべきか?
個人で利用する場合
robots.txtやmetaタグは守るに越したことはないですが[2] 、筆者はたとえクローラからのアクセスであっても、人間が自分の意思でリクエストを発行するようなものであれば、必ずしも遵守する必要はないと考えています。また、サイト運営者側もすべてのbotが守ってくれることを期待すべきではありません。
個人的な利用目的のクローラで気にしなくてはいけないのは、meta タグのnofollow です。robots.txt やnofollowを無視した場合、サイトに過大な負荷をかけてしまうことも考えられますので、リンクを自動でたどってダウンロードするような性質のクローラであれば、尊重することが強く求められます。
収集した情報の変換や再配信を行う場合
収集した情報を、個人的な利用目的を超えて変換や再配信、検索可能にするようなサービスを運用する場合は、クローラの作者はmetaタグのnoindex、noarchiveを遵守することが強く求められます。平成21年に著作権法が改正され、robots.txtやmetaタグによるロボット排除のルールを守ったうえで一定の条件を満たせば、日本国内で合法的に情報検索サービスを運営できるようになっています。metaタグの指示を無視して収集したコンテンツを再公開する場合、サービスの運用形態によっては法的なリスクを抱えることになるため注意が必要です。
任意のURLに対してコンテンツを取ってきて、加工したり翻訳や変換して再公開する性質のサービスは、何か特別な付加価値がない限り「既存コンテンツを変換、再配信した内容」が検索エンジンに掲載されないように、自主的にrobots.txtやmetaタグを使って排除するのがよいでしょう(最近では検索エンジン側が自動で判別してインデックスから削除していることも多いです) 。スパムだと見なされることも多いですし、法的な問題だけでなく、サイト運営者とのトラブルの原因にもなるからです。
固有のユーザエージェントを名乗ろう
ユーザエージェントがユニークであれば、もしあなたの書いたプログラムが暴走して迷惑をかけた場合に、サイト運営者はそのクローラからのリクエストを拒否する設定を書きやすくなります。多くの場合ユーザエージェントにはライブラリ名とバージョンが含まれていますので、書き捨てのスクリプトなどでいちいちユニークなユーザエージェントを名乗る必要はありませんが、継続的にクローラを稼働させる場合にはユニークなユーザエージェントを名乗るようにしたほうがよいでしょう。
皆が同じユーザエージェントを名乗っていると、サイト運営者は適切にリクエストを拒否できません。たとえばGoogleの検索結果は、ユーザエージェントに「libwwwperl」( 注3 )が含まれるリクエストを拒否することが知られています。その結果、LWPユーザすべてが不便を被ることになっています。Perlユーザに対して冷たい対応ではありますが、独自のユーザエージェントを名乗らないbotは門前払いするという意味で、納得もできます。なお、LWPを内部的に使っていても、独自のUserAgentを名乗っているライブラリは影響を受けません。
もっとも、こういったbotっぽいユーザエージェントを広範に拒否していたり、ユーザエージェントに応じてレスポンス内容が変わるサイトも多くあるため、スクレイピングを主目的とする場合など「人間向け」のコンテンツを取得するために、メジャーなブラウザのユーザエージェントに偽装してアクセスすることも広く行われています(こういった場合、Internet Explorerが使われることが多いようです) 。
ログを残し、ステータスコードを保存しよう
リクエストが拒否される場合には、400 Bad Requestや403 Forbiddenレスポンスが返るのが一般的です。ブラウザでは普通にアクセスできるのに、特定のIPアドレス、特定のユーザエージェントのクローラからのリクエストのみ拒否される、400や403レスポンスが返ってくる場合は、あなたの書いたクローラが「何らかの迷惑をかけている」可能性があるので、処理内容やリトライ処理、更新頻度などに問題がないか見なおすとよいでしょう。
コンテンツの更新頻度に合わせよう
定期的に取得するような場合には、コンテンツの更新頻度に見合った周期でアクセスしましょう。
スクレイピングよりAPIやRSSフィードを使おう
HTMLからスクレイピングする前に、APIやRSS(RDF Site Summary )フィードがないか探しましょう。たいていの場合はAPIのほうが負荷が低いですし、最小限の情報だけを出力してくれます。
重い処理は控えめにしよう
動的に生成されるコンテンツ、検索結果、大量のデータを一度に出力するエクスポート機能などは「重い」です。大量のアクセスは避けて、人間がアクセスする場合と同程度の頻度でのアクセスにとどめたほうがよいでしょう。
お行儀良くし過ぎない
Webの世界には長い歴史があり、ほとんどの人が知らなかったり、普段は意識しないマイナーな仕様がたくさんあります。
robots.txtにはCrawl-delayという拡張があり、同一ホストに対してどれぐらいの間隔でアクセスすればよいかを指示できます。これにはいくつかの検索エンジンが対応しているようです。
HTTPレスポンスの503 Service Unavailableを返す際には、Retry-Afterヘッダを指定することで、何秒後にサーバの過負荷やメンテナンス状態が回復見込みであるのかを宣言できます。ただし、クローラ側が対応しているのはほとんど見たことがありません。
こういったマイナーな仕様までもすべて守られるとは限りませんし、守らなかったからといってただちにWebサイト側に迷惑がかかるわけでもありません。ウェイトをどれぐらい入れるべきか、同時接続数はどれぐらいが適切かといったことは、相手のサービスの規模や処理内容などを考慮して決めるとよいでしょう。
<続きの(2)はこちら >