前回の投稿(CasperJSでWEBサイトの画面キャプチャを取得してみた)の続きです。環境構築の方法(Mac)については、前回の投稿をご覧ください。
はじめに
- とある事情で、Qiitaの Organizationページ(自社の) をWEBスクレイピングしました。
- とある事情というのは、自社のブログ に、自社メンバーのQiita新着投稿をブログパーツ的に表示したかった。
- Qiitaへゴリゴリ負荷をかけるものではないです^^;
- CasperJS は CoffeeScript をそのまま解釈してくれるので、今回は CoffeeScript で書いてみます。
- ちなみに CasperJS は仮想ブラウザ?的に動いているので、対象ページが JavaScript 等で動的に描写されるページでも、スクレイピングできるはず..です。
今回の成果物
- QiitaをWEBスクレイピングして、こういうブログパーツ(といってもHTML)を自動生成できるようにしました。
- http://hkusu.github.io/CasperJS_scraping_Qiita/demo.html
- 実際にはこれを cron 等で定期的に生成します。
- 生成スクリプトのソースはこちら
簡単なWEBスクレイピングの例
-
まず手始めに、対象ページの
a
タグのhref="hoge"
を全て取得してみます。ソースはこんな感じ。scraping.coffeecasper = require("casper").create() target_url = "http://qiita.com/organizations/yumemi" # 対象のWEBページを開く casper.start target_url, -> urls = [] urls = @evaluate -> items = document.querySelectorAll("a") Array::map.call items, (e) -> e.getAttribute('href') # 出力 @echo(urls.join("\n")) casper.run -> @exit()
- スクレイピングのポイントは、
querySelectorAll
のところ。 -
querySelector
の使い方については、下記のサイトを参考にしました。
- スクレイピングのポイントは、
-
では上記のソースを実行してみます。コマンドラインで、
$ casperjs scraping.coffee
-
すると次のように、
href="hoge"
の中身が全て取得できたことが確認できます。
querySelector
の使い方のポイント
上記の例のように、単純に a
タグのものを全て取得としてしまうと、余分なものも取得されてしまうので、実際は対象ページのHTMLの構造を見て、絞り込む必要があります。
具体的にいうと、divタグのid名
、class名
、HTMLタグ名
、HTMLタグの属性(検索に正規表現の利用可)
で絞ります。
例えばこの例だと、
elements = []
elements = @evaluate ->
items = document.querySelectorAll(".activities article .body a[href*=\"/items/\"]")
Array::map.call items, (e) ->
e.getAttribute('href');
- 対象ページのHTMLの
activities
class 配下の、 -
article
タグ 配下の、 -
body
class 配下の、 -
a
タグで、href
属性の value(つまりURL)で/items/
を含むものの、 -
href
属性の value(つまりURL)を取得する
となります。
href
属性のところで *=
は部分一致を意味します。もし先頭文字列の一致の場合は ^=
、後方文字列の一致の場合は $=
とします。
e.getAttribute('href');
は属性の取得を意味します。もしHTMLの中身を取得する場合は e.innerHTML
とします。
ただ実際には、うまく絞りきれない場合が多いので.. その場合は、いったん配列にスクレイピングの結果を格納しておいて、普通に CoffeeScript で配列操作を行います。例えば、
-
特定のURLを含むものを、別の配列へ移し替える
- この例の場合は URLが
/piyo
から始まるもの
elements_2 = [] i = 0 while i < elements.length if elements[i].match(/^\/piyo/) elements_2.push(elements[i]) i++
- この例の場合は URLが
-
文字列を加工する
- この例の場合は、余分な文字列の削除
i = 0 while i < element.length entry_days[i] = entry_days[i].replace(/[\n\r]/g,"") entry_days[i] = entry_days[i].replace(/\ /g,"") entry_days[i] = entry_days[i].replace(/<strong>.+?<\/strong>/g,"") i++
おわりに
スクレイピングする際は、対象ページのHTMLソースを見て、睨めっこ&試しながらソースを書いていく流れになります^^; 結構、骨が折れる作業です..