プログラマになりたい

おっさんになっても、プログラマでありつづけたい

Rubyによるクローラー開発技法の目次

 るびきちさんとの共著である「Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例」が今週末(8/23,24)くらいから、本屋さんの店頭に並ぶようです。経緯や執筆スタイルなどは別途まとめたいと思いますが、ようやくここまで辿り着けたというところです。

 AmazonとSBクリエイティブさんのページを見ても、8/21現在では詳細の目次が無いようです。手元にあったデータを貼り付けておきますので、参考にしていただければと思います。


Rubyによるクローラー開発技法 目次


Chapter 1 10分クローラーの作成
 1-1 イントロダクション 2
  1-1-1 クローラーとは 2
  1-1-2 Rubyとは 2
 1-2 クローラー 「GNU Wget」3
  1-2-1 Wgetとは 3
  1-2-2 インストール 4
  1-2-3 Wget の簡単な使い方 7
  1-2-4 クローラーとしての Wget 8
 1-3 クローラーを作るにあたってのRubyの基礎 12
  1-3-1 Rubyの特性 12
  1-3-2 文字列処理 16
  1-3-3 正規表現 19
  1-3-4 ファイルを開く 23
 1-4 Rubyでテストサーバを立てる 25
  1-4-1 標準ライブラリ「WEBrick」でお手軽httpd 25
  1-4-2 URLから規則的な内容のページを表示する 26
  1-4-3 Wgetのオプションを検証する 30
 1-5 超簡単! 10分で作るクローラー 34
  1-5-1 概略 34
  1-5-2 HTMLを解析する 35
  1-5-3 Wget を Ruby から呼ぶ 39
  1-5-4 最新記事をテキストで出力する 40
 1-6 クローラーを拡張する 42
  1-6-1 open-uriに対応させる 42
  1-6-2 RSS2.0 での出力に対応させる 43
  1-6-3 リファクタリング 47
  1-6-4 RSS サーバにする 51

Chapter 2 クローラー作成の基礎
 2-1 クローラーの目的と構造56
  2-1-1 クローラーの目的 56
  2-1-2 クローラーの構造 56
  2-1-3 クローラーが利用するライブラリ 60
  2-1-4 Ruby 製のクローラー 62
 2-2 Anemoneを利用する 66
  2-2-1 Anemoneの機能 67
  2-2-2 Anemoneの内部構造 71
  2-2-3 Anemoneの実行モデル 72
 2-3 Anemoneのインストール(Windows編) 74
  2-3-1 Nokogiriのインストール 74
  2-3-2 Anemone のインストール 75
  2-3-3 コンパイルツールを利用してビルドする場合 76
 2-4 Anemoneのインストール(Mac編) 78
  2-4-1 libxmlとlibxslt、libiconvのインストール 78
  2-4-2 Anemone のインストール 80
 2-5 基本的なクローラーを作成する 81
  2-5-1 Amazonからジャンルごとのベストセラーを取得する 81
  2-5-2 クローリング機能の作成 86 2-5-3 スクレイピング機能の作成 91
  2-5-3 RSS を利用する方法 98
 2-6 クローリングができない場合の対処法101
 2-6-1 クローリングができない原因 102
 2-6-2 プロキシサーバ 102
 2-6-3 サイト側にアクセス拒否されるケース104
 2-7 行儀のよいクローラーを作るには109
 2-7-1 robots.txt 110
 2-7-2 サイトの利用規約 112
 2-7-3 取得したデータの取り扱いと著作権 113
 2-7-4 Web サイトのリソース圧迫と業務妨害 113
 2-7-5 クローラーと API 114
 2-8 ブラウザタイプのクローラー114
 2-8-1 画面テストツール 115
 2-8-2 ブラウザタイプのクローラー作成の準備116
 2-8-3 ログインが必要なページの対処 124
 2-8-4 JavaScriptを多用しているページの対処134
 2-8-5 足りない機能を補完する138

Chapter 3 収集したデータを分析する
 3-1 収集したデータを分析する148
 3-1-1 正規表現と構文解析 148
 3-1-2 日本語の文字コードと日本語処理 149
 3-2 HTML解析と正規表現149
 3-2-1 Ruby における正規表現の実装150
 3-2-2 正規表現のオプション154
 3-2-3 正規表現のパターン 155
 3-3 文字コードの対処法156
 3-3-1 Ruby における文字コードの取り扱い 156
 3-3-2 Nokogiriと文字コード 160
 3-3-3 Anemone と文字コード 161
 3-4 RSSの解析163
 3-4-1 名前空間(Namespace)164
 3-4-2 RSS 1.0 164
 3-4-3 RSS 2.0 166
 3-4-4 Atom 1.0167
 3-4-5 RSSAtom の解析168
 3-5 HTMLの解析172
 3-5-1 Nokogiriのクラス構造 172
 3-5-2 Nokogiri、XPath の使い方 172
 3-5-3 中心的な 3 つのクラス 175
 3-5-4 簡単な XPath の抽出方法183
 3-6 自然言語を使った日本語の処理187
 3-6-1 形態素解析と特徴語抽出187
 3-6-2 日本語処理 188

