もろず blog

もろちゃんがITに関しての様々なトピックを解説します

【在庫一掃処分セール2015】確実にモテる Web サイトクローリング & スクレイピング


f:id:chanmoro999:20151229002710p:plain

【在庫一掃処分セール2015】
とりあえず記事を書き始めたものの途中で何らかの理由でモチベーションが下がり放置されていた記事を掘り起こして、なんとか続きを書き切ることで 2015年に悔いを残さず新年を迎えようという企画です

この記事の途中でモチベーションが落ちた主な原因
  • 文章のテンションの方向性を見失った
  • この内容に興味がある人が皆無に思えた


さあ、そんな理由でボツになりかけていた記事をお楽しみください



誰でも1度は モテたいなーと思いますよね?

そんなときふと思いました

「Webサイトをクロールしたらモテそうだなー」と

そこで、今回は確実にモテる Web サイトクローリング & スクレイピングのやり方を皆さんにご紹介します


そもそも "クローリング"、"スクレイピング" って何?というあなた
クローリングもしくはスクレイピングとは、お目当の Web サイトにアクセスして情報を抽出することを言います
※正式にはクローリングとスクレイピングには区別があるらしいです

どうです、何だかモテそうでしょう?


この記事では
1. なぜモテる Web サイトクローリングが求められているのか
2. モテるのはどんな方法なのか
3. PhantomJS & cheerio の最強タッグ
4. クローラーの実装方法
5. PhantomJS の よくある質問
6. クローリングは慎重に!
7. まとめ
について説明します


1. なぜモテる Web サイトクローリングが求められているのか

さて、モテる Web サイトクローリングのやり方を紹介する前に、なぜ今までのクロールではモテないのかを考える必要があります
まずは、これまでに僕がトライしてきたモテないクローリングの歴史をご紹介します
なぜ今までの方法がモテないのか、どうすればモテるのかを紐解いて行きましょう

クローリング 1.0 時代

まず最初にクローリングでモテようとして思いつくのは、手動で Web ブラウザからサイトにアクセスして目視で情報を探して抜き出す方法です
特に知識がなくても誰でもすぐにできるし無意味な安心感があります

"週末は家でクローリングしているよ" と言えば何だかモテそうだし


しかし、残念ながらこの方法ではモテません

なぜなら、この方法がモテないのは全て手作業でやる必要があるからです
クロールしたい対象が数千ページもある場合はとても太刀打ちできません

何の戦略もなくがむしゃらにテンションを上げているうようなものです


これじゃあモテません

クローリング 2.0 時代

さて、クローリングという言葉だけで簡単にモテるわけではないという現実を理解したところで、
何とかしてこの作業を自動化したらモテるのではないか?と考えました


そこで wgetgrepsed を使い HTML のテキストを切り貼りして情報を抜き出す方法を考えました
"bashスクリプトでクローリングを自動化しているから今週末は空いているよ" と言えば何だかモテそうだし

モテるクローリングを自動化したしこれで最強にモテるぜ!bash 最高!ヒーハー!と思って満足してました


しかし、そんな夢心地もつかの間

残念ながらこの方法でも永久にモテることはありません


まず、この方法では HTML をただのテキストファイルとして解析する必要があります
ひたすら正規表現と自分との戦いです

クロール対象のページやサイトが変わると HTML から文字を抽出する正規表現を1から考え直す必要があります
HTML の構造を完全に無視しているので、せっかくきれいな構造でつくられているサイトでもさほど労力は変わりません


そして、wget やプログラムの関数で HTTP リクエストを送り受け取った素のレスポンスには javascript 実行前の素の HTML しか含まれていません
なので、AngularJS、BackboneJS などのフレームワークAjax などにより javascript で HTML を描画しているサイトの場合、その実行後の HTML を見ることができないのです

つまり、レスポンスとして受け取った直後の HTML と描画された後の HTML は異なっている場合があるということです
※いわゆる SEO 対策でも同じことが問題になるわけですね

なので、ページにアクセスしても手に入った html はただの空の body タグだけ、というような悪夢のような展開に陥るわけです


自分がよく知っているターゲットには強くても、知らない新しいターゲットには人見知り
更に、今日の俺はイケているぞ!という勘違いをしたまま突進していき、フタを開けてみたら何も実りがない
気づいた頃には時すでに遅し、というようなものです


これじゃあモテません

クローリング 3.0 時代 ← いまここ!

これまでの方法では全くもってモテないという現実を突き付けられました

  • もう一生モテないんじゃないか?
  • そもそもクローリングでモテようとしていること自体が間違いなんじゃないか?
  • スタバで MacBook Air を開いてソイラテを飲んでいる方がモテるんじゃないか?

という疑念が湧いてきます

ですがきっと、世界中のモテないクローラー達も同じようにモテるための方法を求めているはずです
Google でさえモテるために世界中の頭脳を駆使して日々模索し続けているはずです


そんな葛藤の中、とうとう僕は考えつきました


クローリング 2.0 時代の利便性を残しつつ、もっと簡単に柔軟に情報を抜き出すことができればきっとモテるだろう

