Protractorでスクレイピングしてみた

Shunsuke Sawada

Railsでスクレイピングが必要な時は Nokogiri を使っていたけれど、普通のサイトはJavascriptを使っているわけで、Nokogiriだけではスクレイピングが難しいこともある。そんな時にどうしようかと。

Nokogiri 鋸

Protractorなら、実際にユーザーがブラウザーを立ち上げて、ボタンをクリックして、テキストを読んで… みたいなことを再現できるのですごい便利。ほんとはAngular.jsのためのテストフレームワークだけど、スクレイピングにも使える。

Protractor - end to end testing for AngularJS

nvmのイントール

手元のMacOSにインストールして使ってみる。
Ruby使っているならお馴染みのrvm(Ruby Version Manager)。
nvmはNode.jsのバージョン管理ツール。

1
2
3
4
5
6
7
8
nvmを入手
$ git clone https://github.com/creationix/nvm.git ~/.nvm

リリースされているNode.jsのリスト
$ nvm ls-remote

好きなバージョンをインストール
$ nvm install v0.10.35

  
ターミナル起動と同時にnvmも実行させるために
~/.bash_profile を編集

1
source ~/.nvm/nvm.sh

  
.bash_profileを再読み込み

1
$ source ~/.bashrc

Protractorのインストール

インストールすると、
protractor と webdriver-manager というコマンドが使えるようになる。

1
2
3
4
5
6
インストール
$ npm install -g protractor

webdriver-managerをアップデート
$ webdriver-manager update

  
Selenium Server をスタート

1
$ webdriver-manager start

スクレイピングしてみる

用意するファイルは spec.js と conf.js だけ。
なんて簡単 :)

conf.js

javascript
1
2
3
4
exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['spec.js']
};

  
spec.js

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var url  = 'http:canpath.jp';

describe('CANPATH', function() {

    // For website without Angular 
    browser.ignoreSynchronization = true;
    browser.get(url);

    /*
    // If you want to click something
    it('should open details', function(){
        // Click dropdown menu
        element(by.css('.dropdown-trigger')).click().then(function(){
            console.log("clicked");
        })
    });
    */

    it('should collect title and URL from ranking', function(){
        element.all(by.css('.ranking-item')).map(function(item, i){

            // Collect information
            // "getText" and "getAttribute" are asynchronous.
            // Those action methods return a Promise. So, use then() to use the value.
            var itemDate = {
                url:   item.element(by.xpath('.//h1[@class="title"]/a')).getAttribute('href'),
                title: item.element(by.xpath('.//h1[@class="title"]/a')).getText()
            };
            // Array will be returned.
            return itemDate;

        }).then(function(menu){
            // Show this array in terminal
            console.log(menu);
            console.log("Done!");
        }); //

    }); //it


}); //describe

実行結果

実行結果はこんな感じ。
http://canpath.jp の人気ストーリーランキングを取ってみました。
実際にブラウザーが立ち上がって、スクレイピングが行われます。

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ protractor conf.js

Using the selenium server at http://localhost:4444/wd/hub
[launcher] Running 1 instances of WebDriver
[ { url: 'http://www.canpath.jp/stories/23',
    title: '立ち直るきっかけを作ってくれた セブ島に感謝' },
  { url: 'http://www.canpath.jp/stories/49',
    title: '就職より大事なもの。そうだセブ島にいこう!' },
  { url: 'http://www.canpath.jp/stories/298',
    title: 'Can you follow me?' },
  { url: 'http://www.canpath.jp/stories/55', title: '私の大きな転機。' },
  { url: 'http://www.canpath.jp/stories/277',
    title: 'トビタテ!留学JAPAN1期生の1人として思うことを改めて。' },
  { url: 'http://www.canpath.jp/stories/6',
    title: 'NZに家族で移住しちゃおう!' },
  { url: 'http://www.canpath.jp/stories/304',
    title: 'Happy birthday from all over the world' },
  { url: 'http://www.canpath.jp/stories/46',
    title: 'タイで起業中に起きたこと。思ったこと。' },
  { url: 'http://www.canpath.jp/stories/299',
    title: '寝ても覚めても、海外' },
  { url: 'http://www.canpath.jp/stories/51',
    title: 'カナダで気づいた“言葉の先にあったもの”' },
  { url: 'http://www.canpath.jp/stories/316', title: '6歳の女の子の話。' },
  { url: 'http://www.canpath.jp/stories/321',
    title: 'To be someone' },
  { url: 'http://www.canpath.jp/stories/8', title: '海外でウェブサイト受注' },
  { url: 'http://www.canpath.jp/stories/4',
    title: '自由な生き方を教えてくれたオーストラリアの冒険家' },
  { url: 'http://www.canpath.jp/stories/53',
    title: 'スイスの山に登ってきました' } ]
Done!
.

Finished in 9.837 seconds
1 test, 0 assertions, 0 failures

今日の日付のディレクトリを自動生成して、
テキストファイルに保存するという流れで実用できそうです。
それもNode.jsでできるよ。

やってから思ったけど、PhantomJSだけでいいかもな…。

参考

Protractor - end to end testing for AngularJS

まだmechanizeで消耗してるの? WebDriverで銀行をスクレイピング(ProtractorとWebdriverIOを例に) - 詩と創作・思索のひろば

protractor-scrape-money/mufg.js at master · motemen/protractor-scrape-money

mkdirp - node.jsで連続フォルダ作成パッケージ | Node.js技術

Node.js Error: Cannot find module express - Stack Overflow

node.js - NPM global install "cannot find module" - Stack Overflow

ユーザーの環境変数を設定するbashの設定ファイルと、カスタムプロンプトについて | OXY NOTES

193
Shunsuke Sawada

おすすめの記事

webpackを使ってJSとCSSをコンパイルする(ES6 / Sass)
Turbolinks で Google adsense が正しく表示されない時の対処方法
5
RailsでGoogle mapsを使いこなすためのメモ 2 / 地図デザインのカスタマイズ
2