Chapter 4 高度な利用方法
 4-1 データの保存方法198
  4-1-1 データストレージ 198
  4-1-2 ファイルに保存 198
  4-1-3 データベースとの連携200
  4-1-4 SQLite3に保存 201 4-1-5 MongoDB に保存 206
  4-1-5 MySQL に保存213
 4-2 クローラーの開発とデバッグ方法 219
  4-2-1 Ruby プログラムのデバッグ方法 219
  4-2-2 開発プロキシを使ったクローラーの開発224
 4-3 クローリングとスクレイピングの分離228
  4-3-1 スクレイピング部分の分離 228
  4-3-2 分離度を上げる 229
 4-4 クローラーを効率的に動かすには232
  4-4-1 多重度を上げる 232
  4-4-2 タイムアウトの調整 236
  4-4-3 HTTP Compressionによる通信データの圧縮237
  4-4-4 未取得のデータのみ取得する 238
  4-4-5 エラーコードに対する処理 238
 4-5 Anemoneのオプション一覧240
  4-5-1 Anemone のオプション 240
  4-5-2 ストレージオプション(storage)240
  4-5-3 クローリング間隔オプション(delay)241
  4-5-4 巡回戦略オプション(skip_query_strings)241
  4-5-5 探索戦略オプション(depth_limit)241
 4-6 APIを利用した収集242
  4-6-1 API を利用するメリット242
  4-6-2 Amazon Product Advertising API243

Chapter 5 目的別クローラーの作成
 5-1 Google の検索結果を取得する248
  5-1-1 Google の検索結果のスクレイピング 248
  5-1-2 Gem を利用する 250
  5-1-3 Google Custom Search API を利用する 251
 5-2 ブログへのクローリング 256
  5-2-1 個別ブログの記事取得256
  5-2-2 本文抽出260
 5-3 Amazonのデータを取得する263
  5-3-1 商品 ID「ASIN」263
  5-3-2 商品 ID の取得 263
  5-3-3 商品データの取得 265
  5-3-4 新着ランキングセール 266
 5-4 Twitter のデータ収集 267
  5-4-1 HTML からのクローリング 267
  5-4-2 Twitter の API272
  5-4-3 Twitter REST API 272
  5-4-4 Twitter Streaming API277
 5-5 Facebookへのクローリング278
  5-5-1 Facebook Graph APIとFQL278
  5-5-2 認証が必要ないFacebook Graph API 279
  5-5-3 認証が必要な Facebook Graph API 280
 5-6 画像を収集する285
  5-6-1 Flickr からクローリングで収集する 285
  5-6-2 Flickr API 287
 5-7 YouTube から動画を収集する 290
  5-7-1 動画の URL を収集する 290
  5-7-2 動画をダウンロードする291
 5-8 iTunes Store の順位を取得する 293
  5-8-1 iTunes Storeのランキング293
  5-8-2 カテゴリ ID とランキング種別 296
  5-8-3 iTunes アプリのランキングを取得する 297
 5-9 Google Playの順位を取得する299
  5-9-1 Google Playのランキング299
  5-9-2 Google Playのクローラーライブラリ 301
  5-9-3 カテゴリ ID とランキング種別 302
 5-10 SEOに役立てる304
  5-10-1 検索順位を収集する 304
  5-10-2 被リンク 305
 5-11 Wikipediaのデータを活用する308
  5-11-1 Wikipedia からのクローリングとデータ 308
  5-11-2 Wikipedia のカテゴリの活用 309
 5-12 キーワードを収集する311
  5-12-1 Wikipedia のタイトル 311
  5-12-2 はてなキーワード311
  5-12-3 Google Suggest API 313
 5-13 流行をキャッチする314
  5-13-1 瞬間的なトレンドをキャッチする314
  5-13-2 長期的なトレンドをキャッチする319
 5-14 企業株価情報を収集する321
  5-14-1 証券コード一覧を取得する 321
  5-14-2 企業情報および当日の株価を収集する 322
  5-14-3 株価の時系列データを収集する325
 5-15 為替情報金融指標を収集する327
  5-15-1 国債金利 327
  5-15-2 為替情報 331
  5-15-3 その他の経済指標332
 5-16 郵便番号と緯度経度情報を取得する333
  5-16-1 Google Maps APIによるジオコーディング333
  5-16-2 郵便番号から緯度珪素の検索334
  5-16-3 郵便番号と経度緯度データによる可視化 335
 5-17 新刊情報を収集する336
  5-17-1 Amazonの新刊予約の検索パラメータ 336
  5-17-2 新刊情報を取得する 338
  5-17-3 APIを利用する 340
 5-18 荷物を追跡する342
  5-18-1 ヤマト運輸の荷物を追跡する 342
  5-18-2 Google Calendar に登録する 3434
 5-19 不動産情報を取得する346
  5-19-1 レインズからのデータ取得 346
 5-20 官公庁のオープンデータを活用する349
  5-20-1 提供されているデータ一覧 350
  5-20-2 次世代統計利用システムのAPI登録 351
  5-20-3 次世代統計利用システムの API の利用352
 5-21 新聞の見出しを集める355
  5-21-1 取得対象とプログラムの構造 355
  5-21-2 親クラスの実装355
  5-21-3 各社別の記事URL の抜き出し 356
  5-21-4 呼び出し元の実装357
  5-21-5 ページング機能の追加 358

