Nokogiriを使ってみた

#Nokogiriを使ってwebサイトのスクレイピング
今回はRubyでスクレイピングする際に使うライブラリのNokogiriについて、使ってみたコードと注意点、思ったことなどを書いていきます。


http://matome.naver.jp/ の注目記事タイトルとview数、著者、リンク先を抽出してcsvに吐き出すコードです。

```rb:scrape_naver.rb
require 'open-uri'
require 'nokogiri'
require 'csv'

url = 'http://matome.naver.jp/'

charset = nil
html = open(url) do |f|
  sleep(1) # サイトに負荷をかけないためにスリープを挟む
  charset = f.charset # 文字種別を取得
  f.read # htmlを読み込んで変数htmlに渡す
end
# htmlをパース(解析)してオブジェクトを生成
doc = Nokogiri::HTML.parse(html, nil, charset)

array = []

doc.css('div.MdTopMTMList01')[0].css('li.mdTopMTMList01Item').each do |node|
  title = node.css('a')[1].attribute('title').value
  view = node.css('.mdTopMTMList01PVCountNum').text
  author = node.css('.mdTopMTMList01UserName').css('a').text
  link = 'https://matome.naver.jp' + node.css('a').attribute('href').value
  array << [title,view,author,link]
end
CSV.open("scrape_naver_list.csv","w",:force_quotes=>true) do |csv|
  array.each do |row|
    csv << row
  end
end
```
結果としては

```:scrape_naver_list.csv
"あのイケメンからレジェンドまで…プロ野球選手の「引退ラッシュ」に悲鳴相次ぐ","3503","stoneflower","https://matome.naver.jp/odai/2153793220910155401"
"これは超お得〜♡ポーチセットやコスメも豪華♪12月号付録が楽しみすぎ！","15764","naokana135","https://matome.naver.jp/odai/2153774849245076401"
"これは優秀！ニトリで大ヒット中の「珪藻土グッズ」","7051","senegirls","https://matome.naver.jp/odai/2153775952349164601"
"全ての行動をインスタに…SNS依存女子に辟易してる男子が多数","531","まひろちゃんぶー","https://matome.naver.jp/odai/2153786078285654301"
"これは絶対確信犯！街で見つけた『並べ方に悪意しか感じない』画像たちw","48865","広瀬ティーオ葵","https://matome.naver.jp/odai/2153760799501480801"
"１７歳甥っ子と入浴...最近の後藤真希がネットをざわつかせている件","2140","何故だろう","https://matome.naver.jp/odai/2153791239903173701"
"審査に落ちてしまう…iPhoneXS / XS Maxを購入できない人が続出！？","998","canty0628","https://matome.naver.jp/odai/2153786186386142001"
"時速86キロ…ついに起訴された吉澤ひとみのひき逃げ事件の新事実","4794","monet333","https://matome.naver.jp/odai/2153793363810927001"
"ついに色付きもデビュー！秋冬に使いたいリップケアアイテム","2571","tyanndai","https://matome.naver.jp/odai/2153771246236551901"
"あなたは理解できる？…Twitterで見かけた『平成の奇書おすすめ7選』","143","sryama","https://matome.naver.jp/odai/2153775701548443801"
"最後のアム活!?安室奈美恵カバーと雑誌付録が見逃せない","24133","写メんなよ","https://matome.naver.jp/odai/2153784075876735101"
"毎日食べたい...♡９月みんながハマった「セブンのグルメ」","695","ramunenomitai7","https://matome.naver.jp/odai/2153782880772033801"
"遊んでほしい時…Twitter発『遊ぶネコたち』がキュートすぎ!","705","futoshi111","https://matome.naver.jp/odai/2153654817336213801"
"これ超可愛い♡・・Amazonで大絶賛「コスプレ衣装」４選","6496","tatsubo1208","https://matome.naver.jp/odai/2153766924318169401"
"考えた人スゴいΣ(ﾟДﾟ)目から鱗な「無印グッズの活用法」","15209","ramunenomitai7","https://matome.naver.jp/odai/2153777280154520201"
"買って損なし♡大人気の手放せなくなる【化粧下地】","16996","juna3434","https://matome.naver.jp/odai/2153772510839493601"
"捨てずにエコ料理♡椎茸（シイタケ）の軸の活用レシピ","908","inusyamo","https://matome.naver.jp/odai/2153783623374832601"
"池井戸潤原作『七つの会議』も！冬のおすすめ小説「実写化映画」","1492","aku1215","https://matome.naver.jp/odai/2153783550874676701"
"秋の美味しいパスタを食べよう！きのことトマトのパスタレシピ","969","wawawa55555","https://matome.naver.jp/odai/2153782422270936301"
"売り切れ必至♡秋冬にあると嬉しい「ダイソーアイテム」","41201","ramunenomitai7","https://matome.naver.jp/odai/2153758262689935501"
```
こんなcsvを出力してくれます。
覚えておきたいメソッドを羅列していきます。

```
Nokogiri::HTML.parse(html, nil, charset)
```
これでhtmlをパースしたNodesetを返してくれます。

```
doc.css('cssの指定')
```
これでNodesetのうちで指定したcssを持っているNodeを検索してくれます。~~それが一つならNode、2つ以上の時はNodesetで返ってきます。ちなみに、指定したCSSがなかった場合、Nilになります。ここで検索したものがどのクラスになっているのかをしっかり把握するのが超重要だと思います。エラーのほとんどは想定していたクラスと違うものが出てきているパターンでした。~~
要素の数によらず返って来るのはNodesetでした。次に記述するリスト内から要素を取り出した時のそれぞれの要素のクラスをしっかりチェックするのが大事。
Nodesetはリストのようにしてほしい要素を指定できます。

```
doc.css('cssの指定')[0..1]
```
こんな感じです。この後にさらに.cssをつけてさらに検索をしていくこともできますし、.eachでループを回していくこともできます。
こうして必要な要素を持ってきた後はその中の要素を次のようなメソッドを用いて取得します。

```
Node.text
Node.attribute('href').value
```
前者は中に含まれている文章を全て取り出してつなげた文字列を返してくれます。
後者は属性を指定して、その値を取り出してきてくれます。

これらをうまく活用してほしい情報を抜き出し、整形してcsvに書き出したりDBに入れたりします。エラーを吐いたときは落ち着いてCSSを検索した際にどのクラスのオブジェクトが帰ってきているのか確認しましょう。

webサイトの検証機能でhtmlとにらめっこしながらコーディングしていきます。また、検証のNetworkタブを用いてJsonが入っているページにopen-uriで接続することでjsonを持ってくることもできます。

さらにwebサイトの内容を持ってくるだけでなくフォームを埋めたりログインしたりといった機能を使うためにはMechanizeというライブラリがあり、formタグやその中のfieldを探して入力してsubmitすることでログインが必要なページでも先にすすんで情報を取得できます。便利！

今までpythonでbeautifulsoup使ってスクレイピングしてみたりしてたけどrubyではNokogiriを使って色んなことができそうです。また、pythonで多少selenium触ったことあるけどrubyにもseleniumがあるみたいだから使いこなせるようになりたい。