RubyでWebスクレイピング
TechMechanizeとNokogiriの使い方について書きます。mechanize 2.7.6, nokogiri 1.6.8.1をベースにしています。
概要
Mechanizeでできること
MechanizeはRubyからWebページにアクセスするためのライブラリです。あるWebサイトのHTMLを取ってきたり、そこからリンクされている画像ファイルをダウンロードなどができます。
Nokogiriでできること
NokogiriはHTMLファイル・XMLファイルをRubyで解析するためのライブラリです。Mechanizeの一部の機能はNokogiriを利用して実装されているため、MechanizeをインストールするとNokogiriも自動的にインストールされますが、gem install nokogiri
のようにすればNokogiriだけをインストールすることもできます。HTMLファイルがすでにダウンロードしてある場合はNokogiriだけあればOKです。
準備
- Ruby
gem install mechanize
Mechanizeを使う
require 'mechanize'
agent = Mechanize.new
page = agent.get("https://google.com")
page.links #=> Mechanize::Page::Linkの一覧
page.forms #=> Mechanize::Formの一覧
page.body #=> HTML文字列
# Nokogiriを使った操作
page.search("img") #=> imgタグの一覧
page.at("img") #=> 最初のimgタグを取得 (.search("img")[0] と同じ)
Mechanize::Formの使い方
Mechanize::Formオブジェクトは例えばform = page.forms.first
のようにして取得できます。
form.keys
で、nameの一覧を調べることができます。例えば以下のようなフォームがあったとすると:
<form action="POST">
ユーザ名:<input type="text" name="user"><br>
パスワード:<input type="password" name="pass"><br>
</form>
form.keys
は["user", "pass"]
のようになります。この場合以下のようにしてフォームを送信できます。
form["user"] = "taro"
form["pass"] = "passw0rd"
form.submit
# new_page = form.submit # 送信後のページもほしい場合はこうする
ログイン後は同じagentオブジェクトでagent.get
等するとログインした状態でページを取得できます。
Nokogiriを使う
require 'nokogiri'
doc = Nokogiri::HTML.parse(File.read("a.html"))
p doc.search("img") #=> imgタグの配列
p doc.at("img") #=> 最初のimgタグ
p doc.at("img.photo") #=> CSSセレクタも書けます
タグに対する操作
span = doc.at("span")
span.text #=> 中身を文字列で返す
span.to_html #=> spanタグ全体をHTML文字列として返す
a = doc.at("a")
a["href"] #=> aタグのhref属性の値を文字列で返す
CSSセレクタ
doc.search("img.news") # 「class="news"」が付いたimgタグの一覧
doc.search("img#news") # 「id="news"」が付いたimgタグの一覧
doc.search("table a") # tableタグ内にあるaタグの一覧
doc.search("table tr:first-child td") # tableの最初のtrにあるtdタグ
doc.search("table tr:nth-child(3) td") # tableの3番目のtrにあるtdタグ
doc.search("table tr:nth-last-child(3) td") # tableの「後ろから3番目」のtrにあるtdタグ
doc.search("table tr:last-child td") # tableの最後のtrにあるtdタグ
doc.search("a[href^='/gallery/']") # hrefが「/gallery/」から始まるaタグの一覧
doc.search("a[href$='.xml']") # hrefが「.xml」で終わるaタグの一覧
doc.search("a[href*='new']") # hrefに「new」が含まれるaタグの一覧
周囲のタグを取得
td = doc.at("td")
td.parent #=> 親要素
td.children #=> 子要素の一覧
td.next #=>次の兄弟要素
td.previous #=> 前の兄弟要素
上級編:エイリアス
searchメソッドは「/」にエイリアスされています。atメソッドは「%」にエイリアスされています。これらを使うとより短く書けます(読みにくくなるかもしれませんが)。
p doc / :td # doc.search("td")と同じ
p doc % :img # doc.at("img")と同じ
例えば「テーブルの各行の最後のtd」は以下のように書けます。
table = doc % :table
(table/:tr).each do |tr|
p (tr/:td).last
end
上級編:内容の書き換え
NokogiriはHTMLを解析するだけでなく、書き換えることもできます。書き換えたあとは、to_htmlメソッドで新しいHTML文字列を取得できます。
div = doc.at("div")
div["class"] = "button new" # 属性値を書き換える
puts doc.to_html #=> 書き換え後のHTML
div.content = "..." # 中身のテキストを置き換える
div.remove # タグを削除する
div.name = "span" # divタグからspanタグに変える
上級編:Cookieを保存する
agent.cookie_jar.save('./cookies.yaml') #=> cookies.yamlというファイルにCookieを保存する
agent.cookie_jar.load('./cookies.yaml') #=> saveしたCookieを読み込む
デフォルトではセッションCookie(expire指定がなく、ブラウザを閉じたら消える想定のCookie)は保存されませんが、session: trueを付けると保存されるようになります。
agent.cookie_jar.save('./cookies.yaml', session: true)
agent.cookie_jar.load('./cookies.yaml', session: true)