Chapter 6 クローラーの運用
 6-1 サーバサイドで動かす362
  6-1-1 サーバで動かすメリット362
  6-1-2 サーバへのインストール363
  6-1-3 Linuxのコマンド 372
 6-2 定期的にデータを収集する375
  6-2-1 Crond でスケジューリングを登録する375
  6-2-2 Crond で動かす際の注意点 377
  6-2-3 差分を検知する 378
  6-2-4 時系列で表示する 380
 6-3 収集結果をメールで自動送信する384
  6-3-1 どういった内容を送るのか 384
  6-3-2 Gmail を使って結果通知する385
  6-3-3 Amazon Simple Email Service(SES)を使って結果通知する390
 6-4 クラウドを活用する396
  6-4-1 AWS のサービス 396
  6-4-2 クラウド上のサーバを利用する 398
  6-4-3 クラウド上のストレージを利用する 402
  6-4-4 Amazon SNS で通知する 407
 6-5 さらなる高速化の手法410
  6-5-1 非同期処理 410
  6-5-2 分散処理415
 6-6 変化に対応する419
  6-6-1 検知方法419
  6-6-2 修正&再処理 422
 6-7 クローラーとそれに付随する技術424
  6-7-1 データを活用する方法425
  6-7-2 データの可視化 425
  6-7-3 データマイニング 426

See Also:
『Rubyによるクローラー開発技法』を書きました

参照:
新刊『Rubyによるクローラー開発技法』2014/08/25発売! | るびきち×Emacs
SBクリエイティブ:Rubyによるクローラー開発技法

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

KimonoLabsと今後のサービスのあり方のはなし

f:id:dkfj:20140813182433p:plain


 別記事にも書きましたが、第2回Webスクレイピング勉強会@東京に参加してきました。そこで注目のサービスであるKimonoLabの中の人であるPratap Ranadさんの話を聞いてきました。シンプルながら明確なメッセージで、非常に感銘を受けました。

KimonoLabsのミッション



 KimonoLabsの始まりは、あるサービスを作ろうとして航空会社ごとのデータを取得しようとしたことが始まりのようです。しかし、航空会社ごとにWebスクレイピングするのは手間で、非常に大変だったそうです。サイト側がAPIを提供すれば解決なのですが、APIを提供している会社は0.0005%に過ぎないそうです。またセマンティックWebにすれば良いという話もありますが、あれはデータを提供する側が努力する必要があり、そもそも構造として間違っていたとのことです。KimonoLabsはこの構造を逆転させ、データを取得する方が少し労力を提供すれば良い構造にしたとのことです。また、誰かがKimonoLabsを使ってスクレイピングのAPIを作ることにより、他の人でも利用できるようになり、結果としてデータを構造化させることができるとのことです。
 私は、セマンティックWebの失敗の理由について、非常に共感しました。いろいろな職場でも議論されてると思いますが、プロジェクト等の経験などがどうして共有されないのかという問題と一緒だと思います。情報を取得する方ではなく、提供する側に努力させても、インセンティブがないのです。受益者側の働きかけに構造を変える必要があるのです。この辺り、KimonoLabsの狙いは非常に素晴らしいと思います。

KimonoLabsの由来



 そもそもKimonoLabsおよびKimonoの名前の由来は何なのでしょうか?それは、「Open the kimono」というビジネス上のスラングに由来するようです。参加者一同、Open the kimonoと聞いたとたん、頭の中は悪代官様しか出なかったのですが、(ビジネス上の)ややこしい問題を紐解くとか整理するといったような意味があるようです。もっとも、サービスに名前をつける必要があったので、思いついたのをつけたという事実もあるようです。

KimonoLabsの収益源



 無料で充分使えるKimonoの収益源の話です。私も気になってたのですが、企業側にAPI提供を手助けすることで収益化を図っているようです。つまり、一般の人が用途の応じてサイトからデータを収集するのではなくて、サイトの運営者側がKimonoを利用してデータを提供するということです。この構造は、一番驚きました。実際、Fortune500などの有力企業に多数採用されているようです。

感想



 先日の記事にも書きましたが、クローラーを作る人やWebスクレイピングする人は、それ自体が目的ではなくデータを集めて何かをするのが目的です。当然ながら、データを収集する為の労力は最小限にするのがよいでしょう。その点を考えると、KimonoLabsが目指す点は、非常に素晴らしいと思います。実際、スクレイピングする人の9割は、Kimonoを利用すれば解決するでしょう。もちろん、Kimonoでは解決できない問題も多数あります。だからと言って、オーダメイドのスーツのようなものを万人に勧めるのは間違いです。既成品では満足できない人にこそ、オーダーメイドが必要なのです。
 SIerに身をおく自分としては、今後のIT市場の方向性がはっきり見えてきて正直怖い部分もあります。一方で便利なサービスが容易に利用できて、楽しみな側面があります。それらを組み合わせて、何を実現するのか。その辺りを考えていこうと思います。
 最後に、半年かけて手掛けてきたクローラー本の発売を目前に控えた自分としては、この発言が一番印象的でした。
私も同感です。


See Also:
RubyでWebスクレイピングの話をしてきました。第1回Webスクレイピング勉強会@東京
「第2回Webスクレイピング勉強会@東京」に参加&発表してきました
プログラミング・レスで5分でサックリWebスクレイピング「kimonolabs」
『Rubyによるクローラー開発技法』を書きました


参照:
マウスでなぞるだけで、あらゆるデータ取得をAPI化——Y Com出身のスタートアップKimono Labsにインタビュー - THE BRIDGE(ザ・ブリッジ)
第2回Webスクレイピング勉強会@東京 に参加してきた #東京スクラッパー | Developers.IO
第2回Webスクレイピング勉強会@東京(全3回) - connpass
2014/08/17 第2回Webスクレイピング勉強会@東京 #東京スクラッパー - Togetterまとめ

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

