ruby nokogiriでスクレイピング


はじめに

ruby初心者、スクレイピング勉強メモ。

MacOS 10.15.7 

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin19]

$ nokogiri -v
# Nokogiri (1.10.10)

参考になったページ

目標

qiitaのrubyの記事のタイトルをcsv形式で保存する。

流れ

  1. htmlと文字コードを取得
  2. 必要な部分だけゲット

準備

$ gem install nokogiri
$ nokogiri -v
# Gemfile
gem 'open-uri'  #URLに簡単にアクセスできるようにするためのライブラリ
gem 'csv'  #CSV出力をできるようにするためのライブラリ
$ bundle install

open,readで情報を取得する

htmlや文字コードなどいろいろ取得することができるらしい。
qiitaのrubyに関する記事のタイトルを取得。

# scrape.rb

require 'nokogiri'
require 'open-uri'

url = 'https://qiita.com/search?q=ruby'

puts "====html===="
fd = open(url)
html =  fd.read
puts html #htmlがゲットできる
# closeはないっぽい?

puts "====charset===="
fd = open(url)
charset = fd.charset
puts charset #文字コードがゲットできるutf-8

puts "====uri===="
fd = open(url)
uri = fd.base_uri
puts uri
$ ruby scrape.rb

出力

この時出力されるhtmlは改行なしの一行😂
ズラーっと表示されます。

====html====
<!DOCTYPE html>
(中略)
</body></html>
====charset====
utf-8
====uri====
https://qiita.com/search?q=ruby

加工して必要な部分だけ取得する

XPATHで欲しい情報までもパスを指定して取り出す。

XPathはXML文章中の要素、属性値などを指定するための言語です。
XPathではXML文章をツリーとして捉えることで、要素や属性の位置を指定することができます。
HTMLもXMLの一種とみなすことができるため、XPathを使ってHTML文章中の要素を指定することができます。
(引用:XPATHの記法まとめ )

開発者ツールでみると、searchResult_itemTitleクラスのなかにタイトルが書いてあるっぽいのでこれまでのパスを指定してあげる。

doc = Nokogiri::HTML.parse(fd, nil, charset) #タグ毎に改行してXML記法にする

doc.xpath('//h1[@class="searchResult_itemTitle"]').each do |node|
    puts node #まずはputsしてみる
end

出力はこんな感じ。これのaタグの中を取り出したい。

<h1 class="searchResult_itemTitle"><a href="/ne230025/items/10457646e2868e203703">【<em>Ruby</em>】<em>Ruby</em>入門</a></h1>
(中略)
<h1 class="searchResult_itemTitle"><a href="/konchan_exbaka/items/bf5789457b6db69dae37">[<em>Ruby</em>]<em>Ruby</em>におけるループの区別、使い所</a></h1>
<h1 class="searchResult_itemTitle"><a href="/Mocacamo/items/292f98441b5d443f4dab">【<em>Ruby</em>】<em>Ruby</em>入門:クラスについて</a></h1>
doc = Nokogiri::HTML.parse(fd, nil, charset) #タグ毎に改行してXML記法にする

doc.xpath('//h1[@class="searchResult_itemTitle"]').each do |node|
    p node.css('a').inner_text #pはputsみたいなやつ、css(cssセレクタで指定)
end

出力はこんな感じ!いい感じに取り出せました。

"【Ruby】Ruby入門"
"Rubyとは?"
"[ruby]Rubyの分数の計算"
"RubyでRubyを描く"
"Ruby"
"Rubyコーディング規約 ❏Ruby❏"
"Rubyでじゃんけん"
"Rubyの||="
"[Ruby]Rubyにおけるループの区別、使い所"
"【Ruby】Ruby入門:クラスについて"

これをcsvで保存します。

完成したコード

require 'nokogiri'
require 'open-uri'
require 'csv'

url = 'https://qiita.com/search?q=ruby'

charset = nil
titles = []

fd = open(url)
charset = fd.charset
html = fd.read

doc = Nokogiri::HTML.parse(html, nil, charset)

doc.xpath('//h1[@class="searchResult_itemTitle"]').each do |node|
    title =  node.css('a').inner_text
    titles.push(title)
end

csv = CSV.open("title.csv", "w")
csv << titles

$ cat title.csv
【Ruby】Ruby入門,Rubyとは?,[ruby]Rubyの分数の計算,RubyでRubyを描く,Ruby,Rubyコーディング規約 ❏Ruby❏,Rubyでじゃんけん,Rubyの||=,[Ruby]Rubyにおけるループの区別、使い所,【Ruby】Ruby入門:クラスについて

やった!