ターゲットが誰であろうと汎用的に対応できれば必ずやモテるだろうと

真実を見極める目を持つことが重要だと

そう、今こそクローリングでモテる時代だと


どうです、モテそうでしょう?

記事の先頭に戻る


2. モテるのはどんな方法なのか

イマドキのモテるクローラー達はどんな方法でサイトをクロールしてモテているんだろうと一生懸命ググりました
必死でググりました
モテているやつらにはきっと共通するものがあるはずです

数ある情報の中からモテる可能性が高そうなこんな方法を見つけ出しました


そしてこれらを実現するための素晴らしいツールに出会いました
それが今回ご紹介する PhantomJS と cheerio です

これらを使いこなすことで、ついに僕らはモテるクローリング 3.0 の時代へ突入することができます


どうです、モテそうでしょう?

記事の先頭に戻る


3. PhantomJS & cheerio の最強タッグ

PhantomJS、cheerio を使用して Web サイトクローリングを実施します

これらのツールがどんなものかを簡単に説明します

PhantomJS

PhantomJS - Scriptable Headless Browser

めっちゃ簡単にいうと CLI で操作する web ブラウザです

PhantomJS is a headless WebKit scriptable with a JavaScript API.

と公式サイトに書かれている通り、画面がないブラウザで操作は全て javascript で行います

PhantomJS は通常の Web ブラウザと同じレンダリングエンジンを備えているので、ページ内の javascript が実行された後の HTML を取得することができます
また、アクセスした Web サイトを通常の web ブラウザと同じように操作することができ、画面キャプチャを画像や PDF で保存する機能もついています

今回はクローリングのために利用していますが、Web アプリケーションのe2eテストにも利用されているようです
PhantomJS を使えば Web サイトに対してのあらゆる操作を高度に自動化するのに使えますね


どうです、モテそうでしょう?

cheerio

GitHub - cheeriojs/cheerio: Fast, flexible, and lean implementation of core jQuery designed specifically for the server.

めっちゃ簡単にいうと node.js 上で使える jQuery です
jQuery 本家のライブラリではなくて、node.js 用に jQuery を再実装したモジュールらしいです

これを利用することで、node.js から jQuery と同じように DOM 操作ができます
HTMLの文字列を解析するため、ファイルに保存された HTML に対して処理できるのがこれの利点です


わざわざそんなことしなくても、PhantomJS 内で jQuery を読み込んでも同じことができるんじゃない?と思ったそこのあなた

今回僕がやりたかったことでは、HTML の取得と HTML の解析は別々にした方が使い勝手がいいと判断したので cheerio を使うことにしました


どうです、モテそうでしょう?


記事の先頭に戻る


4. クローラーの実装方法

それでは具体的に PhantomJS & cheerio の使い方を見て行きましょう

サンプルコードを github に置きました
github.com


サンプルコードにある方法はこんな流れです

  1. PhantomJS でレンダリング済みの HTML を取得してファイルに保存
  2. cheerio で HTML ファイルをパースして情報を抽出

ちょっとややこしいんですが js ファイルの違いはこんな感じです

  • crawler.js
  • analysis.js


それぞれのコードは以下のようにコマンドラインから実行します

$ phantomjs crawler.js http://www.google.com path/to/file.html
$ node analysis.js path/to/file.html


URL のリストを作っておけば、こんな感じにして自動でクロールできます

for f in `cat urlList.txt`
do
  phantomjs crawler.js $f path/to/$f
  node analysis.js path/to/$f >> siteData.tsv
done

このサンプルでは analysis.js でWeb サイトのタイトルと description を tsv 形式で標準出力するようにしていますが、実装次第でどうにでも拡張できます
取得後の HTML や取得した情報を mongodb や elasticsearch に入れるとイケてるクローラーが作れそうな気がしてきますね


どうです、モテそうでしょう?


記事の先頭に戻る


5. PhantomJS の よくある質問

そもそもどういうことかよく分からないんだけど

"ヘッドレスな web ブラウザ" という以上に簡潔でいい説明はありません
web ブラウザ上の javascript コンソールの中にコードを書く感じで操作できます

Firefox とか Chorome とは全然違うんでしょ?

PhantomJS は QtWebKit という webkit をベースとしたレンダリングエンジンを利用しています
メジャーなブラウザだと WebKit2 を使っている Safari が一番近いようですが、厳密には違うものなので Firefox や Chorome と同じようにブラウザ毎の
微妙な違いはあります

Selenium とは何が違うの?

Selenium はブラウザの操作を自動化するためのツールなので FirefoxChromeIE などのブラウザを操作するための API を提供してくれるものですが、PhantomJS は Web ブラウザそのものです

とはいえ、どちらも e2e テストなどによく利用されているものではあるので、ブラウザ操作の自動化という点ではどちらも似たような感じですが

FirefoxChromeIE などのブラウザでテストをする必要がある場合は Selenium を使うということになると思います

PhantomJS を node.js 上から使うことはできないの?