「第2回Webスクレイピング勉強会@東京」に参加&発表してきました

 前回に引き続き第2回Webスクレイピング勉強会@東京に参加し、発表もしてきました。今回は、ブログやサイトから本文部分をどうやって抽出するのかというテーマです。ブログの本文抽出とは、ヘッダーやフッダー、サイドメニューなど情報として不要な部分を排除して、本文部分だけを抜き出す手法です。HTMLのタグを解析するルールベースと、自然言語処理を利用して本文らしさを抽出するヒューリスティックな方法の2つについて、簡単に説明しています。

解説と質疑応答



 そもそもブログやサイトの本文を抽出する目的としては、2つくらいあるのではと思います。1つは、その記事そのものを読みたい場合。もう1つは、記事を統計解析などの元データとして利用したい場合があると思います。前者の場合は記事全文がないと意味がないし、後者は必ずしも記事全文は必要ないという前提になります。
 そういった前提の場合、どういった手法が適切なのかというテーマです。記事全文を正確に取得する場合は、HTMLのタグを解析してルールベースでやるべきです。しかしこの場合は、ブログやサイトごとにHTMLの構造が違うので、ブログ種別ごとに作りこむ必要があり対応に手間がかかります。一方で記事全文が必ずしも必要がない場合は、本文らしさを抽出するヒューリスティックな方法が良いと考えています。
 本文らしさの抽出の方法としては、原理の簡単な説明と既存のモジュールを紹介しています。説明忘れてたのですが、Rubyの本家ExtractContentは、Rubyのバージョンによる正規表現エンジンの違いから、1.8系まででしか使えません。1.9以降で利用する場合は、Fork版を利用する必要があります。ご注意ください。

・ブログのユーザ属性の取得方法について
 「これ間違いなくおじさんだ!」が解るのかについて。どの話の流れからか忘れましたが、ブログを書いている人の属性を取得するという話になりました。私としては、2つくらいの方法があるかと考えています。1つ目はブログのプロフィールに載せられているTwitterやFacebookから属性(男性/女性、10代、20代、30代…)などを取得する。もう一つは、予め素性がはっきりしている人のデータを集めて教師データとして、クラスタリングする方法などが考えられます。ただジェンダーや性別を特徴づける言葉は曖昧なので、後者の方法は中々難しいのではと思います。一方で、関心の範囲でクラスタリングするのは比較的可能だと思います。

感想



 当日は体調最悪で、発表中もボーっとしてて質疑応答の記憶もロクに無いです。申し訳ないです。KimonoLabsさんの発表まで何とか聞いて、途中で断念して帰りました。Kimonoについては色々書きたいことがあるので、改めてエントリーをあげようと思います。Kimonoの中の人と話せなかったのが残念でなりません。
 あと当日も宣伝していましたが、「Rubyによるクローラー開発技法」が遂に今週末に発売です。早いところで8/23くらいから並びだすのではという話です。もし買ったかたおられましたら、感想頂ければありがたいです。どんな厳しい言葉にも耐えられるハートの準備中です。

See Also:
RubyでWebスクレイピングの話をしてきました。第1回Webスクレイピング勉強会@東京
プログラミング・レスで5分でサックリWebスクレイピング「kimonolabs」
『Rubyによるクローラー開発技法』を書きました
KimonoLabsと今後のサービスのあり方のはなし


参照:
第2回Webスクレイピング勉強会@東京 に参加してきた #東京スクラッパー | Developers.IO
第2回Webスクレイピング勉強会@東京(全3回) - connpass
2014/08/17 第2回Webスクレイピング勉強会@東京 #東京スクラッパー - Togetterまとめ


Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

プログラミング・レスで5分でサックリWebスクレイピング「kimonolabs」

 「Rubyによるクローラー開発技法」で付録か何かで書こうか悩んだ末に書かなかったのが、kimonolabsの話です。kimonolabsは、クローラー/スクレイピングをオンラインで実行できるWebサービス(SaaS)です。クローラー本を書いておいて何ですが、9割の人は自分でクローラーを作らずに、この手のサービスを利用すれば事足りると思います。(書かなかった理由は、Ruby縛りサービスの継続性とスケジュールの問題です。主に最後)
f:id:dkfj:20140813182433p:plain

kimonolabsとは?



 kimonolabsは、先述のとおりWebスクレイピングをしてくれるSaaSです。会員登録してChromeの拡張をいれれば、すぐに使えるようになります。一般的に、Webスクレイピングする場合は、次のような手順が必要です。

  1. 対象ページのダウンロード
  2. ダウンロードしたページから、特定の箇所を抜き出す
  3. 抜き出したデータの保存

 対象ページのダウンロードとデータの保存はそれほど手間ではないのですが、2番目の特定の箇所を抜き出すというのが中々やっかいです。一般的には、各プログラムの構文解析器(パーサー)を使って、xpathやCSSセレクタなので要素を指定して抜き出します。パーサーは、Ruby製のNokogiriやPython製のbeautifulsoupなど色々あります。このツールの使い方を覚えるというのと、xpathやCSSセレクタなどHTMLの要素の指定の仕方の2つを覚える必要があります。それ以前に、プログラミングの仕方を知っていないと出来ません。
 kimonolabsを使えば、このあたりを一切知らなくてもスクレイピングできるという優れ物です。対象のページをブラウザで開いた上で、kimonolabの拡張を開いて取得したい部分をマウスで選択するだけです。簡単便利です。
 私も幾つかスクレイピングのSaaSを知っていたのですが、ここまで完成度が高いものはしりませんでした。前回の、Webスクレイピング勉強会@東京で教えて貰いました。

kimonolabsの使い方 APIの登録編



 それではAmazonの商品ページを対象に、実際の使い方を試してみましょう。アカウントとかは適当に作って下さい。今回の取得対象は、このページを対象に、全体のランキングとカテゴリーごとのランキングを取得するようにします。
