Λάδι Βιώσας

http://profile.hatena.ne.jp/kenkitii/

Nokogiri メモ

hatena-mode をいれて日記書きやすくなったので、さっそく日記を更新してみる。俗に言う「ハンマーを持つ人には、すべてが釘に見える (If all you have is a hammer, everything looks like a nail.) 」って奴ですね。いまの自分には Emacs のバッファが、全てハテナ日記にみえてます(うそです)

今まで備忘録は、Emacs Muse (←Emacs 上で動く Wiki)でやってたんですが、公開を前提としてないと殴り書きメモになってしまい、自分でもわかりづらい状況だったので、この際、はてな日記を清書用にしようかと。てわけで日記タイトルも変更しました。たまーに ruby をいじるとすっかり忘れてて、思い出すのに3日とかかかっちゃって、ときどき使いたくなるけどあんまり使わない技術ネタを個人的な備忘録としてまとめていきます。

さて今回は、個人的な Nokogiri はまりポイントです。「あー俺も昨日、丸太を製材するのにはまっちゃってさー」って人はこのブログの読者にはいないと思うので Nokogiri についての説明は省きますご了承下さい 。ちなみに今使ってるバージョンは 1.4.3.1 です。

文字エンコードの指定

doc = Nokogiri::HTML(dat, nil, encoding)

第2引数には、base URI が入るらしいがちゃんと動かないらしい。未検証。

XPath

Hpricotの頃は、div[@id~=/hoge/] とか div[@id^="hoge"] とか指定出来た気がするけど(記憶曖昧)、Nokogiri では出来なくて混乱していつもハマる

id が 'para' で始まる p タグを抽出したい
doc.xpath('//p[starts-with(@id, "para")]')
URLに 'javascript' を含むリンクを抽出したい
doc.xpath('//a[contains(@href, "javascript")]')
テキストに 'Login' という文字を含むリンクを抽出したい
doc.xpath('//a[contains(text(), "Login")]')
複数の XPath を指定するには、| で区切る
doc.xpath("//span[@class='header]|//div[@class='footer']")
検索したいタグに、複数の属性を指定したい場合は or を使う
doc.xpath("//div[@class='header' or @class='footer']")
inner_html と text の違い

inner_html では、実体参照が返ってきます

doc = Nokogiri::HTML(<<-HERE)
<head><title>Foo & Bar</title></head>
HERE
puts doc.at('head/title').inner_html     # => Foo &amp; Bar
puts doc.at('head/title').text           # => Foo & Bar
おまけ

あとこんなコード↓。とあるタグの中を XPath で再検索したいとき。うっかり // つけてしまい気がつかずにはまる

doc = Nokogiri::HTML(<<-HERE)
<table>
  <tr>
    <td class="title">Favorite Poems</td>
    <td class="isbn">123-456</td>
    <td class="page">123</td>
  </tr>
  <tr>
    <td class="title">Chocolate Desserts</td>
    <td class="isbn">654-098</td>
    <td class="page">456</td>
  </tr>
  <tr>
    <td class="title">Jabberwocky</td>
    <td class="isbn">454-545</td>
    <td class="page">726</td>
  </tr>
</table>
HERE

doc.xpath("//table/tr").each do |node|
# title = node.xpath("//td[@class='title']").text # × //が付いてると root から再検索されてしまう
  title = node.xpath("td[@class='title']").text   # ◯ trタグの中を再検索したいときはこんな感じで。end