これは確かにその通りなんですよね
僕も PhantomJS を見つけた時は

  • node.js のモジュールで PhantomJS があればもっとモテそうなのに
  • なぜもっとモテようとしないんだ

と思いました


実際のところ node.js から PhantomJS を呼び出すためのモジュールはあります
GitHub - amir20/phantomjs-node: PhantomJS integration module for NodeJS

処理をイベントドリブンで書かないといけないので正直サクッと使えるかどうかというと微妙です
モテたい気持ちが全面に出すぎたせいでコールバック地獄に苦しんでいるようでは結局モテないので、今回は PhantomJS をそのまま使いました

また、同期処理で書ける node-phantomjs-sync というモジュールもあります
GitHub - sebv/node-phantomjs-sync: sync version of phantomjs-node

これはこれで使えそうでしたが、今回はわざわざ node.js と連携させる理由がなかったので使いませんでした


とはいえ、本格的なクローラーを作る場合や、あるシステムの一部として PhantomJS を使おうとするとこれらのモジュールが必要になってくるはずです

その先には更にモテる未来が待っていることでしょう

PhantomJS と node.js の javascript コードを同じにはできないの?

実際にコードを書いてみると、それぞれの javascript のコードはほとんど同じに見えるので、きっとこの疑問がでてくるはずです
ですが、ここには地味に難しい問題があるので、PhantomJS と node.js は全く別の実行コンテキスト上にある、と考えなくてはいけません

PhantomJS は PhantomJS 内部に自分の javascript エンジンを持っています
Webkit に含まれる JavaScriptCore というエンジンで、HTML ページ上の javascript を実行しているようです
また、PhantomJS 自身を操作する時の javascript もこの JavaScriptCore を使っています


なんで PhantomJS は node.js のモジュールではないの?という質問がQ&Aにありました

PhantomJS - Frequently Asked Questions (FAQ)

The short answer: "No one can serve two masters."

と仰っているように、
node.js の実行環境 (Google V8 JavaScript Engine) と Webkit の実行環境 (JavaScriptCore) は javascript ではあるけど全く違うものなので、これらをくっ付けるというのは想像よりもとんでもなく難しい問題なわけです


つまり、Web ページ上の javascriptJavaScriptCore 上で実行し、PhantomJS の操作は V8 で実行する、
となるとたしかにわけわからん感じになりそうですよね

Google Chromejavascript エンジンは V8 なので、もしかしたらそういう製品を作れる可能性はあります

ただ、仮に両方が同じエンジンを使っていたとしても、それぞれの実行コンテキストを同じにしちゃっていいのか?というと、それは簡単な話では無さそうです

とにかく現状では、これはそれだけのパワーをかけてまで PhantomJS がやりたいことではないはずなので、こういった状況になっているわけですね


ちなみに、先に紹介した phantomjs-node などの node.js モジュールを使う場合には、このあたりを理解できてないとハマるかもしれません


どうです、モテそうでしょう?

記事の先頭に戻る


6. クローリングは慎重に!

Web サイトのクロールをする場合は対象のサイトがクロールを明示的に禁止している場合があります
※例えば Twitter は事前承諾なしのスクレイピングは禁止!と利用規約に書かれています


禁止していなかったとしても過度にサイトにアクセスすると状況によっては DoS 攻撃と同じ事になってしまいます
負荷が掛かりすぎないように同時アクセス数を減らしたり、リクエストの間隔を空けるなどして Webサイトに迷惑がかからないようにしましょう

過去にはクローリングが原因でサイトがダウンしてしまい、偽計業務妨害と判断されて逮捕されたなんて事例があるらしいです・・・


モテたいがために Web サイトに迷惑をかけるようではいつまで経ってもモテません

やろうとするクローリングによって Web サイトに迷惑を掛けないか、自分は本当にモテているのか、お茶でも飲んで落ち着いてから考えましょう


記事の先頭に戻る


7. まとめ

さて、ここまでモテる Web サイトクローリングのやり方について紹介してきました

もしかすると皆さんもうお気づきかもしれません


この際ハッキリ言いましょう

結局のところ、Web クローリングをすればモテるというわけではありません

Web クローリング自体はモテるためにあるものではないのです

もしもあなたが Web クローリングだけでモテようと思っているとしたら?

あなたは大きな間違いを犯していると言えるでしょう


あなたがクローリングをしようとしたとき、その先には本来パワーを掛けるべき本当にモテるための作業があるはずです
クローリング をしてモテることが最終目的ではないのです

モテたいから Web サイトクローリングをする

などという愚かな選択はして欲しくないのです

○○でモテるためには Web サイトクローリングが必要
だから私は PhantomJS と cheerio を使って楽にクローリングして、モテるための○○に100%のパワーを注ぐ

という賢者の選択をできるようになって欲しいのです


ぜひともクローリングを有効活用してモテるための本来のタスクに100%のパワーを注ぎましょう


今回は PhantomJS と cheerio を使った、確実にモテる Web サイトクローリング & スクレイピングのやり方についてご紹介しました


どうです、モテそうでしょう?

記事の先頭に戻る