※ステマ

1.対象ページを開いた上で、kimonolabのchromeの拡張を起動
f:id:dkfj:20140813185212p:plain

2.取得対象を指定する
 マウスのカーソルを取りたいあたりに移動させると、黄色で選択してくれます。その上で、不要な部分があれば☓をしていけば良いです。複数指定したい場合は、kimonoのメニューの+ボタンで増やします。
f:id:dkfj:20140813185746p:plain
ちなみに、中々思い通り選択してくれなくて、イライラすることもたまにあります。

3.取得データを確認する
 メニューの右の方の、=みたいなのや<>でプレビューできます。
f:id:dkfj:20140813190340p:plain
f:id:dkfj:20140813190356p:plain

4.APIとして登録
 確認して問題なければ、Doneボタンを押してAPIとして登録します。その際に、適当に名前を付けます。
f:id:dkfj:20140813190506p:plain

5.APIの詳細設定
 通知や訪問間隔などの設定をします。
f:id:dkfj:20140813190550p:plain

kimonolabsの使い方 データの取得編



 取得したデータは、kimonoの管理画面もしくはアプリケーションIDとAPIキーを指定したURLで取得できます。
・データのバージョン指定
http://www.kimonolabs.com/api/{VERSION_NO}/{API_ID}?apikey={YOUR_API_KEY}
・時系列で取得
http://www.kimonolabs.com/api/{API_ID}?apikey={YOUR_API_KEY}&kimseries=1

 1時間ごとに取得したデータを、時系列でみた例です
f:id:dkfj:20140813182447p:plain

 データは、json,csv,rssで取得できます。データをプログラムから呼び出して、さらにゴニョゴニョするといったことも簡単にできます。

まとめ



 かなり完成度も高く、無料の範囲でも充分利用できます。今回は紹介していませんが、ページネーションなどもできます。クローラーやWebスクレイピングは、それ自体が目的には成り得ません。収集したデータをどう活用するか、そこからが本当のスタートです。だから、データ取得の部分をサービスで代用できるのであれば、できるだけ利用して楽をすべきです。ということで、今は必要でなくても、頭の片隅に記憶しておいたら良いと思いますよ。
 ついでに言うと、自作のクローラーはどういった場合に作ればよいのか?夏休みの自由研究と、既成のサービスで機能的に物足りなくなってからで良いと思います。もしくは、このサービスをキッカケにクローラーに興味をもったら、この本あたりで中でどのように動いているのか勉強するのも良いですよ。※ステマ


See Also:
『Rubyによるクローラー開発技法』を書きました
KimonoLabsと今後のサービスのあり方のはなし


参照:
オープンデータのためのスクレイピング
第1回Webスクレイピング勉強会@東京 (全3回) - connpass


Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

『Rubyによるクローラー開発技法』を書きました

 勉強会やスライドで紹介していましたが、Ruby×クローラーという題材で、『Rubyによるクローラー開発技法』という本を書かせて頂きました。RubyとEmacsの鬼であるるびきちさんとの共著です。


Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

この本を書いた理由



 そもそものキッカケは、るびきちさんのエントリーにある通り、SBクリエイティブの編集者さんが、クローラーの作成経験のある人を探していて、私の書いた「オープンソースのRubyのWebクローラー"Anemone"を使ってみる」を読んで打診してくださったというのが始まりです。
 私自身も、Webからデータを収集して分析するということは、趣味として長年やってきました。一方で、本業の方でクローラーというものを作ったことはなく、せいぜい業務効率化でデータ取得をサポートするスクリプトを作る程度です。もっと言えば、Webサイトの運用で、質の悪いクローラーと戦うことの方が多かったです。そんなこともあり、クローラーというある種グレーゾーンに入りやすいものを題材とするので、書いても良いのかという悩みました。また、そもそもクローラーの本の需要は、ニッチな上に寿命が短いのではという懸念もありました。
 いろいろ考えることはありましたが、クローラーやスクレイピングの技術を正しく使えば有用なことは間違いありません。そこで、私なりのクローラーというものを伝えられればと思い挑戦してみました。

本の内容



 6章構成になっています。

  • 1章 10分クローラー作成
  • 2章 クローラー作成の基礎
  • 3章 収集したデータを分析する
  • 4章 高度な利用法
  • 5章 目的別クローラーの作成
  • 6章 クローラーの運用

 2&3章で、データの収集から解析まで一通り取り扱っています。nokogiri&anemoneやxpathといった基本的なライブラリの使い方から、軽く正規表現や形態素解析・自然言語処理の話をしています。4章の部分は、クローラーを拡張していくにはどうするかという観点で書いています。そして、5章は目的別のクローラーということで、実際のサイトを対象にどのようにデータをとってくるのかを具体的に書いています。おなじみの株価や新聞からの情報収集や、iTunes StoreやGoogle Playからのアプリランキング取得など20以上のトピックスがあります。最後の6章は、主にサーバサイドで動かすにはという話です。この辺りは、AWSの各種サービス(SNS,SQS)との連携などにも触れています。

 全般的には、クローラーを初めて作る人を意識して書いています。クローラーとかスクレイピングは、超絶テクニックが有るわけではなく、どちらかと言えば泥臭い作業の連続です。その辺りを、どのように考えながら作るのかを書いたつもりです。

まとめというか感想



 本を書くということは初めての経験でした。想像以上の大変さで、改めて執筆者の凄さというのを認識できました。また、本の冒頭に家族への感謝の気持ちが書かれていることが多く、今までいったい何なんだろうと思っていました。自分で書いてみて初めて解ったのですが、家族の協力がなければ執筆作業はとてもじゃないですが出来ないです。(平日の晩や土日が潰れるので、家事や子育てなどの負担が重くなる)本当に感謝の気持ちで一杯です。
文系上がりのエンジニアとして何者でもなかった自分が、何かには成れたように思えます。

See Also:
RubyでWebスクレイピングの話をしてきました。第1回Webスクレイピング勉強会@東京
Ruby製の構文解析ツール、Nokogiriの使い方 with Xpath
あらためてRuby製のクローラー、"anemone"を調べてみた
オープンソースのRubyのWebクローラー"Anemone"を使ってみる
開発用プロキシ、「CocProxy」が便利
Rubyによるクローラー開発技法の目次


参照:
新刊『Rubyによるクローラー開発技法』2014/08/25発売! | るびきち×Emacs
SBクリエイティブ:Rubyによるクローラー開発技法

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

Bees with machine gunsを使って負荷テスト

aws

 静的サイトの運用であれば、現状ではS3 Web Hosting機能が最適と考えています。OSやミドルウェアのアップデートも不要で、かつ仮想サーバを起動するより圧倒的に安価です。一方で、ほぼ無敵のS3といえども、一定時間で過剰なアクセスがあった場合はスロットリング(throttling)といって、規制されてアクセス制限が掛かる可能性があります。しかし、その閾値がどれくらいなのか、謎です。(全体のリソース状況によるので、一定ではないとのこと)
 ちょっと試してみたかったので、負荷テストをおこなってみました。S3に対する負荷テストの場合、そんじょそこらの負荷では太刀打ち出来ません。そこで、複数のサーバから負荷を掛けてみることにしてみました。と言っても、複数のサーバをコントロールするのは面倒臭いので、Bees with machine gunsを使ってみました。

Bees with machine gunsとは?



 Python製の負荷テストツールです。Bees with machine gunsをインストールしたマシン(親機)から、Beeとよばれる子機(EC2 micro instance)を操作します。子機は、任意の数を起動可能です。複数のBeeから一斉に負荷を掛けて、最後に親機で集計します。負荷テスト自体は、Apache Benchを利用しているようです。
f:id:dkfj:20140728051149p:plain

Bees with machine gunsのインストール



Bees with machine gunsは、以下のモジュールに依存しています。

  • Python 2.6
  • boto
  • paramiko

 特別なものが無いので、楽勝と思いきやハマりました。Amazon Linuxを利用してたのですが、手順通り進めていくと、下記のようなエラーにぶち当たります。

/usr/lib64/python2.6/site-packages/Crypto/Util/number.py:57: PowmInsecureWarning: Not using mpz_powm_sec. You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.
_warn("Not using mpz_powm_sec. You should rebuild using libgmp >= 5 to avoid timing attack vulnerability.", PowmInsecureWarning)

Traceback (most recent call last):
File "/usr/bin/bees", line 3, in
from beeswithmachineguns import main
File "/usr/lib/python2.6/site-packages/beeswithmachineguns/main.py", line 27, in
import bees
File "/usr/lib/python2.6/site-packages/beeswithmachineguns/bees.py", line 36, in
import paramiko
File "/usr/lib/python2.6/site-packages/paramiko/__init__.py", line 69, in
from transport import SecurityOptions, Transport
File "/usr/lib/python2.6/site-packages/paramiko/transport.py", line 32, in
from paramiko import util
File "/usr/lib/python2.6/site-packages/paramiko/util.py", line 32, in
from paramiko.common import *
File "/usr/lib/python2.6/site-packages/paramiko/common.py", line 98, in
from Crypto import Random
File "/usr/lib64/python2.6/site-packages/Crypto/Random/__init__.py", line 29, in
from Crypto.Random import _UserFriendlyRNG
File "/usr/lib64/python2.6/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 38, in
from Crypto.Random.Fortuna import FortunaAccumulator
File "/usr/lib64/python2.6/site-packages/Crypto/Random/Fortuna/FortunaAccumulator.py", line 39, in
import FortunaGenerator
File "/usr/lib64/python2.6/site-packages/Crypto/Random/Fortuna/FortunaGenerator.py", line 36, in
from Crypto.Cipher import AES
File "/usr/lib64/python2.6/site-packages/Crypto/Cipher/AES.py", line 50, in
from Crypto.Cipher import _AES
ImportError: /usr/lib64/python2.6/site-packages/Crypto/Cipher/_AES.so: undefined symbol: rpl_malloc

 暗号化あたりのモジュールの問題のようで、GNU MPとMPIRを入れ替えた上で、再ビルドが必要のようです。この辺りを参考に、設定します。
The Bug Charmer: Building PyCrypto on Amazon EC2

# yum groupinstall "Development Tools"
# yum install python-devel
# 
# ./configure
# make
# make check
# make install
# wget https://ftp.gnu.org/gnu/gmp/gmp-6.0.0a.tar.bz2
# bzip2 -dc gmp-6.0.0a.tar.bz2 | tar xvf -
# cd gmp-6.0.0
# ./configure
# make
# make check
# make install
# wget http://www.mpir.org/mpir-2.6.0.tar.bz2
# bzip2 -dc mpir-2.6.0.tar.bz2 | tar xvf -
# cd mpir-2.6.0
# ./configure
# make
# make check
# make install
# yum reinstall python
# wget http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.6.tar.gz 
# tar xzvf pycrypto-2.6.tar.gz 
# cd pycrypto-2.6
# vi configure
if test $ac_cv_func_malloc_0_nonnull = yes; then :

$as_echo "#define HAVE_MALLOC 1" >>confdefs.h

#else
#  $as_echo "#define HAVE_MALLOC 0" >>confdefs.h

#   case " $LIBOBJS " in
#  *" malloc.$ac_objext "* ) ;;
#  *) LIBOBJS="$LIBOBJS malloc.$ac_objext"
# ;;
#esac


$as_echo "#define malloc rpl_malloc" >>confdefs.h

# pip uninstall PyCrypto
# python setup.py build
# pyton setup install
# pip install beeswithmachineguns

インストール後に、botoの設定を行ないます。.botoファイルとpemの用意をします。

vi ~/.boto
[Credentials]
aws_access_key_id = 'your access key'
aws_secret_access_key = 'your secret access key'

Bees with machine gunsの利用



 設定が全て終わっていれば、次のようなコマンドでBee(子機)の起動できます。

bees up -s 4 -g セキュリティグループ名 -k pemファイル名

 -sが起動するサーバ数、-gがセキュリティグループ名です。注意点としてはNon-VPCのネットワークで起動するので、Non-VPCのセキュリティグループを作成しておく必要があります。そして、親機からsshでアクセス出来るようにしておく必要があります。

 負荷テストは、次のような形です。
nが負荷リクエストの総数。cが同時接続数です。少ない台数で同時接続数を上げ過ぎると、処理しきれずにエラーがでます。注意点としては、/で終わるURLでないとテストできません。

# bees attack -n 10000 -c 250 -u http://xxxxxxxxxx.s3-website-ap-northeast-1.amazonaws.com/
Read 4 bees from the roster.
Connecting to the hive.
Assembling bees.
Each of 4 bees will fire 2500 rounds, 62 at a time.
Stinging URL so it will be cached for the attack.
Organizing the swarm.
Bee 0 is joining the swarm.
Bee 1 is joining the swarm.
Bee 2 is joining the swarm.
Bee 3 is joining the swarm.
Bee 3 is firing his machine gun. Bang bang!
Bee 2 is firing his machine gun. Bang bang!
Bee 0 is firing his machine gun. Bang bang!
Bee 1 is firing his machine gun. Bang bang!
Bee 1 is out of ammo.
Bee 0 is out of ammo.
Bee 2 is out of ammo.
Bee 3 is out of ammo.
Offensive complete.
     Complete requests:		10000
     Requests per second:	406.720000 [#/sec] (mean)
     Time per request:		621.828500 [ms] (mean)
     50% response time:		544.250000 [ms] (mean)
     90% response time:		804.250000 [ms] (mean)
Mission Assessment: Target successfully fended off the swarm.
The swarm is awaiting new orders.

 上記の結果をみると、毎秒406リクエストをこなしていたのが解ります。念の為、アクセスログを見てみると、全て200 O.K.でした。

 では、S3の限界に挑戦する為に、台数を増やしてみます。追加でBeeを増やせないようなので、一度落とします。

# bees down

 10台立ててみました。Beeが一杯です。
f:id:dkfj:20140728051259p:plain

# bees attack -n 100000 -c 250 -u http://xxxxxxxxxx.s3-website-ap-northeast-1.amazonaws.com/
Read 10 bees from the roster.
Connecting to the hive.
Assembling bees.
Each of 10 bees will fire 10000 rounds, 25 at a time.
Stinging URL so it will be cached for the attack.
Organizing the swarm.
Bee 0 is joining the swarm.
Bee 1 is joining the swarm.
Bee 2 is joining the swarm.
Bee 3 is joining the swarm.
Bee 4 is joining the swarm.
Bee 5 is joining the swarm.
Bee 6 is joining the swarm.
Bee 7 is joining the swarm.
Bee 8 is joining the swarm.
Bee 9 is joining the swarm.
Bee 5 is firing his machine gun. Bang bang!
Bee 6 is firing his machine gun. Bang bang!
Bee 3 is firing his machine gun. Bang bang!
Bee 0 is firing his machine gun. Bang bang!
Bee 2 is firing his machine gun. Bang bang!
Bee 8 is firing his machine gun. Bang bang!
Bee 4 is firing his machine gun. Bang bang!
Bee 4 is out of ammo.
Bee 6 is out of ammo.
Bee 0 is out of ammo.
Bee 5 is out of ammo.
Bee 2 is out of ammo.
Bee 8 is out of ammo.
Bee 3 is out of ammo.
Offensive complete.
     3 of your bees didn't make it to the action. They might be taking a little longer than normal to find their machine guns, or may have been terminated without using "bees down".
     Complete requests:		70000
     Requests per second:	330.450000 [#/sec] (mean)
     Time per request:		529.952571 [ms] (mean)
     50% response time:		523.142857 [ms] (mean)
     90% response time:		548.285714 [ms] (mean)

 3台のBeeが行方不明になってしましました。親機の性能不足でしょうか?それとも、子機の性能不足でしょうか?念の為、親機をc3.largeに変更しておきます。

 同時接続数を減らして、再度実行します。

# bees attack -n 10000 -c 200 -u http://xxxxxxxxxx.s3-website-ap-northeast-1.amazonaws.com/
Read 10 bees from the roster.
Connecting to the hive.
Assembling bees.
Each of 10 bees will fire 1000 rounds, 20 at a time.
Stinging URL so it will be cached for the attack.
Organizing the swarm.
Bee 0 is joining the swarm.
Bee 1 is joining the swarm.
Bee 2 is joining the swarm.
Bee 3 is joining the swarm.
Bee 4 is joining the swarm.
Bee 5 is joining the swarm.
Bee 6 is joining the swarm.
Bee 7 is joining the swarm.
Bee 8 is joining the swarm.
Bee 9 is joining the swarm.
No handlers could be found for logger "paramiko.transport"
Traceback (most recent call last):
  File "/usr/bin/bees", line 5, in <module>
    main.main()
  File "/usr/lib/python2.6/site-packages/beeswithmachineguns/main.py", line 127, in main
    parse_options()
  File "/usr/lib/python2.6/site-packages/beeswithmachineguns/main.py", line 119, in parse_options
    bees.attack(options.url, options.number, options.concurrent)
  File "/usr/lib/python2.6/site-packages/beeswithmachineguns/bees.py", line 325, in attack
    results = pool.map(_attack, params)
  File "/usr/lib64/python2.6/multiprocessing/pool.py", line 148, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/usr/lib64/python2.6/multiprocessing/pool.py", line 422, in get
    raise self._value
AssertionError: PID check failed. RNG must be re-initialized after fork(). Hint: Try Random.atfork()

 paramiko.transportのエラーがでました。

感想



 この後も、何度もパラメータや起動台数を変更しながら試してみました。どうも台数や接続数が多いと安定しない模様です。もう少し、調べてみる必要があります。S3 WebHositingに関して言えば、秒間400接続くらいであれば、余裕でこなせる模様です。流石!!


参照:
newsapps/beeswithmachineguns · GitHub
The Bug Charmer: Building PyCrypto on Amazon EC2

62nd Ruby/Rails勉強会@関西に参加してきた

 ここ半年ほど、Rubyでクローラーを作る本を書いていました。そんなこともあり、前回JAWSUG三都物語に参加した時に、アジャイルウェアの川端さんにRuby関西で話さないかとお誘いを受けました。もともとRubyのコミュニティに興味あったので、参加させて貰いました。
http://rubykansai.doorkeeper.jp/events/1316062nd Ruby/Rails勉強会@関西 #rubykansai - Ruby関西 | Doorkeeper

他の方の発表



RailsGirlsOsakaに参加して思ったこと
 RailsGirlsにスタッフとして参加した@to_uedaさんの感想。RailsGirls面白そうです。次は京都の企画があるので、興味がある人はチェック。
Rails Girls - Japanese


【LT】ちょっとしたTipsの提案をします
 @pinzoloさんのLT。デバッグツールなど個々人が独自で使うGemは、Gemfile.localを使おうという話。最初はGroupじゃダメなのと思ってたけど、自由な環境を使いたいという前提が解った時にしっくりきました。

【LT】るびまの告知
@muryoimplさんのLT。るびまが10周年で、記念メッセージ募集中のこと。併せて、るびまの編集・発行フローの紹介。るびまの中の人、初めてみました。もうちょっと話聞いてみたかったです。
Rubyist Magazine 十周年へのメッセージ


Railsで実装されているGitLabのGit Flow | GitLab実践入門 - Merge Requestによる開発
 GitLabを使って、GitHubチックにGit Flowを使う話。かなり参考になりました。会場からも、かなり具体的な質問が出てきて勉強になりました。リポジトリもCVS⇒SVN⇒Gitと進化してきているので、開発フローも改めて考えなおした方が良いですね。

「develop ブランチなんてオワコン」説
develop ブランチなんてオワコン - Togetterまとめ

Ruby初級者向けレッスン 50回 ブロック
@higakiさんによるRubyレッスン。毎回恒例のようで、今回はblockについて。言語の基本的な所をちゃんと勉強したことが無かったので、かなり勉強になりました。
higaki/learn_ruby_kansai_62 · GitHub

@IT Rails4入門記事をツッコもう
 時間が余ったので急遽追加されたコンテンツ。@agilekawabataさんがモデレータとなって、アジャイルウェアさんが連載している「開発現場でちゃんと使えるRails4入門」について話しあおうという企画。私も発表者の一人として、壇上にあがったもののRails4はまだ使っていないので特に突っ込めることは無かったです。すんません。テーマとして挙がったのは

  • rvm派 or rbenv派。

  壇上は、rbenv派多数。rvm派は川端さんと私だけ。rbenvが軽量なのが人気の理由とのこと

  • 利用するエディタ、開発環境は?

  意外なことにvim派とemacs派が多数で、それぞれ半々くらい。その次が、sublimetext。他にはAtomとNetBeans。みんな軽い環境が好きなんですね。(私もVim派)

  • Rails4の新機能つかってる?

  8つくらいの機能について、軽い解説と使っているかどうか。端末ごとのテンプレートは良いねという話と、config/secrets.ymlは必須だねという結論。Module#concerningは、どう使うのが良いか中々難しいとのことです。後は、CSRFプロテクションの変更は対応必須。

 全般的には、記事へのツッコミというより、川端さんへのツッコミになっているのが面白かったです。

感想



 初参加でしたが、かなり楽しかったです。参加者のレベルは、本当の初心者から上級者まで様々です。間違ったことを言っても直ぐにマサカリが飛んできて訂正してもらえるので、発表する方としても安心して話せるのではという感じでした。また、最後の告知で知ったのですが、町ごとにRuby勉強会が立ち上がっていて、気軽に勉強できる下地ができているようです。なかなか見習うべき所が多かったです。


See Also:
Rubyで作るクローラー Ruby crawler